From 21bc371eaac168c467a310f996f37a1a7be23ebd Mon Sep 17 00:00:00 2001 From: Alex Yakunin Date: Mon, 3 Feb 2020 16:06:11 -0800 Subject: [PATCH 01/31] TupleDescriptor-related performance improvements. --- .../IndexingModel/PrimaryIndexInfo.cs | 2 +- .../Tuples/TupleBehaviorTestBase.cs | 51 +-- .../Tuples/TupleDescriptorTest.cs | 45 +- .../Tuples/TuplePerformanceTest.cs | 17 +- Orm/Xtensive.Orm/Collections/ArrayUtils.cs | 8 +- Orm/Xtensive.Orm/Core/ArgumentValidator.cs | 15 +- .../Core/Extensions/EnumerableExtensions.cs | 29 +- .../Internals/ReflectionExtensions.cs | 20 +- .../Orm/Building/Builders/TypeBuilder.cs | 5 +- Orm/Xtensive.Orm/Orm/EntitySetBase.cs | 10 +- .../Orm/Linq/ItemToTupleConverter{TItem}.cs | 8 +- Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs | 4 +- Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs | 5 +- Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs | 14 +- .../Orm/Rse/ColumnGroupCollection.cs | 11 +- .../Providers/Compilable/AggregateProvider.cs | 11 +- .../Compilable/ContainsTableProvider.cs | 16 +- .../Providers/Compilable/FreeTextProvider.cs | 18 +- .../Providers/Compilable/IncludeProvider.cs | 11 +- .../Providers/Compilable/OrderProviderBase.cs | 15 +- Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs | 96 +++-- .../Packed/PackedFieldAccessorFactory.cs | 13 +- .../Packed/PackedFieldDescriptorComparer.cs | 18 + Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 388 +++++++----------- Orm/Xtensive.Orm/Tuples/TupleExtensions.cs | 25 +- 25 files changed, 419 insertions(+), 436 deletions(-) create mode 100644 Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs diff --git a/Orm/Xtensive.Orm.Tests.Core/Modelling/IndexingModel/PrimaryIndexInfo.cs b/Orm/Xtensive.Orm.Tests.Core/Modelling/IndexingModel/PrimaryIndexInfo.cs index 5b1e60e943..101fdda8f0 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Modelling/IndexingModel/PrimaryIndexInfo.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Modelling/IndexingModel/PrimaryIndexInfo.cs @@ -93,4 +93,4 @@ public PrimaryIndexInfo(TableInfo table, string name) { } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs index af1318df6e..83b9be8a29 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs @@ -6,13 +6,10 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using NUnit.Framework; -using Xtensive.Collections; -using Xtensive.Reflection; -using Xtensive.Orm.Tests; using Xtensive.Tuples; -using Tuple = Xtensive.Tuples.Tuple; using MethodInfo=System.Reflection.MethodInfo; namespace Xtensive.Orm.Tests.Core.Tuples @@ -41,13 +38,10 @@ protected virtual Xtensive.Tuples.Tuple CreateTestTuple(Xtensive.Tuples.Tuple so public void Test() { - IList types = new List(); - for (int i = 0; i < 4; i++) - types.Add(typeof (short)); - - TupleDescriptor descriptor = TupleDescriptor.Create(types); - DummyTuple dummyTuple = new DummyTuple(descriptor); - ITuple tuple = CreateTestTuple(descriptor); + var types = Enumerable.Range(0, 4).Select(_ => typeof(short)).ToArray(); + var d = TupleDescriptor.Create(types); + var dummyTuple = new DummyTuple(d); + var tuple = CreateTestTuple(d); PopulateData(types, dummyTuple, tuple); AssertAreSame(dummyTuple, tuple); } @@ -78,10 +72,8 @@ protected static void PopulateData(IList types, Xtensive.Tuples.Tuple tupl public void BehaviorTest() { - List fields = new List(3); - fields.AddRange(new Type[] {typeof(int), typeof(bool), typeof(string)}); - - TupleDescriptor d = TupleDescriptor.Create(fields); + var types = new Type[] {typeof(int), typeof(bool), typeof(string)}; + var d = TupleDescriptor.Create(types); TestTuple(CreateTestTuple(d)); TestTuple(new DummyTuple(d)); } @@ -144,10 +136,10 @@ private static void TestTuple(Xtensive.Tuples.Tuple tuple) public void EmptyFieldsTest() { - List fields = new List(); - TupleDescriptor descriptor = TupleDescriptor.Create(fields); - DummyTuple dummyTuple = new DummyTuple(descriptor); - ITuple tuple = CreateTestTuple(descriptor); + var types = new Type[0]; + var d = TupleDescriptor.Create(types); + var dummyTuple = new DummyTuple(d); + var tuple = CreateTestTuple(d); Assert.AreEqual(0, tuple.Count); } @@ -162,25 +154,24 @@ public void RandomTest() IList descriptorList = new List(); while (iteration++ < IterationCount) { - int fieldCount = random.Next(0, MaxFieldCount); - List fields = new List(fieldCount); + var fieldCount = random.Next(0, MaxFieldCount); + var types = new List(fieldCount); for (int i = 0; i < fieldCount; i++) - fields.Add(fieldTypes[random.Next(0, fieldTypes.Length - 1)]); - TupleDescriptor descriptor = TupleDescriptor.Create(fields); - descriptorList.Add(descriptor); + types.Add(fieldTypes[random.Next(0, fieldTypes.Length - 1)]); + var d = TupleDescriptor.Create(types.ToArray()); + descriptorList.Add(d); } foreach (TupleDescriptor descriptor in descriptorList) { - DummyTuple dummyTuple = new DummyTuple(descriptor); - ITuple tuple = CreateTestTuple(descriptor); + var dummyTuple = new DummyTuple(descriptor); + var tuple = CreateTestTuple(descriptor); for (int fieldIndex = 0; fieldIndex < tuple.Count / 2; fieldIndex++) { - Type type = descriptor[fieldIndex]; - MethodInfo setValueMethod = setValueMethodGeneric.MakeGenericMethod(type); + var type = descriptor[fieldIndex]; + var setValueMethod = setValueMethodGeneric.MakeGenericMethod(type); setValueMethod.Invoke(null, new object[] { dummyTuple, tuple, fieldIndex, random }); } AssertAreSame(dummyTuple, tuple); } - } protected void AssertAreSame(ITuple dummyTuple, ITuple tuple) @@ -234,4 +225,4 @@ private static void InternalSetValue(Xtensive.Tuples.Tuple tuple, int fieldIn tuple.SetValue(fieldIndex, instance); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleDescriptorTest.cs b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleDescriptorTest.cs index 87f61a4662..c0c74e6d67 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleDescriptorTest.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleDescriptorTest.cs @@ -7,10 +7,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using Xtensive.Collections; -using Xtensive.Orm.Tests; using Xtensive.Tuples; -using Tuple = Xtensive.Tuples.Tuple; namespace Xtensive.Orm.Tests.Core.Tuples { @@ -52,40 +49,38 @@ public class TupleDescriptorTest [Category("Performance")] public void PerformanceTest() { - Random r = RandomManager.CreateRandom(SeedVariatorType.CallingMethod); - - int count = 100; - List types = new List(); - List descriptors = new List(); + var rnd = RandomManager.CreateRandom(SeedVariatorType.CallingMethod); + var count = 100; + var types = new List(); + var descriptors = new List(); using (new Measurement("Creating descriptors {T1}, {T1,T2}, ...", count)) { - for (int i = 0; i(size); - for (int j = 0; j < size; j++) - types.Add(FieldTypes[r.Next(FieldTypes.Length)]); - descriptors.Add(TupleDescriptor.Create(types)); + for (var j = 0; j < size; j++) + types.Add(FieldTypes[rnd.Next(FieldTypes.Length)]); + descriptors.Add(TupleDescriptor.Create(types.ToArray())); } } count = 100000; size = 10; types = new List(size); - for (int j = 0; j < size; j++) - types.Add(FieldTypes[r.Next(FieldTypes.Length)]); + for (var j = 0; j < size; j++) + types.Add(FieldTypes[rnd.Next(FieldTypes.Length)]); using (new Measurement("Creating the same descriptor", count)) { - for (int i = 0; i types) + private TupleDescriptor TestDescriptor(TupleDescriptor theSame, Type[] types) { - TupleDescriptor d1 = TupleDescriptor.Create(types); - TupleDescriptor d2 = TupleDescriptor.Create(types); + var d1 = TupleDescriptor.Create(types); + var d2 = TupleDescriptor.Create(types); Assert.IsNotNull(d1); Assert.IsNotNull(d2); Assert.AreEqual(d1, d2); @@ -137,4 +132,4 @@ private TupleDescriptor TestDescriptor(TupleDescriptor theSame, IList type return d1; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm.Tests.Core/Tuples/TuplePerformanceTest.cs b/Orm/Xtensive.Orm.Tests.Core/Tuples/TuplePerformanceTest.cs index aadce99818..791b05eebb 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Tuples/TuplePerformanceTest.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Tuples/TuplePerformanceTest.cs @@ -4,6 +4,7 @@ using System.Threading; using NUnit.Framework; using Xtensive.Comparison; +using Xtensive.Core; using Xtensive.Orm.Tests; using Xtensive.Tuples; using Tuple = Xtensive.Tuples.Tuple; @@ -45,7 +46,10 @@ public class TuplePerformanceTest [Test] public void BasicTest() { - Xtensive.Tuples.Tuple t = Xtensive.Tuples.Tuple.Create(TupleDescriptor.Create()); + var t = Tuple.Create(TupleDescriptor.Create(new [] { + typeof(string), typeof(int), typeof(string), + typeof(TimeSpan), typeof(string), typeof(string) + })); t.SetValue(0, string.Empty); t.SetValue(2, "n\\a"); t.SetValue(3, new TimeSpan()); @@ -69,11 +73,11 @@ public void GeneratorTest() Random random = RandomManager.CreateRandom(SeedVariatorType.CallingMethod); using (new Measurement("Random Tuple generation", iterationCount)) { while (iteration++ < iterationCount) { - IList fieldTypesList = new List(); + var fieldTypes = new List(); for (int i = 0; i < fieldCount; i++) - fieldTypesList.Add(allFieldTypes[random.Next(allFieldTypes.Length)]); - TupleDescriptor descriptor = TupleDescriptor.Create(fieldTypesList); - Xtensive.Tuples.Tuple tuple = Xtensive.Tuples.Tuple.Create(descriptor); + fieldTypes.Add(allFieldTypes[random.Next(allFieldTypes.Length)]); + var d = TupleDescriptor.Create(fieldTypes.ToArray()); + var tuple = Tuple.Create(d); } } } @@ -414,7 +418,8 @@ public void GeneratorAdvancedTest() for (int i = 0; i < runCount; i++) { var count = sizeRandomizer.Next(maxSize + 1); var tupleTypes = Enumerable.Repeat(0, count) - .Select(_ => types[typeRandomizer.Next(types.Length)]); + .Select(_ => types[typeRandomizer.Next(types.Length)]) + .ToArray(count); var descriptor = TupleDescriptor.Create(tupleTypes); var tuple = Tuple.Create(descriptor); } diff --git a/Orm/Xtensive.Orm/Collections/ArrayUtils.cs b/Orm/Xtensive.Orm/Collections/ArrayUtils.cs index 0e84736ca2..bad2afd7e9 100644 --- a/Orm/Xtensive.Orm/Collections/ArrayUtils.cs +++ b/Orm/Xtensive.Orm/Collections/ArrayUtils.cs @@ -6,6 +6,7 @@ // Created: 2007.07.04 using System; +using System.Runtime.CompilerServices; namespace Xtensive.Collections { @@ -15,13 +16,12 @@ namespace Xtensive.Collections /// Type of array item. public static class ArrayUtils { - private static readonly TItem[] emptyArray = new TItem[] {}; - /// /// Gets empty array of items of type. /// public static TItem[] EmptyArray { - get { return emptyArray; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array.Empty(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Core/ArgumentValidator.cs b/Orm/Xtensive.Orm/Core/ArgumentValidator.cs index 9f0dae85ff..98a4dae595 100644 --- a/Orm/Xtensive.Orm/Core/ArgumentValidator.cs +++ b/Orm/Xtensive.Orm/Core/ArgumentValidator.cs @@ -5,6 +5,7 @@ // Created: 2007.10.01 using System; +using System.Runtime.CompilerServices; using JetBrains.Annotations; using Xtensive.Core; using Xtensive.Comparison; @@ -23,6 +24,7 @@ public static class ArgumentValidator /// /// Value to compare with . /// Name of the method parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentNotNull(object value, [InvokerParameterName] string parameterName) { if (value==null) { @@ -38,6 +40,7 @@ public static void EnsureArgumentNotNull(object value, [InvokerParameterName] st /// Value to compare with . /// Name of the method parameter. /// The type of default value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsNotDefault(T value, [InvokerParameterName] string parameterName) { if (default(T)==null) { @@ -58,6 +61,7 @@ public static void EnsureArgumentIsNotDefault(T value, [InvokerParameterName] /// /// Value to check. /// Name of the method parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentNotNullOrEmpty(string value, [InvokerParameterName] string parameterName) { if (value == null) { @@ -70,6 +74,7 @@ public static void EnsureArgumentNotNullOrEmpty(string value, [InvokerParameterN } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentNotNullOrEmptyOrWhiteSpace(string value, [InvokerParameterName] string parameterName) { if (value==null) { @@ -93,6 +98,7 @@ public static void EnsureArgumentNotNullOrEmptyOrWhiteSpace(string value, [Invok /// Value to compare check. /// Name of the method parameter. /// The expected type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIs(object value, [InvokerParameterName] string parameterName) { EnsureArgumentNotNull(value, parameterName); @@ -109,6 +115,7 @@ public static void EnsureArgumentIs(object value, [InvokerParameterName] stri /// Value to compare check. /// The expected type of value. /// Name of the method parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIs(object value, Type type, [InvokerParameterName] string parameterName) { EnsureArgumentNotNull(value, parameterName); @@ -125,6 +132,7 @@ public static void EnsureArgumentIs(object value, Type type, [InvokerParameterNa /// Value to compare check. /// Name of the method parameter. /// The expected type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsNullOr(object value, [InvokerParameterName] string parameterName) { if (value==null) @@ -144,6 +152,7 @@ public static void EnsureArgumentIsNullOr(object value, [InvokerParameterName /// Upper range boundary (inclusively). /// Name of the method parameter. /// The type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsInRange(T value, T lowerBoundary, T upperBoundary, [InvokerParameterName] string parameterName) where T: struct, IComparable { @@ -161,6 +170,7 @@ public static void EnsureArgumentIsInRange(T value, T lowerBoundary, T upperB /// Value boundary. /// Name of the method parameter. /// The type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsGreaterThan(T value, T boundary, [InvokerParameterName] string parameterName) where T: struct, IComparable { @@ -179,6 +189,7 @@ public static void EnsureArgumentIsGreaterThan(T value, T boundary, [InvokerP /// Value boundary. /// Name of the method parameter. /// The type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsGreaterThanOrEqual(T value, T boundary, [InvokerParameterName] string parameterName) where T: struct, IComparable { @@ -197,6 +208,7 @@ public static void EnsureArgumentIsGreaterThanOrEqual(T value, T boundary, [I /// Value boundary. /// Name of the method parameter. /// The type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsLessThan(T value, T boundary, [InvokerParameterName] string parameterName) where T: struct, IComparable { @@ -215,6 +227,7 @@ public static void EnsureArgumentIsLessThan(T value, T boundary, [InvokerPara /// Value boundary. /// Name of the method parameter. /// The type of value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureArgumentIsLessThanOrEqual(T value, T boundary, [InvokerParameterName] string parameterName) where T: struct, IComparable { @@ -225,4 +238,4 @@ public static void EnsureArgumentIsLessThanOrEqual(T value, T boundary, [Invo string.Format(Strings.ExArgumentMustBeLessThanOrEqualX, boundary)); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Core/Extensions/EnumerableExtensions.cs b/Orm/Xtensive.Orm/Core/Extensions/EnumerableExtensions.cs index 90feb754e9..632bc87544 100644 --- a/Orm/Xtensive.Orm/Core/Extensions/EnumerableExtensions.cs +++ b/Orm/Xtensive.Orm/Core/Extensions/EnumerableExtensions.cs @@ -8,6 +8,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -123,8 +124,6 @@ public static void ForEach(this IEnumerable items, Action action) action.Invoke(item); } - /// - /// Converts the sequence to the . /// /// The type of sequence item. /// The sequence to convert. @@ -280,12 +279,34 @@ public static IEnumerable> Zip( /// The sequence. /// Array of elements of /// or empty array, if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ToArraySafely(this IEnumerable sequence) { if (sequence == null) - return ArrayUtils.EmptyArray; + return Array.Empty(); return sequence.ToArray(); } + + /// + /// Same as sequence.ExtendWithDefaultsTo(length).Take(length).ToArray(), + /// but with a single allocation (of a resulting array). + /// + /// Source sequence. + /// The length of the resulting array. + /// The sequence element type. + /// The resulting array. + public static T[] ToArray(this IEnumerable sequence, int length) + { + if (length == 0) + return Array.Empty(); + + var result = new T[length]; + using (var e = sequence.GetEnumerator()) { + for (var i = 0; i < length && e.MoveNext(); i++) + result[i] = e.Current; + } + return result; + } /// /// Gets the items from the segment. @@ -592,4 +613,4 @@ internal static IEnumerator ToEnumerator(this IEnumerable e } } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Linq/SerializableExpressions/Internals/ReflectionExtensions.cs b/Orm/Xtensive.Orm/Linq/SerializableExpressions/Internals/ReflectionExtensions.cs index 79ff58e90d..8120a8d305 100644 --- a/Orm/Xtensive.Orm/Linq/SerializableExpressions/Internals/ReflectionExtensions.cs +++ b/Orm/Xtensive.Orm/Linq/SerializableExpressions/Internals/ReflectionExtensions.cs @@ -14,21 +14,11 @@ namespace Xtensive.Linq.SerializableExpressions.Internals { internal static class ReflectionExtensions { - public static string ToSerializableForm(this Type type) - { - if (type == null) - return null; + public static string ToSerializableForm(this Type type) + => type?.AssemblyQualifiedName; - return type.AssemblyQualifiedName; - } - - public static Type GetTypeFromSerializableForm(this string serializedValue) - { - if (serializedValue == null) - return null; - - return Type.GetType(serializedValue); - } + public static Type GetTypeFromSerializableForm(this string serializedValue) + => serializedValue == null ? null : Type.GetType(serializedValue); public static string ToSerializableForm(this MethodInfo method) { @@ -124,4 +114,4 @@ private static string[] SplitString(string str) : new[] {"\n"}, StringSplitOptions.None); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs b/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs index 63678dcd4a..d06fabc21d 100644 --- a/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs +++ b/Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs @@ -443,7 +443,8 @@ private KeyInfo BuildKeyInfo(TypeInfo root, HierarchyDef hierarchyDef) .Select(field => field.Column) .ToList(); - var keyTupleDescriptor = TupleDescriptor.Create(keyColumns.Select(c => c.ValueType)); + var keyTupleDescriptor = TupleDescriptor.Create( + keyColumns.Select(c => c.ValueType).ToArray(keyColumns.Count)); var typeIdColumnIndex = -1; if (hierarchyDef.IncludeTypeId) for (int i = 0; i < keyColumns.Count; i++) @@ -581,4 +582,4 @@ public TypeBuilder(BuildingContext context) .ToDictionary(configuration => context.NameBuilder.BuildKeyGeneratorName(configuration)); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/EntitySetBase.cs b/Orm/Xtensive.Orm/Orm/EntitySetBase.cs index d1c6e59b99..61813ec9c9 100644 --- a/Orm/Xtensive.Orm/Orm/EntitySetBase.cs +++ b/Orm/Xtensive.Orm/Orm/EntitySetBase.cs @@ -882,14 +882,18 @@ private static EntitySetTypeState BuildEntitySetTypeState(object key, EntitySetB .ToList() : Enumerable.Range(0, targetDescriptor.Count).ToList(); - var keyDescriptor = TupleDescriptor.Create(ownerDescriptor + var keyFieldCount = ownerDescriptor.Count + itemColumnOffsets.Count; + var keyFieldTypes = ownerDescriptor .Concat(itemColumnOffsets.Select(i => targetDescriptor[i])) - .ToList()); + .ToArray(keyFieldCount); + var keyDescriptor = TupleDescriptor.Create(keyFieldTypes); + var map = Enumerable.Range(0, ownerDescriptor.Count) .Select(i => new Pair(0, i)) .Concat(itemColumnOffsets.Select(i => new Pair(1, i))) - .ToArray(); + .ToArray(keyFieldCount); var seekTransform = new MapTransform(true, keyDescriptor, map); + Func itemCtor = null; if (association.AuxiliaryType!=null) itemCtor = DelegateHelper.CreateDelegate>(null, diff --git a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs index bbbbeb9e5c..a6722ef095 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs @@ -218,12 +218,12 @@ private void BuildConverter() IEnumerable types = EnumerableUtils.Empty; if (IsPersistableType(itemType)) { Expression = (Expression) BuildField(itemType, ref index, ref types); - TupleDescriptor = TupleDescriptor.Create(types); + TupleDescriptor = TupleDescriptor.Create(types.ToArray()); } else { - Xtensive.Collections.ISet processedTypes = new Set(); + Collections.ISet processedTypes = new Set(); LocalCollectionExpression itemExpression = BuildLocalCollectionExpression(itemType, processedTypes, ref index, null, ref types); - TupleDescriptor = TupleDescriptor.Create(types); + TupleDescriptor = TupleDescriptor.Create(types.ToArray()); Expression = itemExpression; } Func converter = delegate(TItem item) { @@ -247,4 +247,4 @@ public ItemToTupleConverter(Func> enumerableFunc, DomainModel BuildConverter(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs b/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs index 3b98a0c58f..50947f4181 100644 --- a/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs +++ b/Orm/Xtensive.Orm/Orm/Model/IndexInfo.cs @@ -383,9 +383,9 @@ public IndexInfo Clone() private void CreateTupleDescriptors() { tupleDescriptor = TupleDescriptor.Create( - from c in Columns select c.ValueType); + Columns.Select(c => c.ValueType).ToArray(Columns.Count)); keyTupleDescriptor = TupleDescriptor.Create( - from c in KeyColumns select c.Key.ValueType); + KeyColumns.Select(c => c.Key.ValueType).ToArray(KeyColumns.Count)); } private void CreateColumns() diff --git a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs index c716564266..4368ffeb23 100644 --- a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs +++ b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs @@ -751,7 +751,8 @@ private void CreateTupleDescriptor() var orderedColumns = columns.OrderBy(c => c.Field.MappingInfo.Offset).ToList(); columns = new ColumnInfoCollection(this, "Columns"); columns.AddRange(orderedColumns); - TupleDescriptor = TupleDescriptor.Create(Columns.Select(c => c.ValueType)); + TupleDescriptor = TupleDescriptor.Create( + Columns.Select(c => c.ValueType).ToArray(Columns.Count)); } private void BuildTuplePrototype() @@ -859,4 +860,4 @@ public TypeInfo(DomainModel model, TypeAttributes typeAttributes) affectedIndexes = new NodeCollection(this, "AffectedIndexes"); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs b/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs index 55fcee5ad8..d3b590ba48 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs @@ -71,9 +71,19 @@ public ColumnCollection Alias(string alias) /// /// Collection of items to add. public ColumnCollection(IEnumerable collection) - : base (collection.ToList()) + : base(collection.ToList()) + { + Initialize(); + } + + /// + /// Initializes a new instance of this class. + /// + /// Collection of items to add. + public ColumnCollection(List collection) + : base(collection) { Initialize(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/ColumnGroupCollection.cs b/Orm/Xtensive.Orm/Orm/Rse/ColumnGroupCollection.cs index 69e351789b..63b0a6dca2 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/ColumnGroupCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/ColumnGroupCollection.cs @@ -56,5 +56,14 @@ public ColumnGroupCollection(IEnumerable items) : base(items.ToList()) { } + + /// + /// Initializes a new instance of this class. + /// + /// The collection items. + public ColumnGroupCollection(List items) + : base(items) + { + } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/AggregateProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/AggregateProvider.cs index ef615ec4f9..ed25772d45 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/AggregateProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/AggregateProvider.cs @@ -73,14 +73,15 @@ protected override string ParametersToString() protected override void Initialize() { base.Initialize(); - var types = new List(); - int i = 0; + var fieldTypes = new Type[GroupColumnIndexes.Length]; var columnIndexes = new int[GroupColumnIndexes.Length]; + var i = 0; foreach (var index in GroupColumnIndexes) { - types.Add(Source.Header.Columns[index].Type); - columnIndexes[i++] = index; + fieldTypes[i] = Source.Header.Columns[index].Type; + columnIndexes[i] = index; + i++; } - Transform = new MapTransform(false, TupleDescriptor.Create(types), columnIndexes); + Transform = new MapTransform(false, TupleDescriptor.Create(fieldTypes), columnIndexes); } /// diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/ContainsTableProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/ContainsTableProvider.cs index 4727742ca3..dc240eb63c 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/ContainsTableProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/ContainsTableProvider.cs @@ -57,17 +57,15 @@ public ContainsTableProvider(FullTextIndexInfo index, Func searchCriteri indexHeader = primaryIndexRecordsetHeader.Add(rankColumn); } else { - if (index.PrimaryIndex.KeyColumns.Count!=1) + var primaryIndexKeyColumns = index.PrimaryIndex.KeyColumns; + if (primaryIndexKeyColumns.Count!=1) throw new InvalidOperationException(Strings.ExOnlySingleColumnKeySupported); - var fieldTypes = index - .PrimaryIndex - .KeyColumns + var fieldTypes = primaryIndexKeyColumns .Select(columnInfo => columnInfo.Key.ValueType) - .AddOne(typeof (double)); - TupleDescriptor tupleDescriptor = TupleDescriptor.Create(fieldTypes); - var columns = index - .PrimaryIndex - .KeyColumns + .AddOne(typeof (double)) + .ToArray(primaryIndexKeyColumns.Count + 1); + var tupleDescriptor = TupleDescriptor.Create(fieldTypes); + var columns = primaryIndexKeyColumns .Select((c, i) => (Column) new MappedColumn("KEY", i, c.Key.ValueType)) .AddOne(new MappedColumn("RANK", tupleDescriptor.Count, typeof (double))); indexHeader = new RecordSetHeader(tupleDescriptor, columns); diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/FreeTextProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/FreeTextProvider.cs index f51c684624..46e0048365 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/FreeTextProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/FreeTextProvider.cs @@ -55,17 +55,15 @@ public FreeTextProvider(FullTextIndexInfo index, Func searchCriteria, st indexHeader = primaryIndexRecordsetHeader.Add(rankColumn); } else { - if (index.PrimaryIndex.KeyColumns.Count!=1) + var primaryIndexKeyColumns = index.PrimaryIndex.KeyColumns; + if (primaryIndexKeyColumns.Count!=1) throw new InvalidOperationException(Strings.ExOnlySingleColumnKeySupported); - var fieldTypes = index - .PrimaryIndex - .KeyColumns + var fieldTypes = primaryIndexKeyColumns .Select(columnInfo => columnInfo.Key.ValueType) - .AddOne(typeof (double)); - TupleDescriptor tupleDescriptor = TupleDescriptor.Create(fieldTypes); - var columns = index - .PrimaryIndex - .KeyColumns + .AddOne(typeof (double)) + .ToArray(primaryIndexKeyColumns.Count + 1); + var tupleDescriptor = TupleDescriptor.Create(fieldTypes); + var columns = primaryIndexKeyColumns .Select((c, i) => (Column) new MappedColumn("KEY", i, c.Key.ValueType)) .AddOne(new MappedColumn("RANK", tupleDescriptor.Count, typeof (double))); indexHeader = new RecordSetHeader(tupleDescriptor, columns); @@ -73,4 +71,4 @@ public FreeTextProvider(FullTextIndexInfo index, Func searchCriteria, st Initialize(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs index 5da79be5d1..0048e0db90 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs @@ -66,9 +66,12 @@ public int[] FilteredColumns { protected override RecordSetHeader BuildHeader() { var newHeader = Source.Header.Add(new SystemColumn(ResultColumnName, 0, typeof(bool))); - var types = FilteredColumns.Select(m => newHeader.Columns[m].Type); - FilteredColumnsExtractionTransform = new MapTransform(true, TupleDescriptor.Create(types), FilteredColumns); - ResultTransform = new CombineTransform(true, Source.Header.TupleDescriptor, TupleDescriptor.Create(new []{typeof(bool)})); + var fieldTypes = FilteredColumns + .Select(m => newHeader.Columns[m].Type) + .ToArray(FilteredColumns.Length); + var tupleDescriptor = TupleDescriptor.Create(fieldTypes); + FilteredColumnsExtractionTransform = new MapTransform(true, tupleDescriptor, FilteredColumns); + ResultTransform = new CombineTransform(true, Source.Header.TupleDescriptor, TupleDescriptor.Create()); return newHeader; } @@ -99,4 +102,4 @@ public IncludeProvider(CompilableProvider source, IncludeAlgorithm algorithm, bo Initialize(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/OrderProviderBase.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/OrderProviderBase.cs index 0cb012903d..f7fed46a72 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/OrderProviderBase.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/OrderProviderBase.cs @@ -11,7 +11,7 @@ using Xtensive.Collections; using Xtensive.Comparison; using Xtensive.Core; - +using Xtensive.Orm.FullTextSearchCondition.Nodes; using Xtensive.Tuples; using Tuple = Xtensive.Tuples.Tuple; using Xtensive.Tuples.Transform; @@ -74,8 +74,15 @@ protected override void Initialize() comparisonRules[i] = new ComparisonRule(orderItem.Value, culture); } - var orderKeyDescriptor = TupleDescriptor.Create(Order.Select(p => Header.Columns[p.Key].Type)); - OrderKeyExtractorTransform = new MapTransform(true, orderKeyDescriptor, Order.Select(p => p.Key).ToArray()); + var fieldTypes = new Type[Order.Count]; + var map = new int[Order.Count]; + for (var i = 0; i < Order.Count; i++) { + var p = Order[i]; + fieldTypes[i] = Header.Columns[p.Key].Type; + map[i] = p.Key; + } + var orderKeyDescriptor = TupleDescriptor.Create(fieldTypes); + OrderKeyExtractorTransform = new MapTransform(true, orderKeyDescriptor, map); } @@ -93,4 +100,4 @@ protected OrderProviderBase(ProviderType providerType, CompilableProvider source Order = order; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs b/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs index 7f66a9f64f..cfc2631856 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs @@ -62,8 +62,11 @@ public TupleDescriptor OrderTupleDescriptor { get { if (Order.Count==0) return null; - if (orderTupleDescriptor==null) lock(this) if (orderTupleDescriptor==null) - orderTupleDescriptor = TupleDescriptor.Create(Order.Select(p => Columns[p.Key].Type)); + if (orderTupleDescriptor==null) lock(this) if (orderTupleDescriptor==null) { + var fieldTypes = Order.Select(p => Columns[p.Key].Type).ToArray(Order.Count); + orderTupleDescriptor = TupleDescriptor.Create(fieldTypes); + } + return orderTupleDescriptor; } } @@ -95,19 +98,21 @@ public RecordSetHeader Add(Column column) /// /// Adds the specified columns to header. /// - /// The columns. + /// The columns to add. /// The constructed header. public RecordSetHeader Add(IEnumerable columns) { - var resultColumns = new List(Columns); - resultColumns.AddRange(columns); - var typeList = new List(TupleDescriptor); - foreach (var value in columns) - typeList.Add(value.Type); - var resultTupleDescriptor = TupleDescriptor.Create(typeList); + var newColumns = new List(Columns); + newColumns.AddRange(columns); + + var newFieldTypes = new Type[newColumns.Count]; + for (var i = 0; i < newColumns.Count; i++) + newFieldTypes[i] = newColumns[i].Type; + var newTupleDescriptor = TupleDescriptor.Create(newFieldTypes); + return new RecordSetHeader( - resultTupleDescriptor, - resultColumns, + newTupleDescriptor, + newColumns, ColumnGroups, OrderTupleDescriptor, Order); @@ -120,26 +125,28 @@ public RecordSetHeader Add(IEnumerable columns) /// The joined header. public RecordSetHeader Join(RecordSetHeader joined) { - var columns = new List(Columns); - var originalColumnsCount = Columns.Count; - columns.AddRange( + var columnCount = Columns.Count; + var newColumns = new List(Columns); + newColumns.AddRange( from c in joined.Columns - select c.Clone(originalColumnsCount + c.Index)); + select c.Clone(columnCount + c.Index)); - var types = new List(TupleDescriptor); - types.AddRange(joined.TupleDescriptor); + var newFieldTypes = new Type[newColumns.Count]; + for (var i = 0; i < newColumns.Count; i++) + newFieldTypes[i] = newColumns[i].Type; + var newTupleDescriptor = TupleDescriptor.Create(newFieldTypes); var groups = new List(ColumnGroups); groups.AddRange( joined.ColumnGroups .Select(g => new ColumnGroup( g.TypeInfoRef, - g.Keys.Select(i => originalColumnsCount + i), - g.Columns.Select(i => originalColumnsCount + i)))); + g.Keys.Select(i => columnCount + i), + g.Columns.Select(i => columnCount + i)))); return new RecordSetHeader( - TupleDescriptor.Create(types), - columns, + newTupleDescriptor, + newColumns, groups, OrderTupleDescriptor, Order); @@ -159,7 +166,8 @@ public RecordSetHeader Select(IEnumerable selectedColumns) columnsMap[oldIndex] = newIndex; } - var resultTupleDescriptor = Xtensive.Tuples.TupleDescriptor.Create(columns.Select(i => TupleDescriptor[i])); + var fieldTypes = columns.Select(i => TupleDescriptor[i]).ToArray(columns.Count); + var resultTupleDescriptor = Xtensive.Tuples.TupleDescriptor.Create(fieldTypes); var resultOrder = new DirectionCollection( Order .Select(o => new KeyValuePair(columnsMap[o.Key], o.Value)) @@ -212,24 +220,30 @@ public static RecordSetHeader GetHeader(IndexInfo indexInfo) private static RecordSetHeader CreateHeader(IndexInfo indexInfo) { - TupleDescriptor resultTupleDescriptor = TupleDescriptor.Create( - indexInfo.Columns.Select(columnInfo => columnInfo.ValueType)); + var indexInfoColumns = indexInfo.Columns; + var indexInfoKeyColumns = indexInfo.KeyColumns; + + var resultFieldTypes = indexInfoColumns.Select(columnInfo => columnInfo.ValueType).ToArray(indexInfoColumns.Count); + var resultTupleDescriptor = TupleDescriptor.Create(resultFieldTypes); var keyOrder = new List>( - indexInfo.KeyColumns.Select((p, i) => new KeyValuePair(i, p.Value))); - + indexInfoKeyColumns.Select((p, i) => new KeyValuePair(i, p.Value))); if (!indexInfo.IsPrimary) { var pkKeys = indexInfo.ReflectedType.Indexes.PrimaryIndex.KeyColumns; keyOrder.AddRange( indexInfo.ValueColumns - .Select((c, i) => new Pair(c, i + indexInfo.KeyColumns.Count)) + .Select((c, i) => new Pair(c, i + indexInfoKeyColumns.Count)) .Where(pair => pair.First.IsPrimaryKey) .Select(pair => new KeyValuePair(pair.Second, pkKeys[pair.First]))); } - var order = new DirectionCollection(keyOrder); - var keyDescriptor = TupleDescriptor.Create(indexInfo.KeyColumns.Select(columnInfo => columnInfo.Key.ValueType)); - var resultColumns = indexInfo.Columns.Select((c,i) => (Column) new MappedColumn(c,i,c.ValueType)); + + var keyFieldTypes = indexInfoKeyColumns + .Select(columnInfo => columnInfo.Key.ValueType) + .ToArray(indexInfoKeyColumns.Count); + var keyDescriptor = TupleDescriptor.Create(keyFieldTypes); + + var resultColumns = indexInfoColumns.Select((c,i) => (Column) new MappedColumn(c,i,c.ValueType)); var resultGroups = new[]{indexInfo.Group}; return new RecordSetHeader( @@ -266,12 +280,12 @@ public RecordSetHeader( /// /// Descriptor of the result item. /// Result columns. - /// Column groups. + /// Column groups. public RecordSetHeader( TupleDescriptor tupleDescriptor, IEnumerable columns, - IEnumerable groups) - : this(tupleDescriptor, columns, groups, null, null) + IEnumerable columnGroups) + : this(tupleDescriptor, columns, columnGroups, null, null) { } @@ -296,14 +310,14 @@ public RecordSetHeader( /// /// Descriptor of the result item. /// Result columns. - /// Column groups. + /// Column groups. /// Descriptor of ordered columns. /// Result sort order. /// columns.Count is out of range. public RecordSetHeader( TupleDescriptor tupleDescriptor, IEnumerable columns, - IEnumerable groups, + IEnumerable columnGroups, TupleDescriptor orderKeyDescriptor, DirectionCollection order) { @@ -311,13 +325,19 @@ public RecordSetHeader( ArgumentValidator.EnsureArgumentNotNull(columns, "columns"); TupleDescriptor = tupleDescriptor; - Columns = new ColumnCollection(columns); + // Unsafe perf. optimization: if you pass a list, it should be immutable! + Columns = columns is List columnList + ? new ColumnCollection(columnList) + : new ColumnCollection(columns); if (tupleDescriptor.Count!=Columns.Count) throw new ArgumentOutOfRangeException("columns.Count"); - ColumnGroups = groups==null + ColumnGroups = columnGroups == null ? ColumnGroupCollection.Empty - : new ColumnGroupCollection(groups); + // Unsafe perf. optimization: if you pass a list, it should be immutable! + : (columnGroups is List columnGroupList + ? new ColumnGroupCollection(columnGroupList) + : new ColumnGroupCollection(columnGroups)); orderTupleDescriptor = orderKeyDescriptor ?? TupleDescriptor.Empty; Order = order ?? new DirectionCollection(); diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs index 42a2ca0637..4b2ac1a5ff 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs @@ -14,14 +14,13 @@ internal static class PackedFieldAccessorFactory private static readonly PackedFieldAccessor ObjectAccessor; private static readonly Dictionary ValueAccessors; - public static IEnumerable KnownTypes { get { return ValueAccessors.Keys; } } + public static IEnumerable KnownTypes => ValueAccessors.Keys; - public static void ProvideAccessor(Type valueType, PackedFieldDescriptor descriptor) + public static void ConfigureDescriptor(PackedFieldDescriptor descriptor, Type accessorType) { - ValueFieldAccessor valueAccessor; - if (ValueAccessors.TryGetValue(valueType, out valueAccessor)) { - descriptor.PackingType = FieldPackingType.Value; + if (ValueAccessors.TryGetValue(accessorType, out var valueAccessor)) { descriptor.Accessor = valueAccessor; + descriptor.PackingType = FieldPackingType.Value; descriptor.ValueBitCount = valueAccessor.BitCount; descriptor.ValueBitMask = valueAccessor.BitMask; } @@ -40,9 +39,7 @@ private static void RegisterAccessor(ValueFieldAccessor accessor) static PackedFieldAccessorFactory() { ObjectAccessor = new ObjectFieldAccessor(); - ValueAccessors = new Dictionary(); - RegisterAccessor(new BooleanFieldAccessor()); RegisterAccessor(new ByteFieldAccessor()); RegisterAccessor(new SByteFieldAccessor()); @@ -60,4 +57,4 @@ static PackedFieldAccessorFactory() RegisterAccessor(new GuidFieldAccessor()); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs new file mode 100644 index 0000000000..4ddf05b233 --- /dev/null +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Xtensive.Tuples.Packed +{ + internal class PackedFieldDescriptorComparer : IComparer + { + public static readonly PackedFieldDescriptorComparer Instance = + new PackedFieldDescriptorComparer(); + + public int Compare(PackedFieldDescriptor x, PackedFieldDescriptor y) + { + var t = y.ValueBitCount - x.ValueBitCount; + if (t != 0) + return t; + return x.FieldIndex - y.FieldIndex; + } + } +} diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index be3b59111d..b37d3f0b52 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -6,6 +6,7 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -27,14 +28,23 @@ namespace Xtensive.Tuples public sealed class TupleDescriptor : IEquatable, IList, ISerializable { [NonSerialized] - private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(new Type[0]); + private static readonly TupleDescriptor EmptyDescriptor = + new TupleDescriptor(new Type[0]); [NonSerialized] - private static readonly Dictionary SingleFieldDescriptors = new Dictionary(); - - //private string[] fieldTypeNames; + private static readonly Dictionary CachedDescriptors1 = + new Dictionary(); + [NonSerialized] + private static readonly Dictionary<(Type, Type), TupleDescriptor> CachedDescriptors2 = + new Dictionary<(Type, Type), TupleDescriptor>(); + [NonSerialized] + private static readonly Dictionary<(Type, Type, Type), TupleDescriptor> CachedDescriptors3 = + new Dictionary<(Type, Type, Type), TupleDescriptor>(); + [NonSerialized] + private static readonly ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor> CachedDescriptors4 = + new ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor>(); [NonSerialized] - private Type[] fieldTypes; + private Type[] _fieldTypes; internal readonly int FieldCount; internal readonly int ValuesLength; @@ -43,10 +53,7 @@ public sealed class TupleDescriptor : IEquatable, IList, [NonSerialized] internal readonly PackedFieldDescriptor[] FieldDescriptors; - internal Type[] FieldTypes - { - get { return fieldTypes; } - } + internal Type[] FieldTypes => _fieldTypes; /// /// Gets the empty tuple descriptor. @@ -55,50 +62,7 @@ internal Type[] FieldTypes public static TupleDescriptor Empty { [DebuggerStepThrough] - get { return EmptyDescriptor; } - } - - /// - /// Gets total count of compiled descriptors. - /// - [Obsolete("Tuple descriptors are no longer cached. This property always returns -1")] - public static int TotalCount - { - [DebuggerStepThrough] - get { return -1; } - } - - /// - [Obsolete("Tuple descriptors no longer has unique indentifier. This property always returns 0.")] - public int Identifier - { - [DebuggerStepThrough] - get { return 0; } - } - - /// - /// Indicates whether class for handling underlying - /// is already compiled. - /// - [Obsolete("Tuple descriptors are always initialized. This property always returns true.")] - public bool IsInitialized - { - [DebuggerStepThrough] - get { return true; } - } - - /// - /// Gets the type of underlying - /// implementation. , if - /// ==. - /// - [Obsolete("This property always returns the same type.")] - public Type TupleType - { - get - { - return typeof (PackedTuple); - } + get => EmptyDescriptor; } /// @@ -110,7 +74,7 @@ public int GetCommonPartLength(TupleDescriptor other) ArgumentValidator.EnsureArgumentNotNull(other, "other"); var minCount = FieldCount < other.FieldCount ? FieldCount : other.FieldCount; for (int i = 0; i < minCount; i++) { - if (FieldTypes[i]!=other.FieldTypes[i]) + if (FieldTypes[i] != other.FieldTypes[i]) return i; } return minCount; @@ -124,32 +88,28 @@ public int GetCommonPartLength(TupleDescriptor other) /// if specified field is a value type field; /// otherwise, . /// - public bool IsValueType(int fieldIndex) - { - return FieldTypes[fieldIndex].IsValueType; - } + public bool IsValueType(int fieldIndex) + => FieldTypes[fieldIndex].IsValueType; #region IList members /// public Type this[int fieldIndex] { - get { return FieldTypes[fieldIndex]; } - set { throw Exceptions.CollectionIsReadOnly(null); } + get => FieldTypes[fieldIndex]; + set => throw Exceptions.CollectionIsReadOnly(null); } /// public int Count { [DebuggerStepThrough] - get { return FieldCount; } + get => FieldCount; } /// - public int IndexOf(Type item) - { - return FieldTypes.IndexOf(item, true); - } + public int IndexOf(Type item) + => FieldTypes.IndexOf(item, true); /// public void Insert(int index, Type item) @@ -307,70 +267,84 @@ public override string ToString() // PackedFieldAccessorFactory.ProvideAccessor(FieldTypes[i], FieldDescriptors[i]); //} - private static TupleDescriptor CreateInternal(IList fieldTypes) + #region Create methods (base) + + public static TupleDescriptor Create(Type t1) { - var fieldCount = fieldTypes.Count; - if (fieldCount==0) - return EmptyDescriptor; - if (fieldCount==1) { - TupleDescriptor cachedDescriptor; - if (SingleFieldDescriptors.TryGetValue(fieldTypes[0], out cachedDescriptor)) - return cachedDescriptor; - } - return new TupleDescriptor(fieldTypes); + if (CachedDescriptors1.TryGetValue(t1, out var cachedDescriptor)) + return cachedDescriptor; + return new TupleDescriptor(new [] {t1}); } - #region Create methods (base) + public static TupleDescriptor Create(Type t1, Type t2) + { + var key = (t1, t2); + if (CachedDescriptors2.TryGetValue(key, out var cachedDescriptor)) + return cachedDescriptor; + return new TupleDescriptor(new [] {t1, t2}); + } - /// - /// Creates or returns already created descriptor - /// for provided set of types. - /// - /// List of tuple field types. - /// Either new or existing tuple descriptor - /// describing the specified set of fields. - public static TupleDescriptor Create(Type[] fieldTypes) + public static TupleDescriptor Create(Type t1, Type t2, Type t3) { - ArgumentValidator.EnsureArgumentNotNull(fieldTypes, "fieldTypes"); - return CreateInternal(fieldTypes); + var key = (t1, t2, t3); + if (CachedDescriptors3.TryGetValue(key, out var cachedDescriptor)) + return cachedDescriptor; + return new TupleDescriptor(new [] {t1, t2, t3}); } - /// - /// Creates or returns already created descriptor - /// for provided set of types. - /// - /// List of tuple field types. - /// Either new or existing tuple descriptor - /// describing the specified set of fields. - public static TupleDescriptor Create(IList fieldTypes) + public static TupleDescriptor Create(Type t1, Type t2, Type t3, Type t4) { - ArgumentValidator.EnsureArgumentNotNull(fieldTypes, "fieldTypes"); - return CreateInternal(fieldTypes); + var key = (t1, t2, t3, t4); + return CachedDescriptors4.GetOrAdd(key, k => + new TupleDescriptor(new [] {k.Item1, k.Item2, k.Item3, k.Item4})); } /// /// Creates or returns already created descriptor /// for provided set of types. /// - /// Enumerable of tuple field types. + /// List of tuple field types. /// Either new or existing tuple descriptor /// describing the specified set of fields. - public static TupleDescriptor Create(IEnumerable fieldTypes) + public static TupleDescriptor Create(Type[] fieldTypes) { - ArgumentValidator.EnsureArgumentNotNull(fieldTypes, "fieldTypes"); - return CreateInternal(fieldTypes.ToList()); + ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); + switch (fieldTypes.Length) { + case 0: + return EmptyDescriptor; + case 1: + if (CachedDescriptors1.TryGetValue(fieldTypes[0], out var cachedDescriptor)) + return cachedDescriptor; + break; + case 2: + var key2 = (fieldTypes[0], fieldTypes[1]); + if (CachedDescriptors2.TryGetValue(key2, out cachedDescriptor)) + return cachedDescriptor; + break; + case 3: + var key3 = (fieldTypes[0], fieldTypes[1], fieldTypes[2]); + if (CachedDescriptors3.TryGetValue(key3, out cachedDescriptor)) + return cachedDescriptor; + break; + case 4: + var key4 = (fieldTypes[0], fieldTypes[1], fieldTypes[2], fieldTypes[3]); + return CachedDescriptors4.GetOrAdd(key4, k => + new TupleDescriptor(new [] {k.Item1, k.Item2, k.Item3, k.Item4})); + } + return new TupleDescriptor(fieldTypes); } /// /// Creates tuple descriptor containing head of the current one. /// - /// Head field count. + /// Head field count. /// Either new or existing tuple descriptor /// describing the specified set of fields. - public TupleDescriptor Head(int headFieldCount) + public TupleDescriptor Head(int fieldCount) { - ArgumentValidator.EnsureArgumentIsInRange(headFieldCount, 1, Count, "headFieldCount"); - return Create(FieldTypes.Take(headFieldCount)); + ArgumentValidator.EnsureArgumentIsInRange(fieldCount, 1, Count, "fieldCount"); + var fieldTypes = FieldTypes.ToArray(fieldCount); + return Create(fieldTypes); } /// @@ -382,7 +356,8 @@ public TupleDescriptor Head(int headFieldCount) public TupleDescriptor Tail(int tailFieldCount) { ArgumentValidator.EnsureArgumentIsInRange(tailFieldCount, 1, Count, "tailFieldCount"); - return Create(FieldTypes.Skip(Count - tailFieldCount)); + var fieldTypes = FieldTypes.Skip(Count - tailFieldCount).ToArray(tailFieldCount); + return Create(fieldTypes); } #endregion @@ -394,12 +369,8 @@ public TupleDescriptor Tail(int tailFieldCount) /// /// Type of the only tuple field. /// Newly created object. - public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T) - }); - } + public static TupleDescriptor Create() + => Create(typeof(T)); /// /// Creates new by its field type(s). @@ -407,13 +378,8 @@ public static TupleDescriptor Create() /// Type of the first tuple field. /// Type of the 2nd tuple field. /// Newly created object - public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T1), - typeof (T2) - }); - } + public static TupleDescriptor Create() + => Create(typeof(T1), typeof(T2)); /// /// Creates new by its field type(s). @@ -423,13 +389,7 @@ public static TupleDescriptor Create() /// Type of the 3rd tuple field. /// Newly created object public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T1), - typeof (T2), - typeof (T3) - }); - } + => Create(typeof(T1), typeof(T2), typeof(T3)); /// /// Creates new by its field type(s). @@ -440,132 +400,68 @@ public static TupleDescriptor Create() /// Type of the 4th tuple field. /// Newly created object public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T1), - typeof (T2), - typeof (T3), - typeof (T4) - }); - } - - /// - /// Creates new by its field type(s). - /// - /// Type of the first tuple field. - /// Type of the 2nd tuple field. - /// Type of the 3rd tuple field. - /// Type of the 4th tuple field. - /// Type of the 5th tuple field. - /// Newly created object - public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T1), - typeof (T2), - typeof (T3), - typeof (T4), - typeof (T5) - }); - } - - /// - /// Creates new by its field type(s). - /// - /// Type of the first tuple field. - /// Type of the 2nd tuple field. - /// Type of the 3rd tuple field. - /// Type of the 4th tuple field. - /// Type of the 5th tuple field. - /// Type of the 6th tuple field. - /// Newly created object - public static TupleDescriptor Create() - { - return CreateInternal(new[] { - typeof (T1), - typeof (T2), - typeof (T3), - typeof (T4), - typeof (T5), - typeof (T6) - }); - } + => Create(typeof(T1), typeof(T2), typeof(T3), typeof(T4)); #endregion // Constructors - private TupleDescriptor(IList fieldTypes) + private TupleDescriptor(Type[] fieldTypes) { - ArgumentValidator.EnsureArgumentNotNull(fieldTypes, "fieldTypes"); + ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); - FieldCount = fieldTypes.Count; - this.fieldTypes = new Type[FieldCount]; + _fieldTypes = fieldTypes; + FieldCount = fieldTypes.Length; FieldDescriptors = new PackedFieldDescriptor[FieldCount]; - const int longBits = 64; - const int stateBits = 2; - const int statesPerLong = longBits / stateBits; + const int longBitCount = 64; + const int stateBitCount = 2; + const int statesPerLong = longBitCount / stateBitCount; var objectIndex = 0; - - var valueIndex = FieldCount / statesPerLong + Math.Min(1, FieldCount % statesPerLong); + var valueIndex = (FieldCount + statesPerLong - 1) / statesPerLong; var valueBitOffset = 0; - var stateIndex = 0; - var stateBitOffset = 0; - - for (int i = 0; i < FieldCount; i++) { + for (var i = 0; i < fieldTypes.Length; i++) { var fieldType = fieldTypes[i].StripNullable(); - var descriptor = new PackedFieldDescriptor {FieldIndex = i}; - - PackedFieldAccessorFactory.ProvideAccessor(fieldType, descriptor); - - FieldTypes[i] = fieldType; + var descriptor = new PackedFieldDescriptor { FieldIndex = i }; + PackedFieldAccessorFactory.ConfigureDescriptor(descriptor, fieldType); + _fieldTypes[i] = fieldType; FieldDescriptors[i] = descriptor; } - var orderedDescriptors = FieldDescriptors - .OrderByDescending(d => d.ValueBitCount) - .ThenBy(d => d.FieldIndex); - - foreach (var descriptor in orderedDescriptors) { - switch (descriptor.PackingType) { - case FieldPackingType.Object: - descriptor.ValueIndex = objectIndex++; - break; - case FieldPackingType.Value: - if (descriptor.ValueBitCount > longBits) { - if (valueBitOffset > 0) { - valueIndex++; - valueBitOffset = 0; - } - descriptor.ValueIndex = valueIndex; - descriptor.ValueBitOffset = 0; - valueIndex += descriptor.ValueBitCount / longBits + Math.Min(1, descriptor.ValueBitCount % longBits); - } - else { - if (valueBitOffset + descriptor.ValueBitCount > longBits) { - valueIndex++; - valueBitOffset = 0; - } - descriptor.ValueIndex = valueIndex; - descriptor.ValueBitOffset = valueBitOffset; - valueBitOffset += descriptor.ValueBitCount; + var orderedDescriptors = (PackedFieldDescriptor[]) FieldDescriptors.Clone(); + Array.Sort(orderedDescriptors, PackedFieldDescriptorComparer.Instance); + + foreach (var d in orderedDescriptors) { + var fieldIndex = d.FieldIndex; + d.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 + d.StateBitOffset = (fieldIndex & 31) << 1; + + if (d.PackingType == FieldPackingType.Object) { + d.ValueIndex = objectIndex++; + continue; + } + + // d.PackingType == FieldPackingType.Value + if (d.ValueBitCount >= longBitCount) { + if (valueBitOffset != 0) { + valueIndex++; + valueBitOffset = 0; } - break; - default: - throw new ArgumentOutOfRangeException("descriptor.PackType"); + d.ValueIndex = valueIndex; + valueIndex += (d.ValueBitCount + longBitCount - 1) / longBitCount; } - - if (stateBitOffset + stateBits > longBits) { - stateIndex++; - stateBitOffset = 0; + else { + d.ValueIndex = valueIndex; + d.ValueBitOffset = valueBitOffset; + valueBitOffset += d.ValueBitCount; + if (valueBitOffset > longBitCount) { + d.ValueIndex = ++valueIndex; + d.ValueBitOffset = 0; + valueBitOffset = d.ValueBitCount; + } } - - descriptor.StateIndex = stateIndex; - descriptor.StateBitOffset = stateBitOffset; - stateBitOffset += stateBits; } ValuesLength = valueIndex + Math.Min(1, valueBitOffset); @@ -578,23 +474,33 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) ValuesLength = info.GetInt32("ValuesLength"); ObjectsLength = info.GetInt32("ObjectsLength"); - var typeNames = (string[]) info.GetValue("FieldTypes", typeof(string[])); - FieldDescriptors = (PackedFieldDescriptor[])info.GetValue("FieldDescriptors", typeof(PackedFieldDescriptor[])); - - fieldTypes = new Type[typeNames.Length]; - for (int i = 0; i < typeNames.Length; i++) - FieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); - for (int i = 0; i < FieldCount; i++) - PackedFieldAccessorFactory.ProvideAccessor(FieldTypes[i], FieldDescriptors[i]); + FieldDescriptors = (PackedFieldDescriptor[])info.GetValue( + "FieldDescriptors", typeof(PackedFieldDescriptor[])); + _fieldTypes = new Type[typeNames.Length]; + for (var i = 0; i < typeNames.Length; i++) + _fieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); + for (var i = 0; i < _fieldTypes.Length; i++) + PackedFieldAccessorFactory.ConfigureDescriptor(FieldDescriptors[i], _fieldTypes[i]); } static TupleDescriptor() { - foreach (var type in PackedFieldAccessorFactory.KnownTypes) - SingleFieldDescriptors.Add(type, new TupleDescriptor(new[] {type})); + var types = PackedFieldAccessorFactory.KnownTypes.Concat(new [] { + typeof(string), + typeof(byte[]), + }); + foreach (var type1 in types) { + CachedDescriptors1.Add(type1, new TupleDescriptor(new[] {type1})); + foreach (var type2 in types) { + CachedDescriptors2.Add((type1, type2), new TupleDescriptor(new[] {type1, type2})); + foreach (var type3 in types) { + CachedDescriptors3.Add((type1, type2, type3), new TupleDescriptor(new[] {type1, type2, type3})); + } + } + } } } } diff --git a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs index 1f8a7ac6ba..8183c72c36 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs @@ -200,24 +200,19 @@ public static Tuple Combine(this Tuple left, Tuple right) /// public static Tuple GetSegment(this Tuple tuple, Segment segment) { - var map = new int[segment.Length]; - for (int i = 0; i < segment.Length; i++) - map[i] = segment.Offset + i; - - var types = new ArraySegment(tuple.Descriptor.FieldTypes, segment.Offset, segment.Length); - var descriptor = TupleDescriptor.Create(types.AsEnumerable()); + var length = segment.Length; + var map = new int[length]; + var fieldTypes = new Type[length]; + for (var index = 0; index < map.Length; index++) { + var sourceIndex = segment.Offset + index; + map[index] = sourceIndex; + fieldTypes[index] = tuple.Descriptor.FieldTypes[sourceIndex]; + } + var descriptor = TupleDescriptor.Create(fieldTypes); var transform = new MapTransform(false, descriptor, map); return transform.Apply(TupleTransformType.TransformedTuple, tuple); } - private static IEnumerable AsEnumerable(this ArraySegment segment) - { - ArgumentValidator.EnsureArgumentNotNull(segment, "segment"); - int lastPosition = segment.Offset + segment.Count; - for (int i = segment.Offset; i < lastPosition; i++) - yield return segment.Array[i]; - } - #endregion #region Merge methods @@ -559,4 +554,4 @@ private static void MergeTuplesPreferOriginFast(PackedTuple origin, PackedTuple } } } -} \ No newline at end of file +} From b6430ae20a83715cdffd92346092ee6e2b2a92df Mon Sep 17 00:00:00 2001 From: Alex Yakunin Date: Mon, 3 Feb 2020 17:39:22 -0800 Subject: [PATCH 02/31] More performance related fixes based on profiling. # Conflicts: # Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs --- .../Internals/ExpressionVisitor.cs | 2 +- .../Collections/DirectionCollection.cs | 33 +++++++------------ .../Comparison/AdvancedComparerStruct.cs | 30 ++++++++--------- Orm/Xtensive.Orm/Conversion/Biconverter.cs | 4 +-- Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs | 10 ++---- Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs | 6 ++-- .../Linq/ExpressionVisitor{TResult}.cs | 6 ++-- Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs | 12 ++++--- Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs | 2 +- 9 files changed, 46 insertions(+), 59 deletions(-) diff --git a/Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs b/Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs index 1a3fe05bd9..e568eca763 100644 --- a/Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs +++ b/Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs @@ -206,7 +206,7 @@ private IEnumerable VisitExpressionList(ReadOnlyCollection list = null; for (int i = 0, n = original.Count; i < n; i++) { - Expression p = Visit(original[i]); + var p = Visit(original[i]); if (list!=null) list.Add(p); else if (p!=original[i]) { diff --git a/Orm/Xtensive.Orm/Collections/DirectionCollection.cs b/Orm/Xtensive.Orm/Collections/DirectionCollection.cs index 37cbff7325..fce75dc282 100644 --- a/Orm/Xtensive.Orm/Collections/DirectionCollection.cs +++ b/Orm/Xtensive.Orm/Collections/DirectionCollection.cs @@ -22,6 +22,13 @@ namespace Xtensive.Collections [DebuggerDisplay("Count = {Count}")] public sealed class DirectionCollection: FlagCollection { + private static readonly Biconverter DirectionToBoolBiconverter = + new Biconverter( + value => value == Direction.None + ? throw Exceptions.InvalidArgument(value, nameof(value)) + : value == Direction.Positive, + value => value ? Direction.Positive : Direction.Negative); + /// public override void Add(T key) { @@ -33,13 +40,7 @@ public override void Add(T key) /// /// Initial content of collection. public DirectionCollection(IEnumerable> enumerable) - : base(new Biconverter( - delegate (Direction value) { - if (value==Direction.None) - throw Exceptions.InvalidArgument(value, "value"); - return value == Direction.Positive; - }, - delegate(bool value) { return value ? Direction.Positive : Direction.Negative; }), + : base(DirectionToBoolBiconverter, enumerable) { } @@ -49,13 +50,7 @@ public DirectionCollection(IEnumerable> enumerable) /// /// Initial content of collection. public DirectionCollection(params T[] items) - : base(new Biconverter( - value => { - if (value==Direction.None) - throw Exceptions.InvalidArgument(value, "value"); - return value==Direction.Positive; - }, - value => value ? Direction.Positive : Direction.Negative)) + : base(DirectionToBoolBiconverter) { foreach (T item in items) Add(item, Direction.Positive); @@ -65,14 +60,8 @@ public DirectionCollection(params T[] items) /// Initializes a new instance of this type. /// public DirectionCollection() - : base(new Biconverter( - value => { - if (value==Direction.None) - throw Exceptions.InvalidArgument(value, "value"); - return value==Direction.Positive; - }, - value => value ? Direction.Positive : Direction.Negative)) + : base(DirectionToBoolBiconverter) { } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Comparison/AdvancedComparerStruct.cs b/Orm/Xtensive.Orm/Comparison/AdvancedComparerStruct.cs index ec7685e5f0..4cad5fbd12 100644 --- a/Orm/Xtensive.Orm/Comparison/AdvancedComparerStruct.cs +++ b/Orm/Xtensive.Orm/Comparison/AdvancedComparerStruct.cs @@ -19,7 +19,7 @@ namespace Xtensive.Comparison /// /// The type of generic argument. [Serializable] - public struct AdvancedComparerStruct: ISerializable + public readonly struct AdvancedComparerStruct: ISerializable { /// /// Gets for comparer. @@ -29,7 +29,7 @@ public struct AdvancedComparerStruct: ISerializable /// /// Gets for comparer. /// - public readonly static AdvancedComparerStruct System = new AdvancedComparerStruct(AdvancedComparer.System); + public static readonly AdvancedComparerStruct System = new AdvancedComparerStruct(AdvancedComparer.System); /// /// Gets the underlying comparer for this cache. @@ -44,12 +44,12 @@ public struct AdvancedComparerStruct: ISerializable /// /// Gets method delegate. /// - public readonly new Predicate Equals; + public new readonly Predicate Equals; /// /// Gets method delegate. /// - public readonly new Func GetHashCode; + public new readonly Func GetHashCode; /// /// Gets method delegate. @@ -92,11 +92,11 @@ public static implicit operator AdvancedComparerStruct(AdvancedComparer co private AdvancedComparerStruct(AdvancedComparer comparer) { Comparer = comparer; - Compare = Comparer==null ? null : Comparer.Compare; - Equals = Comparer==null ? null : Comparer.Equals; - GetHashCode = Comparer==null ? null : Comparer.GetHashCode; - GetNearestValue = Comparer==null ? null : Comparer.GetNearestValue; - ValueRangeInfo = Comparer==null ? null : Comparer.ValueRangeInfo; + Compare = Comparer?.Compare; + Equals = Comparer?.Equals; + GetHashCode = Comparer?.GetHashCode; + GetNearestValue = Comparer?.GetNearestValue; + ValueRangeInfo = Comparer?.ValueRangeInfo; } /// @@ -107,11 +107,11 @@ private AdvancedComparerStruct(AdvancedComparer comparer) private AdvancedComparerStruct(SerializationInfo info, StreamingContext context) { Comparer = (AdvancedComparer)info.GetValue("Comparer", typeof(AdvancedComparer)); - Compare = Comparer==null ? null : Comparer.Compare; - Equals = Comparer==null ? null : Comparer.Equals; - GetHashCode = Comparer==null ? null : Comparer.GetHashCode; - GetNearestValue = Comparer==null ? null : Comparer.GetNearestValue; - ValueRangeInfo = Comparer==null ? null : Comparer.ValueRangeInfo; + Compare = Comparer?.Compare; + Equals = Comparer?.Equals; + GetHashCode = Comparer?.GetHashCode; + GetNearestValue = Comparer?.GetNearestValue; + ValueRangeInfo = Comparer?.ValueRangeInfo; } /// @@ -121,4 +121,4 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) info.AddValue("Comparer", Comparer); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Conversion/Biconverter.cs b/Orm/Xtensive.Orm/Conversion/Biconverter.cs index f72ac5f9a9..95ef28b949 100644 --- a/Orm/Xtensive.Orm/Conversion/Biconverter.cs +++ b/Orm/Xtensive.Orm/Conversion/Biconverter.cs @@ -15,7 +15,7 @@ namespace Xtensive.Conversion /// Type to convert from. /// Type to convert to. [Serializable] - public struct Biconverter : + public readonly struct Biconverter : IEquatable> { /// @@ -119,4 +119,4 @@ public Biconverter(IBiconverter biconverter) ConvertBackward = biconverter.ConvertBackward; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs b/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs index 57f88f1e93..08d478d87e 100644 --- a/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs +++ b/Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs @@ -8,8 +8,6 @@ using System.Diagnostics; using Xtensive.Comparison; - - namespace Xtensive.Core { /// @@ -19,7 +17,7 @@ namespace Xtensive.Core /// The of second value. [Serializable] [DebuggerDisplay("{First}, {Second}")] - public struct Pair : + public readonly struct Pair : IComparable>, IEquatable> { @@ -67,9 +65,7 @@ public override bool Equals(object obj) public override int GetHashCode() { unchecked { - int result = (First!=null ? First.GetHashCode() : 0); - result = (result * 397) ^ (Second!=null ? Second.GetHashCode() : 0); - return result; + return ((First?.GetHashCode() ?? 0) * 397) ^ (Second?.GetHashCode() ?? 0); } } @@ -117,4 +113,4 @@ public Pair(TFirst first, TSecond second) Second = second; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs b/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs index 7cc920bda3..0adbc871d4 100644 --- a/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs +++ b/Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs @@ -20,10 +20,10 @@ public abstract class ExpressionVisitor : ExpressionVisitor protected override ReadOnlyCollection VisitExpressionList(ReadOnlyCollection expressions) { bool isChanged = false; - var results = new List(); + var results = new List(expressions.Count); for (int i = 0, n = expressions.Count; i < n; i++) { var expression = expressions[i]; - Expression p = Visit(expression); + var p = Visit(expression); results.Add(p); isChanged |= !ReferenceEquals(expression, p); } @@ -282,4 +282,4 @@ protected ExpressionVisitor(bool isCaching) { } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs b/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs index df6c9a114f..d93cba9123 100644 --- a/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs +++ b/Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs @@ -141,9 +141,9 @@ protected virtual TResult Visit(Expression e) /// Visit result. protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection expressions) { - var results = new List(); + var results = new List(expressions.Count); for (int i = 0, n = expressions.Count; i < n; i++) { - TResult p = Visit(expressions[i]); + var p = Visit(expressions[i]); results.Add(p); } return results.AsReadOnly(); @@ -281,4 +281,4 @@ protected ExpressionVisitor(bool isCaching) cache = new Dictionary(); } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs b/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs index d3b590ba48..d5bbbccc82 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/ColumnCollection.cs @@ -19,7 +19,7 @@ namespace Xtensive.Orm.Rse [Serializable] public sealed class ColumnCollection : ReadOnlyList { - private readonly Dictionary nameIndex = new Dictionary(); + private readonly Dictionary nameIndex; /// /// Gets by provided . @@ -37,9 +37,9 @@ public Column this[string fullName] { } } - private void Initialize() + private void BuildNameIndex() { - for (int index = 0; index < Count; index++) + for (var index = 0; index < Count; index++) nameIndex.Add(this[index].Name, index); } @@ -73,7 +73,8 @@ public ColumnCollection Alias(string alias) public ColumnCollection(IEnumerable collection) : base(collection.ToList()) { - Initialize(); + nameIndex = new Dictionary(Count); + BuildNameIndex(); } /// @@ -83,7 +84,8 @@ public ColumnCollection(IEnumerable collection) public ColumnCollection(List collection) : base(collection) { - Initialize(); + nameIndex = new Dictionary(Count); + BuildNameIndex(); } } } diff --git a/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs b/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs index cfc2631856..11c97f0f23 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs @@ -232,7 +232,7 @@ private static RecordSetHeader CreateHeader(IndexInfo indexInfo) var pkKeys = indexInfo.ReflectedType.Indexes.PrimaryIndex.KeyColumns; keyOrder.AddRange( indexInfo.ValueColumns - .Select((c, i) => new Pair(c, i + indexInfoKeyColumns.Count)) + .Select((c, i) => new Pair(c, i + indexInfoKeyColumns.Count)) .Where(pair => pair.First.IsPrimaryKey) .Select(pair => new KeyValuePair(pair.Second, pkKeys[pair.First]))); } From b0de0f75efffd2dfd177b5f1a76f4d9f0a0e15a9 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Fri, 13 Mar 2020 17:37:21 -0700 Subject: [PATCH 03/31] Convert PackedFieldDescriptor to struct and pass it by reference everywhere --- Orm/Xtensive.Orm/Tuples/AccessorDelegates.cs | 4 +- .../Tuples/Packed/PackedFieldAccessor.cs | 110 +++++++++--------- .../Packed/PackedFieldAccessorFactory.cs | 3 +- .../Tuples/Packed/PackedFieldDescriptor.cs | 2 +- Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs | 42 +++---- Orm/Xtensive.Orm/Tuples/Tuple.cs | 20 ++-- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 29 ++--- Orm/Xtensive.Orm/Tuples/TupleExtensions.cs | 12 +- 8 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/AccessorDelegates.cs b/Orm/Xtensive.Orm/Tuples/AccessorDelegates.cs index d9bb5c14d3..f90b6d6085 100644 --- a/Orm/Xtensive.Orm/Tuples/AccessorDelegates.cs +++ b/Orm/Xtensive.Orm/Tuples/AccessorDelegates.cs @@ -16,7 +16,7 @@ namespace Xtensive.Tuples /// Field descriptor. /// State of a field. /// - internal delegate TValue GetValueDelegate(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState); + internal delegate TValue GetValueDelegate(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState); /// /// Incapsulates method. @@ -25,5 +25,5 @@ namespace Xtensive.Tuples /// Tuple to use. /// Field descriptor. /// A value. - internal delegate void SetValueDelegate(PackedTuple tuple, PackedFieldDescriptor descriptor, TValue value); + internal delegate void SetValueDelegate(PackedTuple tuple, ref PackedFieldDescriptor descriptor, TValue value); } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index 491c90bc16..a7585983ce 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -30,76 +30,76 @@ internal abstract class PackedFieldAccessor /// protected Delegate NullableSetter; - public void SetValue(PackedTuple tuple, PackedFieldDescriptor descriptor, bool isNullable, T value) + public void SetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, T value) { var setter = (isNullable ? NullableSetter : Setter) as SetValueDelegate; if (setter!=null) - setter.Invoke(tuple, descriptor, value); + setter.Invoke(tuple, ref descriptor, value); else - SetUntypedValue(tuple, descriptor, value); + SetUntypedValue(tuple, ref descriptor, value); } - public T GetValue(PackedTuple tuple, PackedFieldDescriptor descriptor, bool isNullable, out TupleFieldState fieldState) + public T GetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, out TupleFieldState fieldState) { var getter = (isNullable ? NullableGetter : Getter) as GetValueDelegate; if (getter!=null) - return getter.Invoke(tuple, descriptor, out fieldState); + return getter.Invoke(tuple, ref descriptor, out fieldState); var targetType = typeof (T); //Dirty hack of nullable enum reading if (isNullable) targetType = Nullable.GetUnderlyingType(targetType) ?? targetType; if (targetType.IsEnum) - return (T) Enum.ToObject(targetType, GetUntypedValue(tuple, descriptor, out fieldState)); - return (T) GetUntypedValue(tuple, descriptor, out fieldState); + return (T) Enum.ToObject(targetType, GetUntypedValue(tuple, ref descriptor, out fieldState)); + return (T) GetUntypedValue(tuple, ref descriptor, out fieldState); } - public abstract object GetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState); + public abstract object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState); - public abstract void SetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, object value); + public abstract void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, object value); - public abstract void CopyValue(PackedTuple source, PackedFieldDescriptor sourceDescriptor, - PackedTuple target, PackedFieldDescriptor targetDescriptor); + public abstract void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, + PackedTuple target, ref PackedFieldDescriptor targetDescriptor); - public abstract bool ValueEquals(PackedTuple left, PackedFieldDescriptor leftDescriptor, - PackedTuple right, PackedFieldDescriptor rightDescriptor); + public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor, + PackedTuple right, ref PackedFieldDescriptor rightDescriptor); - public abstract int GetValueHashCode(PackedTuple tuple, PackedFieldDescriptor descriptor); + public abstract int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor); } internal sealed class ObjectFieldAccessor : PackedFieldAccessor { - public override object GetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState) + public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { - var state = tuple.GetFieldState(descriptor); + var state = tuple.GetFieldState(ref descriptor); fieldState = state; return state==TupleFieldState.Available ? tuple.Objects[descriptor.ValueIndex] : null; } - public override void SetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, object value) + public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, object value) { tuple.Objects[descriptor.ValueIndex] = value; if (value!=null) - tuple.SetFieldState(descriptor, TupleFieldState.Available); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available); else - tuple.SetFieldState(descriptor, TupleFieldState.Available | TupleFieldState.Null); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available | TupleFieldState.Null); } - public override void CopyValue(PackedTuple source, PackedFieldDescriptor sourceDescriptor, - PackedTuple target, PackedFieldDescriptor targetDescriptor) + public override void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, + PackedTuple target, ref PackedFieldDescriptor targetDescriptor) { target.Objects[targetDescriptor.ValueIndex] = source.Objects[sourceDescriptor.ValueIndex]; } - public override bool ValueEquals(PackedTuple left, PackedFieldDescriptor leftDescriptor, - PackedTuple right, PackedFieldDescriptor rightDescriptor) + public override bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor, + PackedTuple right, ref PackedFieldDescriptor rightDescriptor) { var leftValue = left.Objects[leftDescriptor.ValueIndex]; var rightValue = right.Objects[rightDescriptor.ValueIndex]; return leftValue.Equals(rightValue); } - public override int GetValueHashCode(PackedTuple tuple, PackedFieldDescriptor descriptor) + public override int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor) { return tuple.Objects[descriptor.ValueIndex].GetHashCode(); } @@ -157,73 +157,73 @@ protected virtual T Decode(long[] values, int offset) throw new NotSupportedException(); } - public override object GetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState) + public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { - var state = tuple.GetFieldState(descriptor); + var state = tuple.GetFieldState(ref descriptor); fieldState = state; - return state==TupleFieldState.Available ? (object) Load(tuple, descriptor) : null; + return state==TupleFieldState.Available ? (object) Load(tuple, ref descriptor) : null; } - public override void SetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, object value) + public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, object value) { if (value!=null) { - Store(tuple, descriptor, (T) value); - tuple.SetFieldState(descriptor, TupleFieldState.Available); + Store(tuple, ref descriptor, (T) value); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available); } else - tuple.SetFieldState(descriptor, TupleFieldState.Available | TupleFieldState.Null); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available | TupleFieldState.Null); } - public override void CopyValue(PackedTuple source, PackedFieldDescriptor sourceDescriptor, - PackedTuple target, PackedFieldDescriptor targetDescriptor) + public override void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, + PackedTuple target, ref PackedFieldDescriptor targetDescriptor) { - Store(target, targetDescriptor, Load(source, sourceDescriptor)); + Store(target, ref targetDescriptor, Load(source, ref sourceDescriptor)); } - public override bool ValueEquals(PackedTuple left, PackedFieldDescriptor leftDescriptor, - PackedTuple right, PackedFieldDescriptor rightDescriptor) + public override bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor, + PackedTuple right, ref PackedFieldDescriptor rightDescriptor) { - var leftValue = Load(left, leftDescriptor); - var rightValue = Load(right, rightDescriptor); + var leftValue = Load(left, ref leftDescriptor); + var rightValue = Load(right, ref rightDescriptor); return leftValue.Equals(rightValue); } - public override int GetValueHashCode(PackedTuple tuple, PackedFieldDescriptor descriptor) + public override int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor) { - return Load(tuple, descriptor).GetHashCode(); + return Load(tuple, ref descriptor).GetHashCode(); } - private T GetValue(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState) + private T GetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { - var state = tuple.GetFieldState(descriptor); + var state = tuple.GetFieldState(ref descriptor); fieldState = state; - return state==TupleFieldState.Available ? Load(tuple, descriptor) : DefaultValue; + return state==TupleFieldState.Available ? Load(tuple, ref descriptor) : DefaultValue; } - private T? GetNullableValue(PackedTuple tuple, PackedFieldDescriptor descriptor, out TupleFieldState fieldState) + private T? GetNullableValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { - var state = tuple.GetFieldState(descriptor); + var state = tuple.GetFieldState(ref descriptor); fieldState = state; - return state==TupleFieldState.Available ? Load(tuple, descriptor) : NullValue; + return state==TupleFieldState.Available ? Load(tuple, ref descriptor) : NullValue; } - private void SetValue(PackedTuple tuple, PackedFieldDescriptor descriptor, T value) + private void SetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, T value) { - Store(tuple, descriptor, value); - tuple.SetFieldState(descriptor, TupleFieldState.Available); + Store(tuple, ref descriptor, value); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available); } - private void SetNullableValue(PackedTuple tuple, PackedFieldDescriptor descriptor, T? value) + private void SetNullableValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, T? value) { if (value!=null) { - Store(tuple, descriptor, value.Value); - tuple.SetFieldState(descriptor, TupleFieldState.Available); + Store(tuple, ref descriptor, value.Value); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available); } else - tuple.SetFieldState(descriptor, TupleFieldState.Available | TupleFieldState.Null); + tuple.SetFieldState(ref descriptor, TupleFieldState.Available | TupleFieldState.Null); } - private void Store(PackedTuple tuple, PackedFieldDescriptor d, T value) + private void Store(PackedTuple tuple, ref PackedFieldDescriptor d, T value) { if (d.ValueBitCount > 64) { Encode(value, tuple.Values, d.ValueIndex); @@ -236,7 +236,7 @@ private void Store(PackedTuple tuple, PackedFieldDescriptor d, T value) tuple.Values[d.ValueIndex] = (block & ~mask) | ((encoded << d.ValueBitOffset) & mask); } - private T Load(PackedTuple tuple, PackedFieldDescriptor d) + private T Load(PackedTuple tuple, ref PackedFieldDescriptor d) { if (d.ValueBitCount > 64) return Decode(tuple.Values, d.ValueIndex); diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs index 4b2ac1a5ff..d6f95b5360 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs @@ -16,8 +16,9 @@ internal static class PackedFieldAccessorFactory public static IEnumerable KnownTypes => ValueAccessors.Keys; - public static void ConfigureDescriptor(PackedFieldDescriptor descriptor, Type accessorType) + public static void ConfigureDescriptor(ref PackedFieldDescriptor descriptor, int fieldIndex, Type accessorType) { + descriptor.FieldIndex = fieldIndex; if (ValueAccessors.TryGetValue(accessorType, out var valueAccessor)) { descriptor.Accessor = valueAccessor; descriptor.PackingType = FieldPackingType.Value; diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index ef5a5d5a7b..e4b2a2c6c0 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -9,7 +9,7 @@ namespace Xtensive.Tuples.Packed { [Serializable] - internal sealed class PackedFieldDescriptor + internal struct PackedFieldDescriptor { public FieldPackingType PackingType; diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs index 07ff1ae59f..4d0f1ab79c 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs @@ -43,16 +43,17 @@ public override bool Equals(Tuple other) if (Descriptor!=packedOther.Descriptor) return false; + var fieldDescriptors = PackedDescriptor.FieldDescriptors; var count = Count; for (int i = 0; i < count; i++) { - var descriptor = PackedDescriptor.FieldDescriptors[i]; - var thisState = GetFieldState(descriptor); - var otherState = packedOther.GetFieldState(descriptor); + var thisState = GetFieldState(ref fieldDescriptors[i]); + var otherState = packedOther.GetFieldState(ref fieldDescriptors[i]); if (thisState!=otherState) return false; if (thisState!=TupleFieldState.Available) continue; - if (!descriptor.Accessor.ValueEquals(this, descriptor, packedOther, descriptor)) + var accessor = fieldDescriptors[i].Accessor; + if (!accessor.ValueEquals(this, ref fieldDescriptors[i], packedOther, ref fieldDescriptors[i])) return false; } @@ -62,12 +63,13 @@ public override bool Equals(Tuple other) public override int GetHashCode() { var count = Count; + var fieldDescriptors = PackedDescriptor.FieldDescriptors; int result = 0; for (int i = 0; i < count; i++) { - var descriptor = PackedDescriptor.FieldDescriptors[i]; - var state = GetFieldState(descriptor); + var accessor = fieldDescriptors[i].Accessor; + var state = GetFieldState(ref fieldDescriptors[i]); var fieldHash = state==TupleFieldState.Available - ? descriptor.Accessor.GetValueHashCode(this, descriptor) + ? accessor.GetValueHashCode(this, ref fieldDescriptors[i]) : 0; result = HashCodeMultiplier * result ^ fieldHash; } @@ -76,8 +78,7 @@ public override int GetHashCode() public override TupleFieldState GetFieldState(int fieldIndex) { - var descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - return GetFieldState(descriptor); + return GetFieldState(ref PackedDescriptor.FieldDescriptors[fieldIndex]); } protected internal override void SetFieldState(int fieldIndex, TupleFieldState fieldState) @@ -85,33 +86,34 @@ protected internal override void SetFieldState(int fieldIndex, TupleFieldState f if (fieldState==TupleFieldState.Null) throw new ArgumentOutOfRangeException("fieldState"); - var descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - SetFieldState(descriptor, fieldState); - - if (fieldState!=TupleFieldState.Available && descriptor.PackingType==FieldPackingType.Object) - Objects[descriptor.ValueIndex] = null; + var fieldDescriptors = PackedDescriptor.FieldDescriptors; + SetFieldState(ref fieldDescriptors[fieldIndex], fieldState); } public override object GetValue(int fieldIndex, out TupleFieldState fieldState) { - var descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - return descriptor.Accessor.GetUntypedValue(this, descriptor, out fieldState); + var fieldDescriptors = PackedDescriptor.FieldDescriptors; + return fieldDescriptors[fieldIndex].Accessor.GetUntypedValue(this, ref fieldDescriptors[fieldIndex], out fieldState); } public override void SetValue(int fieldIndex, object fieldValue) { - var descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - descriptor.Accessor.SetUntypedValue(this, descriptor, fieldValue); + var fieldDescriptors = PackedDescriptor.FieldDescriptors; + fieldDescriptors[fieldIndex].Accessor.SetUntypedValue(this, ref fieldDescriptors[fieldIndex], fieldValue); } - public void SetFieldState(PackedFieldDescriptor d, TupleFieldState fieldState) + public void SetFieldState(ref PackedFieldDescriptor d, TupleFieldState fieldState) { var bits = (long) fieldState; var block = Values[d.StateIndex]; Values[d.StateIndex] = (block & ~(3L << d.StateBitOffset)) | (bits << d.StateBitOffset); + + if (fieldState!=TupleFieldState.Available && d.PackingType==FieldPackingType.Object) { + Objects[d.ValueIndex] = null; + } } - public TupleFieldState GetFieldState(PackedFieldDescriptor d) + public TupleFieldState GetFieldState(ref PackedFieldDescriptor d) { var block = Values[d.StateIndex]; return (TupleFieldState) ((block >> d.StateBitOffset) & 3); diff --git a/Orm/Xtensive.Orm/Tuples/Tuple.cs b/Orm/Xtensive.Orm/Tuples/Tuple.cs index 7d256b04f0..662aaaa183 100644 --- a/Orm/Xtensive.Orm/Tuples/Tuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Tuple.cs @@ -111,17 +111,15 @@ public T GetValue(int fieldIndex, out TupleFieldState fieldState) { var isNullable = null==default(T); // Is nullable value type or class - var packedTuple = this as PackedTuple; - if (packedTuple!=null) { + if (this is PackedTuple packedTuple) { var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; - return descriptor.Accessor.GetValue(packedTuple, descriptor, isNullable, out fieldState); + return descriptor.Accessor.GetValue(packedTuple, ref descriptor, isNullable, out fieldState); } var mappedContainer = GetMappedContainer(fieldIndex, false); - var mappedTuple = mappedContainer.First as PackedTuple; - if (mappedTuple!=null) { + if (mappedContainer.First is PackedTuple mappedTuple) { var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; - return descriptor.Accessor.GetValue(mappedTuple, descriptor, isNullable, out fieldState); + return descriptor.Accessor.GetValue(mappedTuple, ref descriptor, isNullable, out fieldState); } var value = GetValue(fieldIndex, out fieldState); @@ -187,19 +185,17 @@ public T GetValueOrDefault(int fieldIndex) public void SetValue(int fieldIndex, T fieldValue) { var isNullable = null==default(T); // Is nullable value type or class - var packedTuple = this as PackedTuple; - if (packedTuple!=null) { + if (this is PackedTuple packedTuple) { var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; - descriptor.Accessor.SetValue(packedTuple, descriptor, isNullable, fieldValue); + descriptor.Accessor.SetValue(packedTuple, ref descriptor, isNullable, fieldValue); return; } var mappedContainer = GetMappedContainer(fieldIndex, true); - var mappedTuple = mappedContainer.First as PackedTuple; - if (mappedTuple!=null) { + if (mappedContainer.First is PackedTuple mappedTuple) { var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; - descriptor.Accessor.SetValue(mappedTuple, descriptor, isNullable, fieldValue); + descriptor.Accessor.SetValue(mappedTuple, ref descriptor, isNullable, fieldValue); return; } diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index b37d3f0b52..57e0459e73 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -424,10 +424,8 @@ private TupleDescriptor(Type[] fieldTypes) for (var i = 0; i < fieldTypes.Length; i++) { var fieldType = fieldTypes[i].StripNullable(); - var descriptor = new PackedFieldDescriptor { FieldIndex = i }; - PackedFieldAccessorFactory.ConfigureDescriptor(descriptor, fieldType); + PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[i], i, fieldType); _fieldTypes[i] = fieldType; - FieldDescriptors[i] = descriptor; } var orderedDescriptors = (PackedFieldDescriptor[]) FieldDescriptors.Clone(); @@ -435,11 +433,11 @@ private TupleDescriptor(Type[] fieldTypes) foreach (var d in orderedDescriptors) { var fieldIndex = d.FieldIndex; - d.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 - d.StateBitOffset = (fieldIndex & 31) << 1; + FieldDescriptors[fieldIndex].StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 + FieldDescriptors[fieldIndex].StateBitOffset = (fieldIndex & 31) << 1; if (d.PackingType == FieldPackingType.Object) { - d.ValueIndex = objectIndex++; + FieldDescriptors[fieldIndex].ValueIndex = objectIndex++; continue; } @@ -449,16 +447,16 @@ private TupleDescriptor(Type[] fieldTypes) valueIndex++; valueBitOffset = 0; } - d.ValueIndex = valueIndex; + FieldDescriptors[fieldIndex].ValueIndex = valueIndex; valueIndex += (d.ValueBitCount + longBitCount - 1) / longBitCount; } else { - d.ValueIndex = valueIndex; - d.ValueBitOffset = valueBitOffset; + FieldDescriptors[fieldIndex].ValueIndex = valueIndex; + FieldDescriptors[fieldIndex].ValueBitOffset = valueBitOffset; valueBitOffset += d.ValueBitCount; if (valueBitOffset > longBitCount) { - d.ValueIndex = ++valueIndex; - d.ValueBitOffset = 0; + FieldDescriptors[fieldIndex].ValueIndex = ++valueIndex; + FieldDescriptors[fieldIndex].ValueBitOffset = 0; valueBitOffset = d.ValueBitCount; } } @@ -479,10 +477,13 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) "FieldDescriptors", typeof(PackedFieldDescriptor[])); _fieldTypes = new Type[typeNames.Length]; - for (var i = 0; i < typeNames.Length; i++) + for (var i = 0; i < typeNames.Length; i++) { _fieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); - for (var i = 0; i < _fieldTypes.Length; i++) - PackedFieldAccessorFactory.ConfigureDescriptor(FieldDescriptors[i], _fieldTypes[i]); + } + + for (var i = 0; i < _fieldTypes.Length; i++) { + PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[i], i, _fieldTypes[i]); + } } diff --git a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs index 8183c72c36..33bb483fc0 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs @@ -437,10 +437,10 @@ private static void CopyValue(Tuple source, int sourceIndex, Tuple target, int t private static void CopyPackedValue(PackedTuple source, int sourceIndex, PackedTuple target, int targetIndex) { - var sourceDescriptor = source.PackedDescriptor.FieldDescriptors[sourceIndex]; - var targetDescriptor = target.PackedDescriptor.FieldDescriptors[targetIndex]; + var sourceDescriptors = source.PackedDescriptor.FieldDescriptors; + var targetDescriptors = target.PackedDescriptor.FieldDescriptors; - var fieldState = source.GetFieldState(sourceDescriptor); + var fieldState = source.GetFieldState(ref sourceDescriptors[sourceIndex]); if (!fieldState.IsAvailable()) return; @@ -449,15 +449,15 @@ private static void CopyPackedValue(PackedTuple source, int sourceIndex, PackedT return; } - var accessor = sourceDescriptor.Accessor; - if (accessor!=targetDescriptor.Accessor) + var accessor = sourceDescriptors[sourceIndex].Accessor; + if (accessor!=targetDescriptors[targetIndex].Accessor) throw new InvalidOperationException(string.Format( Strings.ExInvalidCast, source.PackedDescriptor[sourceIndex], target.PackedDescriptor[targetIndex])); target.SetFieldState(targetIndex, TupleFieldState.Available); - accessor.CopyValue(source, sourceDescriptor, target, targetDescriptor); + accessor.CopyValue(source, ref sourceDescriptors[sourceIndex], target, ref targetDescriptors[targetIndex]); } private static void PartiallyCopyTupleSlow(Tuple source, Tuple target, int sourceStartIndex, int targetStartIndex, int length) From ac415e5ea9e1f668948c59609a7b0a6baf34997c Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 16 Mar 2020 16:01:23 -0700 Subject: [PATCH 04/31] Use lightweight data type while sorting FieldDescriptors. Get rid of StripNullable call. --- .../Tuples/Packed/PackedFieldAccessor.cs | 6 +++++ .../Packed/PackedFieldAccessorFactory.cs | 11 +++++--- .../Packed/PackedFieldDescriptorComparer.cs | 18 ------------- .../Tuples/Packed/PackingOrderInfoComparer.cs | 25 +++++++++++++++++++ Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 21 ++++++++-------- Orm/Xtensive.Orm/Xtensive.Orm.csproj | 2 +- 6 files changed, 51 insertions(+), 32 deletions(-) delete mode 100644 Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs create mode 100644 Orm/Xtensive.Orm/Tuples/Packed/PackingOrderInfoComparer.cs diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index a7585983ce..f076b2e25c 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -30,6 +30,8 @@ internal abstract class PackedFieldAccessor /// protected Delegate NullableSetter; + public abstract Type FieldType { get; } + public void SetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, T value) { var setter = (isNullable ? NullableSetter : Setter) as SetValueDelegate; @@ -69,6 +71,8 @@ public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor lef internal sealed class ObjectFieldAccessor : PackedFieldAccessor { + public override Type FieldType => null; + public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { var state = tuple.GetFieldState(ref descriptor); @@ -137,6 +141,8 @@ internal abstract class ValueFieldAccessor : ValueFieldAccessor private static readonly T DefaultValue = default(T); private static readonly T? NullValue = null; + public override Type FieldType => typeof(T); + protected virtual long Encode(T value) { throw new NotSupportedException(); diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs index d6f95b5360..ed7fd9c7d2 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Xtensive.Tuples.Packed { @@ -14,12 +15,12 @@ internal static class PackedFieldAccessorFactory private static readonly PackedFieldAccessor ObjectAccessor; private static readonly Dictionary ValueAccessors; - public static IEnumerable KnownTypes => ValueAccessors.Keys; + public static IEnumerable KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType); - public static void ConfigureDescriptor(ref PackedFieldDescriptor descriptor, int fieldIndex, Type accessorType) + public static void ConfigureDescriptor(ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) { descriptor.FieldIndex = fieldIndex; - if (ValueAccessors.TryGetValue(accessorType, out var valueAccessor)) { + if (ValueAccessors.TryGetValue(fieldType, out var valueAccessor)) { descriptor.Accessor = valueAccessor; descriptor.PackingType = FieldPackingType.Value; descriptor.ValueBitCount = valueAccessor.BitCount; @@ -29,12 +30,16 @@ public static void ConfigureDescriptor(ref PackedFieldDescriptor descriptor, int descriptor.Accessor = ObjectAccessor; descriptor.PackingType = FieldPackingType.Object; } + + descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 + descriptor.StateBitOffset = (fieldIndex & 31) << 1; } private static void RegisterAccessor(ValueFieldAccessor accessor) where T : struct, IEquatable { ValueAccessors.Add(typeof (T), accessor); + ValueAccessors.Add(typeof (T?), accessor); } static PackedFieldAccessorFactory() diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs deleted file mode 100644 index 4ddf05b233..0000000000 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptorComparer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Xtensive.Tuples.Packed -{ - internal class PackedFieldDescriptorComparer : IComparer - { - public static readonly PackedFieldDescriptorComparer Instance = - new PackedFieldDescriptorComparer(); - - public int Compare(PackedFieldDescriptor x, PackedFieldDescriptor y) - { - var t = y.ValueBitCount - x.ValueBitCount; - if (t != 0) - return t; - return x.FieldIndex - y.FieldIndex; - } - } -} diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackingOrderInfoComparer.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackingOrderInfoComparer.cs new file mode 100644 index 0000000000..d283fa272b --- /dev/null +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackingOrderInfoComparer.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Xtensive.Tuples.Packed +{ + + internal struct PackingOrderInfo + { + public int FieldIndex; + public int ValueBitCount; + } + + internal class PackingOrderInfoComparer : IComparer + { + public static readonly PackingOrderInfoComparer Instance = + new PackingOrderInfoComparer(); + + public int Compare(PackingOrderInfo x, PackingOrderInfo y) + { + var bitCountDiff = y.ValueBitCount - x.ValueBitCount; + return bitCountDiff != 0 + ? bitCountDiff + : x.FieldIndex - y.FieldIndex; + } + } +} diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 57e0459e73..862dffd316 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -422,19 +422,20 @@ private TupleDescriptor(Type[] fieldTypes) var valueIndex = (FieldCount + statesPerLong - 1) / statesPerLong; var valueBitOffset = 0; - for (var i = 0; i < fieldTypes.Length; i++) { - var fieldType = fieldTypes[i].StripNullable(); - PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[i], i, fieldType); - _fieldTypes[i] = fieldType; + var packingOrderInfos = new PackingOrderInfo[fieldTypes.Length]; + for (var fieldIndex = 0; fieldIndex < fieldTypes.Length; fieldIndex++) { + var fieldType = fieldTypes[fieldIndex]; + PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[fieldIndex], fieldIndex, fieldType); + packingOrderInfos[fieldIndex].FieldIndex = fieldIndex; + packingOrderInfos[fieldIndex].ValueBitCount = FieldDescriptors[fieldIndex].ValueBitCount; + _fieldTypes[fieldIndex] = FieldDescriptors[fieldIndex].Accessor.FieldType ?? fieldType; } - var orderedDescriptors = (PackedFieldDescriptor[]) FieldDescriptors.Clone(); - Array.Sort(orderedDescriptors, PackedFieldDescriptorComparer.Instance); + Array.Sort(packingOrderInfos, PackingOrderInfoComparer.Instance); - foreach (var d in orderedDescriptors) { - var fieldIndex = d.FieldIndex; - FieldDescriptors[fieldIndex].StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 - FieldDescriptors[fieldIndex].StateBitOffset = (fieldIndex & 31) << 1; + foreach (var info in packingOrderInfos) { + var fieldIndex = info.FieldIndex; + var d = FieldDescriptors[fieldIndex]; if (d.PackingType == FieldPackingType.Object) { FieldDescriptors[fieldIndex].ValueIndex = objectIndex++; diff --git a/Orm/Xtensive.Orm/Xtensive.Orm.csproj b/Orm/Xtensive.Orm/Xtensive.Orm.csproj index 3e3a26050a..da76472f56 100644 --- a/Orm/Xtensive.Orm/Xtensive.Orm.csproj +++ b/Orm/Xtensive.Orm/Xtensive.Orm.csproj @@ -32,7 +32,7 @@ - + From 66824b70619e44f194f2a6430dee11fd62eed311 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Tue, 17 Mar 2020 21:54:17 -0700 Subject: [PATCH 05/31] No Array.Sort() method call in TupleDescriptor's constructor --- .../Tuples/Packed/PackedFieldAccessor.cs | 60 +++----- .../Packed/PackedFieldAccessorFactory.cs | 130 ++++++++++++++++-- .../Tuples/Packed/PackedFieldDescriptor.cs | 53 +++++-- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 87 ++++++------ 4 files changed, 224 insertions(+), 106 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index f076b2e25c..8d27a603a6 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -30,8 +30,6 @@ internal abstract class PackedFieldAccessor /// protected Delegate NullableSetter; - public abstract Type FieldType { get; } - public void SetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, T value) { var setter = (isNullable ? NullableSetter : Setter) as SetValueDelegate; @@ -71,8 +69,6 @@ public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor lef internal sealed class ObjectFieldAccessor : PackedFieldAccessor { - public override Type FieldType => null; - public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { var state = tuple.GetFieldState(ref descriptor); @@ -111,57 +107,41 @@ public override int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescripto internal abstract class ValueFieldAccessor : PackedFieldAccessor { - public readonly int BitCount; - public readonly long BitMask; + public readonly int Rank; - private static long GetMask(int bits) - { - long result = 0; + public abstract Type FieldType { get; } - for (int i = 0; i < bits; i++) { - result <<= 1; - result |= 1; + private static int GetRank(int bitSize) + { + var rank = 0; + while ((bitSize >>= 1) > 0) { + rank++; } - return result; + return rank; } - protected ValueFieldAccessor(int bits) + protected ValueFieldAccessor(int bitCount) { - BitCount = bits; - - if (bits <= 64) - BitMask = GetMask(bits); + Rank = GetRank(bitCount); } } internal abstract class ValueFieldAccessor : ValueFieldAccessor where T : struct, IEquatable { - private static readonly T DefaultValue = default(T); + private static readonly T DefaultValue = default; private static readonly T? NullValue = null; - public override Type FieldType => typeof(T); + public override Type FieldType { get; } = typeof(T); - protected virtual long Encode(T value) - { - throw new NotSupportedException(); - } + protected virtual long Encode(T value) => throw new NotSupportedException(); - protected virtual void Encode(T value, long[] values, int offset) - { - throw new NotSupportedException(); - } + protected virtual void Encode(T value, long[] values, int offset) => throw new NotSupportedException(); - protected virtual T Decode(long value) - { - throw new NotSupportedException(); - } + protected virtual T Decode(long value) => throw new NotSupportedException(); - protected virtual T Decode(long[] values, int offset) - { - throw new NotSupportedException(); - } + protected virtual T Decode(long[] values, int offset) => throw new NotSupportedException(); public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, out TupleFieldState fieldState) { @@ -176,8 +156,9 @@ public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescripto Store(tuple, ref descriptor, (T) value); tuple.SetFieldState(ref descriptor, TupleFieldState.Available); } - else + else { tuple.SetFieldState(ref descriptor, TupleFieldState.Available | TupleFieldState.Null); + } } public override void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, @@ -231,7 +212,7 @@ private void SetNullableValue(PackedTuple tuple, ref PackedFieldDescriptor descr private void Store(PackedTuple tuple, ref PackedFieldDescriptor d, T value) { - if (d.ValueBitCount > 64) { + if (Rank > 6) { Encode(value, tuple.Values, d.ValueIndex); return; } @@ -244,8 +225,9 @@ private void Store(PackedTuple tuple, ref PackedFieldDescriptor d, T value) private T Load(PackedTuple tuple, ref PackedFieldDescriptor d) { - if (d.ValueBitCount > 64) + if (Rank > 6) { return Decode(tuple.Values, d.ValueIndex); + } var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & d.ValueBitMask; return Decode(encoded); diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs index ed7fd9c7d2..7bb0f8d65d 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs @@ -10,29 +10,123 @@ namespace Xtensive.Tuples.Packed { + internal ref struct ValPointers + { + public ValPointer Val001Pointer; + public ValPointer Val008Pointer; + public ValPointer Val016Pointer; + public ValPointer Val032Pointer; + public ValPointer Val064Pointer; + public ValPointer Val128Pointer; + } + + internal ref struct ValPointer + { + public int Index; + public int Offset; + } + + internal ref struct ValCounters + { + public int ObjectCounter; + + public int Val001Counter; + public int Val008Counter; + public int Val016Counter; + public int Val032Counter; + public int Val064Counter; + public int Val128Counter; + } + internal static class PackedFieldAccessorFactory { - private static readonly PackedFieldAccessor ObjectAccessor; + private delegate int CounterIncrementer(ref ValCounters valCounters); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); + + private static readonly CounterIncrementer[] incrementers = { + (ref ValCounters valueCounters) => valueCounters.Val001Counter++, + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => valueCounters.Val008Counter++, + (ref ValCounters valueCounters) => valueCounters.Val016Counter++, + (ref ValCounters valueCounters) => valueCounters.Val032Counter++, + (ref ValCounters valueCounters) => valueCounters.Val064Counter++, + (ref ValCounters valueCounters) => valueCounters.Val128Counter++ + }; + + private static readonly PositionUpdater[] positionUpdaters = { + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) + }; + + private const int Val064Rank = 6; + + private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) + { + const int remainderBitMask = (1 << Val064Rank) - 1; + + var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; + + descriptor.ValueIndex = valPointer.Index; + descriptor.ValueBitOffset = valPointer.Offset; + + valPointer.Index += increasedOffset >> Val064Rank; + valPointer.Offset = increasedOffset & remainderBitMask; + } + + private static readonly ObjectFieldAccessor ObjectAccessor; private static readonly Dictionary ValueAccessors; public static IEnumerable KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType); - public static void ConfigureDescriptor(ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) + public static void SetAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => + descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) + ? (PackedFieldAccessor) valueAccessor + : ObjectAccessor; + + public static Type ConfigureDescriptorPhase1(ref ValCounters counters, ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) { - descriptor.FieldIndex = fieldIndex; + descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 + descriptor.StateBitOffset = (fieldIndex & 31) << 1; + if (ValueAccessors.TryGetValue(fieldType, out var valueAccessor)) { - descriptor.Accessor = valueAccessor; - descriptor.PackingType = FieldPackingType.Value; - descriptor.ValueBitCount = valueAccessor.BitCount; - descriptor.ValueBitMask = valueAccessor.BitMask; - } - else { - descriptor.Accessor = ObjectAccessor; - descriptor.PackingType = FieldPackingType.Object; + ConfigureValueDescriptor(ref descriptor, ref counters, valueAccessor); + return valueAccessor.FieldType; } - descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 - descriptor.StateBitOffset = (fieldIndex & 31) << 1; + ConfigureObjectDescriptor(ref descriptor, ref counters, ObjectAccessor); + return fieldType; + } + + private static void ConfigureObjectDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + ObjectFieldAccessor objectAccessor) + { + descriptor.Accessor = objectAccessor; + descriptor.PackingType = FieldPackingType.Object; + descriptor.ValueIndex = counters.ObjectCounter++; + } + + private static void ConfigureValueDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + ValueFieldAccessor valueAccessor) + { + descriptor.Accessor = valueAccessor; + descriptor.PackingType = FieldPackingType.Value; + descriptor.Rank = valueAccessor.Rank; + descriptor.ValueIndex = incrementers[valueAccessor.Rank].Invoke(ref counters); } private static void RegisterAccessor(ValueFieldAccessor accessor) @@ -62,5 +156,15 @@ static PackedFieldAccessorFactory() RegisterAccessor(new DecimalFieldAccessor()); RegisterAccessor(new GuidFieldAccessor()); } + + public static void ConfigureDescriptorPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + { + if (descriptor.PackingType == FieldPackingType.Object) { + return; + } + + // d.PackingType == FieldPackingType.Value + positionUpdaters[descriptor.Rank].Invoke(ref descriptor, ref valPointers); + } } } diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index e4b2a2c6c0..0806a15870 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -11,20 +11,57 @@ namespace Xtensive.Tuples.Packed [Serializable] internal struct PackedFieldDescriptor { - public FieldPackingType PackingType; + private const int IndexBitCount = 20; + private const int IndexMask = (1 << IndexBitCount) - 1; + private const int OffsetBitCount = 7; + private const int OffsetMask = ((1 << OffsetBitCount) - 1) << IndexBitCount; + private const int MaskBitCount = (sizeof(int) * 8) - (IndexBitCount + OffsetBitCount); + private const int Mask = ((1 << MaskBitCount) - 1) << (IndexBitCount + OffsetBitCount); + + private int data1; + private int data2; [NonSerialized] public PackedFieldAccessor Accessor; - public int FieldIndex; + public int ValueIndex + { + get => data1 & IndexMask; + set => data1 = (data1 & ~IndexMask) | (value & IndexMask); + } + + public int ValueBitOffset + { + get => (data1 & OffsetMask) >> IndexBitCount; + set => data1 = (data1 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask); + } + + public int Rank + { + get => (data1 & Mask) >> (IndexBitCount + OffsetBitCount); + set => data1 = (data1 & ~Mask) | ((value << (IndexBitCount + OffsetBitCount)) & Mask); + } + + public int ValueBitCount => 1 << Rank; + + public long ValueBitMask => (1L << (ValueBitCount - 1) << 1) - 1; - public int ValueIndex; - public int ValueBitOffset; - public int ValueBitCount; + public int StateIndex + { + get => data2 & IndexMask; + set => data2 = (data2 & ~IndexMask) | (value & IndexMask); + } - public long ValueBitMask; + public int StateBitOffset + { + get => (data2 & OffsetMask) >> IndexBitCount; + set => data2 = (data2 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask); + } - public int StateIndex; - public int StateBitOffset; + public FieldPackingType PackingType + { + get => (FieldPackingType)((data2 & Mask) >> (IndexBitCount + OffsetBitCount)); + set => data2 = (data2 & ~Mask) | (((int)value << (IndexBitCount + OffsetBitCount)) & Mask); + } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 862dffd316..038546f01f 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using Xtensive.Core; @@ -406,6 +407,23 @@ public static TupleDescriptor Create() // Constructors + private const int Val128Rank = 7; + private const int Val064Rank = 6; + private const int Val032Rank = 5; + private const int Val016Rank = 4; + private const int Val008Rank = 3; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void InitValPointer( + ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) + { + const int remainderBitMask = (1 << Val064Rank) - 1; + var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; + + pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); + pointer.Offset = prevBitCountWithOffset & remainderBitMask; + } + private TupleDescriptor(Type[] fieldTypes) { ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); @@ -414,57 +432,34 @@ private TupleDescriptor(Type[] fieldTypes) FieldCount = fieldTypes.Length; FieldDescriptors = new PackedFieldDescriptor[FieldCount]; - const int longBitCount = 64; + var valCounters = new ValCounters(); + for (var fieldIndex = 0; fieldIndex < FieldCount; fieldIndex++) { + _fieldTypes[fieldIndex] = PackedFieldAccessorFactory.ConfigureDescriptorPhase1( + ref valCounters, ref FieldDescriptors[fieldIndex], fieldIndex, fieldTypes[fieldIndex]); + } + + const int longBitCount = 1 << Val064Rank; const int stateBitCount = 2; const int statesPerLong = longBitCount / stateBitCount; - var objectIndex = 0; var valueIndex = (FieldCount + statesPerLong - 1) / statesPerLong; - var valueBitOffset = 0; - - var packingOrderInfos = new PackingOrderInfo[fieldTypes.Length]; - for (var fieldIndex = 0; fieldIndex < fieldTypes.Length; fieldIndex++) { - var fieldType = fieldTypes[fieldIndex]; - PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[fieldIndex], fieldIndex, fieldType); - packingOrderInfos[fieldIndex].FieldIndex = fieldIndex; - packingOrderInfos[fieldIndex].ValueBitCount = FieldDescriptors[fieldIndex].ValueBitCount; - _fieldTypes[fieldIndex] = FieldDescriptors[fieldIndex].Accessor.FieldType ?? fieldType; - } - Array.Sort(packingOrderInfos, PackingOrderInfoComparer.Instance); - - foreach (var info in packingOrderInfos) { - var fieldIndex = info.FieldIndex; - var d = FieldDescriptors[fieldIndex]; - - if (d.PackingType == FieldPackingType.Object) { - FieldDescriptors[fieldIndex].ValueIndex = objectIndex++; - continue; - } - - // d.PackingType == FieldPackingType.Value - if (d.ValueBitCount >= longBitCount) { - if (valueBitOffset != 0) { - valueIndex++; - valueBitOffset = 0; - } - FieldDescriptors[fieldIndex].ValueIndex = valueIndex; - valueIndex += (d.ValueBitCount + longBitCount - 1) / longBitCount; - } - else { - FieldDescriptors[fieldIndex].ValueIndex = valueIndex; - FieldDescriptors[fieldIndex].ValueBitOffset = valueBitOffset; - valueBitOffset += d.ValueBitCount; - if (valueBitOffset > longBitCount) { - FieldDescriptors[fieldIndex].ValueIndex = ++valueIndex; - FieldDescriptors[fieldIndex].ValueBitOffset = 0; - valueBitOffset = d.ValueBitCount; - } - } + var valPointers = new ValPointers { + Val128Pointer = new ValPointer {Index = valueIndex, Offset = 0} + }; + InitValPointer(ref valPointers.Val064Pointer, ref valPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); + InitValPointer(ref valPointers.Val032Pointer, ref valPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); + InitValPointer(ref valPointers.Val016Pointer, ref valPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); + InitValPointer(ref valPointers.Val008Pointer, ref valPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); + InitValPointer(ref valPointers.Val001Pointer, ref valPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); + + ValuesLength = valPointers.Val001Pointer.Index + + ((valCounters.Val001Counter + valPointers.Val001Pointer.Offset) >> Val064Rank) + 1; + ObjectsLength = valCounters.ObjectCounter; + + for (var fieldIndex = 0; fieldIndex < FieldCount; fieldIndex++) { + PackedFieldAccessorFactory.ConfigureDescriptorPhase2(ref FieldDescriptors[fieldIndex], ref valPointers); } - - ValuesLength = valueIndex + Math.Min(1, valueBitOffset); - ObjectsLength = objectIndex; } public TupleDescriptor(SerializationInfo info, StreamingContext context) @@ -483,7 +478,7 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) } for (var i = 0; i < _fieldTypes.Length; i++) { - PackedFieldAccessorFactory.ConfigureDescriptor(ref FieldDescriptors[i], i, _fieldTypes[i]); + PackedFieldAccessorFactory.SetAccessor(ref FieldDescriptors[i], _fieldTypes[i]); } } From d06056d745060d4aa560c2cb89d0acf7f8f3925a Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 18 Mar 2020 00:09:23 -0700 Subject: [PATCH 06/31] Precise calculation of ValuesLength property --- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 038546f01f..31d80c9487 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -412,6 +412,7 @@ public static TupleDescriptor Create() private const int Val032Rank = 5; private const int Val016Rank = 4; private const int Val008Rank = 3; + private const int Val001Rank = 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void InitValPointer( @@ -442,7 +443,7 @@ private TupleDescriptor(Type[] fieldTypes) const int stateBitCount = 2; const int statesPerLong = longBitCount / stateBitCount; - var valueIndex = (FieldCount + statesPerLong - 1) / statesPerLong; + var valueIndex = (FieldCount + (statesPerLong - 1)) / statesPerLong; var valPointers = new ValPointers { Val128Pointer = new ValPointer {Index = valueIndex, Offset = 0} @@ -453,8 +454,10 @@ private TupleDescriptor(Type[] fieldTypes) InitValPointer(ref valPointers.Val008Pointer, ref valPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); InitValPointer(ref valPointers.Val001Pointer, ref valPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); - ValuesLength = valPointers.Val001Pointer.Index - + ((valCounters.Val001Counter + valPointers.Val001Pointer.Offset) >> Val064Rank) + 1; + var valuesEndPointer = new ValPointer(); + InitValPointer(ref valuesEndPointer, ref valPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); + ValuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> 31) + 1; + ObjectsLength = valCounters.ObjectCounter; for (var fieldIndex = 0; fieldIndex < FieldCount; fieldIndex++) { From af7eb9297688946b0f652e4e21904346e78aa627 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 18 Mar 2020 13:23:15 -0700 Subject: [PATCH 07/31] Move all packed field layout configuration code to TupleLayout class --- ...FieldAccessorFactory.cs => TupleLayout.cs} | 393 ++++++++++-------- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 70 +--- 2 files changed, 231 insertions(+), 232 deletions(-) rename Orm/Xtensive.Orm/Tuples/Packed/{PackedFieldAccessorFactory.cs => TupleLayout.cs} (70%) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs similarity index 70% rename from Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs rename to Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 7bb0f8d65d..bcaa5d9aca 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -1,170 +1,223 @@ -// Copyright (C) 2003-2012 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. -// Created by: Denis Krjuchkov -// Created: 2012.12.29 - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Xtensive.Tuples.Packed -{ - internal ref struct ValPointers - { - public ValPointer Val001Pointer; - public ValPointer Val008Pointer; - public ValPointer Val016Pointer; - public ValPointer Val032Pointer; - public ValPointer Val064Pointer; - public ValPointer Val128Pointer; - } - - internal ref struct ValPointer - { - public int Index; - public int Offset; - } - - internal ref struct ValCounters - { - public int ObjectCounter; - - public int Val001Counter; - public int Val008Counter; - public int Val016Counter; - public int Val032Counter; - public int Val064Counter; - public int Val128Counter; - } - - internal static class PackedFieldAccessorFactory - { - private delegate int CounterIncrementer(ref ValCounters valCounters); - private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); - - private static readonly CounterIncrementer[] incrementers = { - (ref ValCounters valueCounters) => valueCounters.Val001Counter++, - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => valueCounters.Val008Counter++, - (ref ValCounters valueCounters) => valueCounters.Val016Counter++, - (ref ValCounters valueCounters) => valueCounters.Val032Counter++, - (ref ValCounters valueCounters) => valueCounters.Val064Counter++, - (ref ValCounters valueCounters) => valueCounters.Val128Counter++ - }; - - private static readonly PositionUpdater[] positionUpdaters = { - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) - }; - - private const int Val064Rank = 6; - - private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) - { - const int remainderBitMask = (1 << Val064Rank) - 1; - - var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; - - descriptor.ValueIndex = valPointer.Index; - descriptor.ValueBitOffset = valPointer.Offset; - - valPointer.Index += increasedOffset >> Val064Rank; - valPointer.Offset = increasedOffset & remainderBitMask; - } - - private static readonly ObjectFieldAccessor ObjectAccessor; - private static readonly Dictionary ValueAccessors; - - public static IEnumerable KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType); - - public static void SetAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => - descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) - ? (PackedFieldAccessor) valueAccessor - : ObjectAccessor; - - public static Type ConfigureDescriptorPhase1(ref ValCounters counters, ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) - { - descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 - descriptor.StateBitOffset = (fieldIndex & 31) << 1; - - if (ValueAccessors.TryGetValue(fieldType, out var valueAccessor)) { - ConfigureValueDescriptor(ref descriptor, ref counters, valueAccessor); - return valueAccessor.FieldType; - } - - ConfigureObjectDescriptor(ref descriptor, ref counters, ObjectAccessor); - return fieldType; - } - - private static void ConfigureObjectDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, - ObjectFieldAccessor objectAccessor) - { - descriptor.Accessor = objectAccessor; - descriptor.PackingType = FieldPackingType.Object; - descriptor.ValueIndex = counters.ObjectCounter++; - } - - private static void ConfigureValueDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, - ValueFieldAccessor valueAccessor) - { - descriptor.Accessor = valueAccessor; - descriptor.PackingType = FieldPackingType.Value; - descriptor.Rank = valueAccessor.Rank; - descriptor.ValueIndex = incrementers[valueAccessor.Rank].Invoke(ref counters); - } - - private static void RegisterAccessor(ValueFieldAccessor accessor) - where T : struct, IEquatable - { - ValueAccessors.Add(typeof (T), accessor); - ValueAccessors.Add(typeof (T?), accessor); - } - - static PackedFieldAccessorFactory() - { - ObjectAccessor = new ObjectFieldAccessor(); - ValueAccessors = new Dictionary(); - RegisterAccessor(new BooleanFieldAccessor()); - RegisterAccessor(new ByteFieldAccessor()); - RegisterAccessor(new SByteFieldAccessor()); - RegisterAccessor(new ShortFieldAccessor()); - RegisterAccessor(new UShortFieldAccessor()); - RegisterAccessor(new IntFieldAccessor()); - RegisterAccessor(new UIntFieldAccessor()); - RegisterAccessor(new LongFieldAccessor()); - RegisterAccessor(new ULongFieldAccessor()); - RegisterAccessor(new FloatFieldAccessor()); - RegisterAccessor(new DoubleFieldAccessor()); - RegisterAccessor(new DateTimeFieldAccessor()); - RegisterAccessor(new TimeSpanFieldAccessor()); - RegisterAccessor(new DecimalFieldAccessor()); - RegisterAccessor(new GuidFieldAccessor()); - } - - public static void ConfigureDescriptorPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - { - if (descriptor.PackingType == FieldPackingType.Object) { - return; - } - - // d.PackingType == FieldPackingType.Value - positionUpdaters[descriptor.Rank].Invoke(ref descriptor, ref valPointers); - } - } -} +// Copyright (C) 2003-2012 Xtensive LLC. +// All rights reserved. +// For conditions of distribution and use, see license. +// Created by: Denis Krjuchkov +// Created: 2012.12.29 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Xtensive.Tuples.Packed +{ + internal ref struct ValPointers + { + public ValPointer Val001Pointer; + public ValPointer Val008Pointer; + public ValPointer Val016Pointer; + public ValPointer Val032Pointer; + public ValPointer Val064Pointer; + public ValPointer Val128Pointer; + } + + internal ref struct ValPointer + { + public int Index; + public int Offset; + } + + internal ref struct ValCounters + { + public int ObjectCounter; + + public int Val001Counter; + public int Val008Counter; + public int Val016Counter; + public int Val032Counter; + public int Val064Counter; + public int Val128Counter; + } + + internal static class TupleLayout + { + private const int Val128Rank = 7; + private const int Val064Rank = 6; + private const int Val032Rank = 5; + private const int Val016Rank = 4; + private const int Val008Rank = 3; + private const int Val001Rank = 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void InitValPointer( + ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) + { + const int remainderBitMask = (1 << Val064Rank) - 1; + var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; + + pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); + pointer.Offset = prevBitCountWithOffset & remainderBitMask; + } + + public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, + out int objectsLength) + { + var valCounters = new ValCounters(); + var fieldCount = fieldTypes.Length; + for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + fieldTypes[fieldIndex] = TupleLayout.ConfigureDescriptorPhase1( + ref valCounters, ref fieldDescriptors[fieldIndex], fieldIndex, fieldTypes[fieldIndex]); + } + + const int longBitCount = 1 << Val064Rank; + const int stateBitCount = 2; + const int statesPerLong = longBitCount / stateBitCount; + + var valueIndex = (fieldCount + (statesPerLong - 1)) / statesPerLong; + + var valPointers = new ValPointers { + Val128Pointer = new ValPointer {Index = valueIndex, Offset = 0} + }; + InitValPointer(ref valPointers.Val064Pointer, ref valPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); + InitValPointer(ref valPointers.Val032Pointer, ref valPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); + InitValPointer(ref valPointers.Val016Pointer, ref valPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); + InitValPointer(ref valPointers.Val008Pointer, ref valPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); + InitValPointer(ref valPointers.Val001Pointer, ref valPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); + + var valuesEndPointer = new ValPointer(); + InitValPointer(ref valuesEndPointer, ref valPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); + valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> 31) + 1; + + objectsLength = valCounters.ObjectCounter; + + for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + TupleLayout.ConfigureDescriptorPhase2(ref fieldDescriptors[fieldIndex], ref valPointers); + } + } + + private delegate int CounterIncrementer(ref ValCounters valCounters); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); + + private static readonly CounterIncrementer[] incrementers = { + (ref ValCounters valueCounters) => valueCounters.Val001Counter++, + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => valueCounters.Val008Counter++, + (ref ValCounters valueCounters) => valueCounters.Val016Counter++, + (ref ValCounters valueCounters) => valueCounters.Val032Counter++, + (ref ValCounters valueCounters) => valueCounters.Val064Counter++, + (ref ValCounters valueCounters) => valueCounters.Val128Counter++ + }; + + private static readonly PositionUpdater[] positionUpdaters = { + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) + }; + + private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) + { + const int remainderBitMask = (1 << Val064Rank) - 1; + + var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; + + descriptor.ValueIndex = valPointer.Index; + descriptor.ValueBitOffset = valPointer.Offset; + + valPointer.Index += increasedOffset >> Val064Rank; + valPointer.Offset = increasedOffset & remainderBitMask; + } + + private static readonly ObjectFieldAccessor ObjectAccessor; + private static readonly Dictionary ValueAccessors; + + public static IEnumerable KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType); + + public static void ConfigureAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => + descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) + ? (PackedFieldAccessor) valueAccessor + : ObjectAccessor; + + public static Type ConfigureDescriptorPhase1(ref ValCounters counters, ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) + { + descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 + descriptor.StateBitOffset = (fieldIndex & 31) << 1; + + if (ValueAccessors.TryGetValue(fieldType, out var valueAccessor)) { + ConfigureValueDescriptor(ref descriptor, ref counters, valueAccessor); + return valueAccessor.FieldType; + } + + ConfigureObjectDescriptor(ref descriptor, ref counters, ObjectAccessor); + return fieldType; + } + + private static void ConfigureObjectDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + ObjectFieldAccessor objectAccessor) + { + descriptor.Accessor = objectAccessor; + descriptor.PackingType = FieldPackingType.Object; + descriptor.ValueIndex = counters.ObjectCounter++; + } + + private static void ConfigureValueDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + ValueFieldAccessor valueAccessor) + { + descriptor.Accessor = valueAccessor; + descriptor.PackingType = FieldPackingType.Value; + descriptor.Rank = valueAccessor.Rank; + descriptor.ValueIndex = incrementers[valueAccessor.Rank].Invoke(ref counters); + } + + private static void RegisterAccessor(ValueFieldAccessor accessor) + where T : struct, IEquatable + { + ValueAccessors.Add(typeof (T), accessor); + ValueAccessors.Add(typeof (T?), accessor); + } + + static TupleLayout() + { + ObjectAccessor = new ObjectFieldAccessor(); + ValueAccessors = new Dictionary(); + RegisterAccessor(new BooleanFieldAccessor()); + RegisterAccessor(new ByteFieldAccessor()); + RegisterAccessor(new SByteFieldAccessor()); + RegisterAccessor(new ShortFieldAccessor()); + RegisterAccessor(new UShortFieldAccessor()); + RegisterAccessor(new IntFieldAccessor()); + RegisterAccessor(new UIntFieldAccessor()); + RegisterAccessor(new LongFieldAccessor()); + RegisterAccessor(new ULongFieldAccessor()); + RegisterAccessor(new FloatFieldAccessor()); + RegisterAccessor(new DoubleFieldAccessor()); + RegisterAccessor(new DateTimeFieldAccessor()); + RegisterAccessor(new TimeSpanFieldAccessor()); + RegisterAccessor(new DecimalFieldAccessor()); + RegisterAccessor(new GuidFieldAccessor()); + } + + public static void ConfigureDescriptorPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + { + if (descriptor.PackingType == FieldPackingType.Object) { + return; + } + + // d.PackingType == FieldPackingType.Value + positionUpdaters[descriptor.Rank].Invoke(ref descriptor, ref valPointers); + } + } +} diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 31d80c9487..03548da3b9 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using Xtensive.Core; @@ -44,9 +43,6 @@ public sealed class TupleDescriptor : IEquatable, IList, private static readonly ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor> CachedDescriptors4 = new ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor>(); - [NonSerialized] - private Type[] _fieldTypes; - internal readonly int FieldCount; internal readonly int ValuesLength; internal readonly int ObjectsLength; @@ -54,7 +50,8 @@ public sealed class TupleDescriptor : IEquatable, IList, [NonSerialized] internal readonly PackedFieldDescriptor[] FieldDescriptors; - internal Type[] FieldTypes => _fieldTypes; + [field: NonSerialized] + internal Type[] FieldTypes { get; } /// /// Gets the empty tuple descriptor. @@ -407,62 +404,15 @@ public static TupleDescriptor Create() // Constructors - private const int Val128Rank = 7; - private const int Val064Rank = 6; - private const int Val032Rank = 5; - private const int Val016Rank = 4; - private const int Val008Rank = 3; - private const int Val001Rank = 0; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InitValPointer( - ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) - { - const int remainderBitMask = (1 << Val064Rank) - 1; - var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; - - pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); - pointer.Offset = prevBitCountWithOffset & remainderBitMask; - } - private TupleDescriptor(Type[] fieldTypes) { ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); - _fieldTypes = fieldTypes; + FieldTypes = fieldTypes; FieldCount = fieldTypes.Length; FieldDescriptors = new PackedFieldDescriptor[FieldCount]; - var valCounters = new ValCounters(); - for (var fieldIndex = 0; fieldIndex < FieldCount; fieldIndex++) { - _fieldTypes[fieldIndex] = PackedFieldAccessorFactory.ConfigureDescriptorPhase1( - ref valCounters, ref FieldDescriptors[fieldIndex], fieldIndex, fieldTypes[fieldIndex]); - } - - const int longBitCount = 1 << Val064Rank; - const int stateBitCount = 2; - const int statesPerLong = longBitCount / stateBitCount; - - var valueIndex = (FieldCount + (statesPerLong - 1)) / statesPerLong; - - var valPointers = new ValPointers { - Val128Pointer = new ValPointer {Index = valueIndex, Offset = 0} - }; - InitValPointer(ref valPointers.Val064Pointer, ref valPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); - InitValPointer(ref valPointers.Val032Pointer, ref valPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); - InitValPointer(ref valPointers.Val016Pointer, ref valPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); - InitValPointer(ref valPointers.Val008Pointer, ref valPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); - InitValPointer(ref valPointers.Val001Pointer, ref valPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); - - var valuesEndPointer = new ValPointer(); - InitValPointer(ref valuesEndPointer, ref valPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); - ValuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> 31) + 1; - - ObjectsLength = valCounters.ObjectCounter; - - for (var fieldIndex = 0; fieldIndex < FieldCount; fieldIndex++) { - PackedFieldAccessorFactory.ConfigureDescriptorPhase2(ref FieldDescriptors[fieldIndex], ref valPointers); - } + TupleLayout.Configure(fieldTypes, FieldDescriptors, out ValuesLength, out ObjectsLength); } public TupleDescriptor(SerializationInfo info, StreamingContext context) @@ -475,20 +425,16 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) FieldDescriptors = (PackedFieldDescriptor[])info.GetValue( "FieldDescriptors", typeof(PackedFieldDescriptor[])); - _fieldTypes = new Type[typeNames.Length]; + FieldTypes = new Type[typeNames.Length]; for (var i = 0; i < typeNames.Length; i++) { - _fieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); - } - - for (var i = 0; i < _fieldTypes.Length; i++) { - PackedFieldAccessorFactory.SetAccessor(ref FieldDescriptors[i], _fieldTypes[i]); + FieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); + TupleLayout.ConfigureAccessor(ref FieldDescriptors[i], FieldTypes[i]); } } - static TupleDescriptor() { - var types = PackedFieldAccessorFactory.KnownTypes.Concat(new [] { + var types = TupleLayout.KnownTypes.Concat(new [] { typeof(string), typeof(byte[]), }); From 1e8113f8a4653f3cbb001f8d5b83ec52f5ff8b54 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 18 Mar 2020 15:17:00 -0700 Subject: [PATCH 08/31] Organize code in TupleLayout class --- .../Tuples/Packed/PackedFieldAccessor.cs | 5 +- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 250 +++++++++--------- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 7 +- 3 files changed, 131 insertions(+), 131 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index 8d27a603a6..2e6121b0bd 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -109,7 +109,7 @@ internal abstract class ValueFieldAccessor : PackedFieldAccessor { public readonly int Rank; - public abstract Type FieldType { get; } + public Type FieldType { get; protected set; } private static int GetRank(int bitSize) { @@ -133,8 +133,6 @@ internal abstract class ValueFieldAccessor : ValueFieldAccessor private static readonly T DefaultValue = default; private static readonly T? NullValue = null; - public override Type FieldType { get; } = typeof(T); - protected virtual long Encode(T value) => throw new NotSupportedException(); protected virtual void Encode(T value, long[] values, int offset) => throw new NotSupportedException(); @@ -236,6 +234,7 @@ private T Load(PackedTuple tuple, ref PackedFieldDescriptor d) protected ValueFieldAccessor(int bits) : base(bits) { + FieldType = typeof(T); Getter = (GetValueDelegate) GetValue; Setter = (SetValueDelegate) SetValue; diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index bcaa5d9aca..b4d2bef5de 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -11,34 +11,6 @@ namespace Xtensive.Tuples.Packed { - internal ref struct ValPointers - { - public ValPointer Val001Pointer; - public ValPointer Val008Pointer; - public ValPointer Val016Pointer; - public ValPointer Val032Pointer; - public ValPointer Val064Pointer; - public ValPointer Val128Pointer; - } - - internal ref struct ValPointer - { - public int Index; - public int Offset; - } - - internal ref struct ValCounters - { - public int ObjectCounter; - - public int Val001Counter; - public int Val008Counter; - public int Val016Counter; - public int Val032Counter; - public int Val064Counter; - public int Val128Counter; - } - internal static class TupleLayout { private const int Val128Rank = 7; @@ -48,35 +20,75 @@ internal static class TupleLayout private const int Val008Rank = 3; private const int Val001Rank = 0; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InitValPointer( - ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) + private const int Val064BitCount = 1 << Val064Rank; + private const int Val032BitCount = 1 << Val032Rank; + private const int Modulo064RemainderMask = Val064BitCount - 1; + private const int Modulo032RemainderMask = Val032BitCount - 1; + + private ref struct ValPointer { - const int remainderBitMask = (1 << Val064Rank) - 1; - var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; + public int Index; + public int Offset; + } - pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); - pointer.Offset = prevBitCountWithOffset & remainderBitMask; + private ref struct ValPointers + { + public ValPointer Val001Pointer; + public ValPointer Val008Pointer; + public ValPointer Val016Pointer; + public ValPointer Val032Pointer; + public ValPointer Val064Pointer; + public ValPointer Val128Pointer; } + private ref struct ValCounters + { + public int ObjectCounter; + + public int Val001Counter; + public int Val008Counter; + public int Val016Counter; + public int Val032Counter; + public int Val064Counter; + public int Val128Counter; + } + + private delegate void CounterIncrementer(ref ValCounters valCounters); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); + + private static readonly ObjectFieldAccessor ObjectAccessor; + private static readonly Dictionary ValueAccessors; + private static readonly CounterIncrementer[] IncrementerByRank; + private static readonly PositionUpdater[] PositionUpdaterByRank; + + public static Type[] KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType) + .Concat(new[] {typeof(string), typeof(byte[])}) + .ToArray(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ConfigureFieldAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => + descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) + ? (PackedFieldAccessor) valueAccessor + : ObjectAccessor; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, out int objectsLength) { var valCounters = new ValCounters(); var fieldCount = fieldTypes.Length; for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - fieldTypes[fieldIndex] = TupleLayout.ConfigureDescriptorPhase1( - ref valCounters, ref fieldDescriptors[fieldIndex], fieldIndex, fieldTypes[fieldIndex]); + ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref valCounters, fieldTypes, fieldIndex); } - const int longBitCount = 1 << Val064Rank; const int stateBitCount = 2; - const int statesPerLong = longBitCount / stateBitCount; - - var valueIndex = (fieldCount + (statesPerLong - 1)) / statesPerLong; + const int statesPerLong = Val064BitCount / stateBitCount; var valPointers = new ValPointers { - Val128Pointer = new ValPointer {Index = valueIndex, Offset = 0} + Val128Pointer = new ValPointer { + Index = (fieldCount + (statesPerLong - 1)) / statesPerLong, + Offset = 0 + } }; InitValPointer(ref valPointers.Val064Pointer, ref valPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); InitValPointer(ref valPointers.Val032Pointer, ref valPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); @@ -86,111 +98,83 @@ public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDes var valuesEndPointer = new ValPointer(); InitValPointer(ref valuesEndPointer, ref valPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); - valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> 31) + 1; + + const int max032Shift = Val032BitCount - 1; + // Expression ((N - 1) >> max032Shift) evaluates to 0 for all N > 0; for N <= 0 it evaluates to -1 + // This means we add one element to values array if Offset is positive; otherwise we don't + valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> max032Shift) + 1; objectsLength = valCounters.ObjectCounter; for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - TupleLayout.ConfigureDescriptorPhase2(ref fieldDescriptors[fieldIndex], ref valPointers); + ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref valPointers); } } - private delegate int CounterIncrementer(ref ValCounters valCounters); - private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void InitValPointer( + ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) + { + var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; - private static readonly CounterIncrementer[] incrementers = { - (ref ValCounters valueCounters) => valueCounters.Val001Counter++, - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => valueCounters.Val008Counter++, - (ref ValCounters valueCounters) => valueCounters.Val016Counter++, - (ref ValCounters valueCounters) => valueCounters.Val032Counter++, - (ref ValCounters valueCounters) => valueCounters.Val064Counter++, - (ref ValCounters valueCounters) => valueCounters.Val128Counter++ - }; - - private static readonly PositionUpdater[] positionUpdaters = { - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) - }; + pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); + pointer.Offset = prevBitCountWithOffset & Modulo064RemainderMask; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) { - const int remainderBitMask = (1 << Val064Rank) - 1; - - var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; - descriptor.ValueIndex = valPointer.Index; descriptor.ValueBitOffset = valPointer.Offset; + var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; valPointer.Index += increasedOffset >> Val064Rank; - valPointer.Offset = increasedOffset & remainderBitMask; + valPointer.Offset = increasedOffset & Modulo064RemainderMask; } - private static readonly ObjectFieldAccessor ObjectAccessor; - private static readonly Dictionary ValueAccessors; - - public static IEnumerable KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ConfigureFieldPhase1( + ref PackedFieldDescriptor descriptor, ref ValCounters counters, Type[] fieldTypes, int fieldIndex) + { + descriptor.StateIndex = fieldIndex >> Val032Rank; // d.FieldIndex / 32 + descriptor.StateBitOffset = (fieldIndex & Modulo032RemainderMask) << 1; - public static void ConfigureAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => - descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) - ? (PackedFieldAccessor) valueAccessor - : ObjectAccessor; + if (ValueAccessors.TryGetValue(fieldTypes[fieldIndex], out var valueAccessor)) { + descriptor.Accessor = valueAccessor; + descriptor.PackingType = FieldPackingType.Value; + descriptor.Rank = valueAccessor.Rank; - public static Type ConfigureDescriptorPhase1(ref ValCounters counters, ref PackedFieldDescriptor descriptor, int fieldIndex, Type fieldType) - { - descriptor.StateIndex = fieldIndex >> 5; // d.FieldIndex / 32 - descriptor.StateBitOffset = (fieldIndex & 31) << 1; + IncrementerByRank[valueAccessor.Rank].Invoke(ref counters); - if (ValueAccessors.TryGetValue(fieldType, out var valueAccessor)) { - ConfigureValueDescriptor(ref descriptor, ref counters, valueAccessor); - return valueAccessor.FieldType; + fieldTypes[fieldIndex] = valueAccessor.FieldType; + return; } - ConfigureObjectDescriptor(ref descriptor, ref counters, ObjectAccessor); - return fieldType; - } - - private static void ConfigureObjectDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, - ObjectFieldAccessor objectAccessor) - { - descriptor.Accessor = objectAccessor; + descriptor.Accessor = ObjectAccessor; descriptor.PackingType = FieldPackingType.Object; descriptor.ValueIndex = counters.ObjectCounter++; } - private static void ConfigureValueDescriptor(ref PackedFieldDescriptor descriptor, ref ValCounters counters, - ValueFieldAccessor valueAccessor) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) { - descriptor.Accessor = valueAccessor; - descriptor.PackingType = FieldPackingType.Value; - descriptor.Rank = valueAccessor.Rank; - descriptor.ValueIndex = incrementers[valueAccessor.Rank].Invoke(ref counters); - } + if (descriptor.PackingType == FieldPackingType.Object) { + return; + } - private static void RegisterAccessor(ValueFieldAccessor accessor) - where T : struct, IEquatable - { - ValueAccessors.Add(typeof (T), accessor); - ValueAccessors.Add(typeof (T?), accessor); + // d.PackingType == FieldPackingType.Value + PositionUpdaterByRank[descriptor.Rank].Invoke(ref descriptor, ref valPointers); } static TupleLayout() { + void RegisterAccessor(ValueFieldAccessor accessor) + where T : struct, IEquatable + { + ValueAccessors.Add(typeof(T), accessor); + ValueAccessors.Add(typeof(T?), accessor); + } + ObjectAccessor = new ObjectFieldAccessor(); ValueAccessors = new Dictionary(); RegisterAccessor(new BooleanFieldAccessor()); @@ -208,16 +192,36 @@ static TupleLayout() RegisterAccessor(new TimeSpanFieldAccessor()); RegisterAccessor(new DecimalFieldAccessor()); RegisterAccessor(new GuidFieldAccessor()); - } - public static void ConfigureDescriptorPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - { - if (descriptor.PackingType == FieldPackingType.Object) { - return; - } + IncrementerByRank = new CounterIncrementer[] { + (ref ValCounters valueCounters) => valueCounters.Val001Counter++, + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => throw new NotSupportedException(), + (ref ValCounters valueCounters) => valueCounters.Val008Counter++, + (ref ValCounters valueCounters) => valueCounters.Val016Counter++, + (ref ValCounters valueCounters) => valueCounters.Val032Counter++, + (ref ValCounters valueCounters) => valueCounters.Val064Counter++, + (ref ValCounters valueCounters) => valueCounters.Val128Counter++ + }; - // d.PackingType == FieldPackingType.Value - positionUpdaters[descriptor.Rank].Invoke(ref descriptor, ref valPointers); + PositionUpdaterByRank = new PositionUpdater[] { + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), + (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) + }; } } } diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 03548da3b9..2a24d0ebaf 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -428,16 +428,13 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) FieldTypes = new Type[typeNames.Length]; for (var i = 0; i < typeNames.Length; i++) { FieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); - TupleLayout.ConfigureAccessor(ref FieldDescriptors[i], FieldTypes[i]); + TupleLayout.ConfigureFieldAccessor(ref FieldDescriptors[i], FieldTypes[i]); } } static TupleDescriptor() { - var types = TupleLayout.KnownTypes.Concat(new [] { - typeof(string), - typeof(byte[]), - }); + var types = TupleLayout.KnownTypes; foreach (var type1 in types) { CachedDescriptors1.Add(type1, new TupleDescriptor(new[] {type1})); foreach (var type2 in types) { From eef85ec132c313332d35803a3bfd117cd8edaa38 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 18 Mar 2020 15:43:57 -0700 Subject: [PATCH 09/31] Make code resistant to sign bit propagation by right shift operator --- .../Tuples/Packed/PackedFieldDescriptor.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index 0806a15870..11e516a0ce 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -15,8 +15,10 @@ internal struct PackedFieldDescriptor private const int IndexMask = (1 << IndexBitCount) - 1; private const int OffsetBitCount = 7; private const int OffsetMask = ((1 << OffsetBitCount) - 1) << IndexBitCount; + private const int MaskBitCount = (sizeof(int) * 8) - (IndexBitCount + OffsetBitCount); - private const int Mask = ((1 << MaskBitCount) - 1) << (IndexBitCount + OffsetBitCount); + private const int GetValueMask = (1 << MaskBitCount) - 1; + private const int SetValueMask = GetValueMask << (IndexBitCount + OffsetBitCount); private int data1; private int data2; @@ -38,8 +40,8 @@ public int ValueBitOffset public int Rank { - get => (data1 & Mask) >> (IndexBitCount + OffsetBitCount); - set => data1 = (data1 & ~Mask) | ((value << (IndexBitCount + OffsetBitCount)) & Mask); + get => (data1 >> (IndexBitCount + OffsetBitCount)) & GetValueMask; + set => data1 = (data1 & ~SetValueMask) | ((value << (IndexBitCount + OffsetBitCount)) & SetValueMask); } public int ValueBitCount => 1 << Rank; @@ -60,8 +62,8 @@ public int StateBitOffset public FieldPackingType PackingType { - get => (FieldPackingType)((data2 & Mask) >> (IndexBitCount + OffsetBitCount)); - set => data2 = (data2 & ~Mask) | (((int)value << (IndexBitCount + OffsetBitCount)) & Mask); + get => (FieldPackingType)((data2 >> (IndexBitCount + OffsetBitCount)) & GetValueMask); + set => data2 = (data2 & ~SetValueMask) | (((int)value << (IndexBitCount + OffsetBitCount)) & SetValueMask); } } } \ No newline at end of file From 03234aca944e51717b397c757812ca2d75bdb9ba Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 18 Mar 2020 16:05:02 -0700 Subject: [PATCH 10/31] Explanation of ValueBitMask calculation --- .../Tuples/Packed/PackedFieldDescriptor.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index 11e516a0ce..f11738b391 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -46,6 +46,17 @@ public int Rank public int ValueBitCount => 1 << Rank; + // What we want here is to shift 1L by ValueBitCount to left and then subtract 1 + // This gives us a mask. For example if bit count = 4 then + // 0000_0001 << 4 = 0001_0000 + // 0001_000 - 1 = 0000_1111 + // However in case bit count equal to data type size left shift doesn't work as we want + // e.g. for Int8 : 0000_0001 << 8 = 0000_0001 but we would like it to be 0000_0000 + // because 0000_0000 - 1 = 1111_1111 and this is exactly what we need. + // As a workaround we do left shift in two steps. In the example above + // 0000_0001 << 7 = 1000_0000 + // and then + // 1000_0000 << 1 = 0000_0000 public long ValueBitMask => (1L << (ValueBitCount - 1) << 1) - 1; public int StateIndex From 1ca12b7e42bb1ddb445338639c6a6db9821bc3f4 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 25 Mar 2020 14:44:51 -0700 Subject: [PATCH 11/31] TypeInfo.BuildVersionExtractor method improvements --- Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs index 4368ffeb23..93bfb1e71f 100644 --- a/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs +++ b/Orm/Xtensive.Orm/Orm/Model/TypeInfo.cs @@ -811,12 +811,13 @@ private void BuildVersionExtractor() { // Building version tuple extractor var versionColumns = GetVersionColumns(); - if (versionColumns==null || versionColumns.Count==0) { + var versionColumnsCount = versionColumns?.Count ?? 0; + if (versionColumns==null || versionColumnsCount==0) { VersionExtractor = null; return; } - var types = versionColumns.Select(c => c.ValueType).ToArray(); - var map = versionColumns.Select(c => c.Field.MappingInfo.Offset).ToArray(); + var types = versionColumns.Select(c => c.ValueType).ToArray(versionColumnsCount); + var map = versionColumns.Select(c => c.Field.MappingInfo.Offset).ToArray(versionColumnsCount); var versionTupleDescriptor = TupleDescriptor.Create(types); VersionExtractor = new MapTransform(true, versionTupleDescriptor, map); } From c1db7b22c98c2a733f0a62309b04c39189bd4399 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 25 Mar 2020 14:45:33 -0700 Subject: [PATCH 12/31] ItemToTupleConverter improvements --- .../Orm/Linq/ItemToTupleConverter{TItem}.cs | 65 +++++++++++++------ Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 2 +- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs index a6722ef095..645eb18441 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs @@ -26,6 +26,30 @@ namespace Xtensive.Orm.Linq [Serializable] internal sealed class ItemToTupleConverter : ItemToTupleConverter { + private class TupleTypeCollection: IReadOnlyCollection + { + private IEnumerable types; + private int count; + + public int Count => count; + + public IEnumerator GetEnumerator() => (types ?? Enumerable.Empty()).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public void Add(Type type) + { + count++; + types = types==null ? EnumerableUtils.One(type) : types.Concat(EnumerableUtils.One(type)); + } + + public void AddRange(IReadOnlyCollection newTypes) + { + count += newTypes.Count; + types = types == null ? newTypes : types.Concat(newTypes); + } + } + private readonly Func> enumerableFunc; private readonly DomainModel model; private Func converter; @@ -124,7 +148,7 @@ private void FillLocalCollectionField(object item, Tuple tuple, Expression expre throw new NotSupportedException(); } - private LocalCollectionExpression BuildLocalCollectionExpression(Type type, Xtensive.Collections.ISet processedTypes, ref int columnIndex, MemberInfo parentMember, ref IEnumerable types) + private LocalCollectionExpression BuildLocalCollectionExpression(Type type, HashSet processedTypes, ref int columnIndex, MemberInfo parentMember, TupleTypeCollection types) { if (type.IsAssignableFrom(typeof (Key))) throw new InvalidOperationException(String.Format(Strings.ExUnableToStoreUntypedKeyToStorage, typeof (Ref<>).GetShortName())); @@ -144,11 +168,11 @@ private LocalCollectionExpression BuildLocalCollectionExpression(Type type, Xten ? ((FieldInfo) memberInfo).FieldType : propertyInfo.PropertyType; if (IsPersistableType(memberType)) { - IMappedExpression expression = BuildField(memberType, ref columnIndex, ref types); + IMappedExpression expression = BuildField(memberType, ref columnIndex, types); fields.Add(memberInfo, expression); } else { - LocalCollectionExpression collectionExpression = BuildLocalCollectionExpression(memberType, new Set(processedTypes), ref columnIndex, memberInfo, ref types); + LocalCollectionExpression collectionExpression = BuildLocalCollectionExpression(memberType, new HashSet(processedTypes), ref columnIndex, memberInfo, types); fields.Add(memberInfo, collectionExpression); } } @@ -160,7 +184,7 @@ private LocalCollectionExpression BuildLocalCollectionExpression(Type type, Xten } - private IMappedExpression BuildField(Type type, ref int index, ref IEnumerable types) + private IMappedExpression BuildField(Type type, ref int index, TupleTypeCollection types) { // if (type.IsOfGenericType(typeof (Ref<>))) { // var entityType = type.GetGenericType(typeof (Ref<>)).GetGenericArguments()[0]; @@ -186,7 +210,7 @@ private IMappedExpression BuildField(Type type, ref int index, ref IEnumerable(index, tupleDescriptor.Count); StructureExpression structureExpression = StructureExpression.CreateLocalCollectionStructure(typeInfo, tupleSegment); index += tupleDescriptor.Count; - types = types.Concat(tupleDescriptor); + types.AddRange(tupleDescriptor); return structureExpression; } if (TypeIsStorageMappable(type)) { ColumnExpression columnExpression = ColumnExpression.Create(type, index); - types = types.AddOne(type); + types.Add(type); index++; return columnExpression; } @@ -212,29 +236,28 @@ private IMappedExpression BuildField(Type type, ref int index, ref IEnumerable types = EnumerableUtils.Empty; + var itemType = isKeyConverter ? entityTypestoredInKey : typeof (TItem); + var index = 0; + var types = new TupleTypeCollection(); if (IsPersistableType(itemType)) { - Expression = (Expression) BuildField(itemType, ref index, ref types); - TupleDescriptor = TupleDescriptor.Create(types.ToArray()); + Expression = (Expression) BuildField(itemType, ref index, types); + TupleDescriptor = TupleDescriptor.Create(types.ToArray(types.Count)); } else { - Collections.ISet processedTypes = new Set(); - LocalCollectionExpression itemExpression = BuildLocalCollectionExpression(itemType, processedTypes, ref index, null, ref types); - TupleDescriptor = TupleDescriptor.Create(types.ToArray()); + var processedTypes = new HashSet(); + var itemExpression = BuildLocalCollectionExpression(itemType, processedTypes, ref index, null, types); + TupleDescriptor = TupleDescriptor.Create(types.ToArray(types.Count)); Expression = itemExpression; } - Func converter = delegate(TItem item) { - RegularTuple tuple = Tuple.Create(TupleDescriptor); - if (ReferenceEquals(item, null)) + + converter = delegate(TItem item) { + Tuple tuple = Tuple.Create(TupleDescriptor); + if (ReferenceEquals(item, null)) { return tuple; - int offset = 0; + } FillLocalCollectionField(item, tuple, Expression); return tuple; }; - this.converter = converter; } public ItemToTupleConverter(Func> enumerableFunc, DomainModel model, Expression sourceExpression, Type storedEntityType) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 2a24d0ebaf..3e9a77fbb4 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -25,7 +25,7 @@ namespace Xtensive.Tuples /// Provides information about structure. /// [Serializable] - public sealed class TupleDescriptor : IEquatable, IList, ISerializable + public sealed class TupleDescriptor : IEquatable, IList, IReadOnlyList, ISerializable { [NonSerialized] private static readonly TupleDescriptor EmptyDescriptor = From 44197e1b32ad05f534cfe8129b8e6a77f9b3f6bc Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 30 Mar 2020 15:56:38 -0700 Subject: [PATCH 13/31] Tail and Head methods improvements --- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 3e9a77fbb4..45af33bd9a 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -340,9 +340,10 @@ public static TupleDescriptor Create(Type[] fieldTypes) /// describing the specified set of fields. public TupleDescriptor Head(int fieldCount) { - ArgumentValidator.EnsureArgumentIsInRange(fieldCount, 1, Count, "fieldCount"); - var fieldTypes = FieldTypes.ToArray(fieldCount); - return Create(fieldTypes); + ArgumentValidator.EnsureArgumentIsInRange(fieldCount, 1, Count, nameof(fieldCount)); + var fieldTypes = new Type[fieldCount]; + Array.Copy(FieldTypes, 0, fieldTypes, 0, fieldCount); + return new TupleDescriptor(fieldTypes); } /// @@ -353,9 +354,10 @@ public TupleDescriptor Head(int fieldCount) /// describing the specified set of fields. public TupleDescriptor Tail(int tailFieldCount) { - ArgumentValidator.EnsureArgumentIsInRange(tailFieldCount, 1, Count, "tailFieldCount"); - var fieldTypes = FieldTypes.Skip(Count - tailFieldCount).ToArray(tailFieldCount); - return Create(fieldTypes); + ArgumentValidator.EnsureArgumentIsInRange(tailFieldCount, 1, Count, nameof(tailFieldCount)); + var fieldTypes = new Type[tailFieldCount]; + Array.Copy(FieldTypes, Count - tailFieldCount, fieldTypes, 0, tailFieldCount); + return new TupleDescriptor(fieldTypes); } #endregion From c403616a114149c03b2075dcf56beb4e33f89ab7 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 30 Mar 2020 15:54:04 -0700 Subject: [PATCH 14/31] Cache BoolType and BoolTypeDescriptor --- .../Orm/Rse/Providers/Compilable/IncludeProvider.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs index 0048e0db90..f50f484112 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs @@ -62,16 +62,19 @@ public int[] FilteredColumns { public CombineTransform ResultTransform { get; private set; } + private static readonly Type BoolType = typeof(bool); + private static readonly TupleDescriptor BoolTupleDescriptor = TupleDescriptor.Create(new[] {BoolType}); + /// protected override RecordSetHeader BuildHeader() { - var newHeader = Source.Header.Add(new SystemColumn(ResultColumnName, 0, typeof(bool))); + var newHeader = Source.Header.Add(new SystemColumn(ResultColumnName, 0, BoolType)); var fieldTypes = FilteredColumns .Select(m => newHeader.Columns[m].Type) .ToArray(FilteredColumns.Length); var tupleDescriptor = TupleDescriptor.Create(fieldTypes); FilteredColumnsExtractionTransform = new MapTransform(true, tupleDescriptor, FilteredColumns); - ResultTransform = new CombineTransform(true, Source.Header.TupleDescriptor, TupleDescriptor.Create()); + ResultTransform = new CombineTransform(true, Source.Header.TupleDescriptor, BoolTupleDescriptor); return newHeader; } From 2ecce7b2a1939a18e160d09e0c68579a1d7505e3 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 30 Mar 2020 16:02:17 -0700 Subject: [PATCH 15/31] Do not create new empty array on field initialization --- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 45af33bd9a..fae354a6b5 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -27,9 +27,7 @@ namespace Xtensive.Tuples [Serializable] public sealed class TupleDescriptor : IEquatable, IList, IReadOnlyList, ISerializable { - [NonSerialized] - private static readonly TupleDescriptor EmptyDescriptor = - new TupleDescriptor(new Type[0]); + private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(Array.Empty()); [NonSerialized] private static readonly Dictionary CachedDescriptors1 = new Dictionary(); From 1ff45732b51c7f802a2098a7c858f804a1e08f39 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 16:29:51 -0700 Subject: [PATCH 16/31] Small KeyFactory improvement --- Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs b/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs index a844a1d0ee..c9cd37796a 100644 --- a/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs +++ b/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs @@ -155,7 +155,7 @@ private static GenericKeyFactory BuildGenericKeyFactory(TypeInfo typeInfo) var descriptor = typeInfo.Key.TupleDescriptor; var keyTypeName = string.Format(GenericKeyNameFormat, typeof (Key<>).Namespace, typeof (Key).Name, descriptor.Count); var keyType = typeof (Key).Assembly.GetType(keyTypeName); - keyType = keyType.MakeGenericType(descriptor.ToArray()); + keyType = keyType.MakeGenericType(descriptor.ToArray(descriptor.Count)); var defaultConstructor = DelegateHelper.CreateDelegate>( null, keyType, "Create", ArrayUtils.EmptyArray); var keyIndexBasedConstructor = DelegateHelper.CreateDelegate>( From 2cf5c038c4ca21ebfa4134af31d4a8371c64c013 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 25 Mar 2020 17:50:43 -0700 Subject: [PATCH 17/31] Bump version to 6.0.2 'tupledescriptor' --- Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Version.props b/Version.props index 2ec8dab432..a74ce738a2 100644 --- a/Version.props +++ b/Version.props @@ -2,8 +2,8 @@ - 6.0.1 - + 6.0.2 + tupledescriptor From 1ee574141480ed042c64581389c2a552e9286513 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 18:58:34 -0700 Subject: [PATCH 18/31] Get rid of TupleDescriptor caches --- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 6 +- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 56 +------------------ 2 files changed, 2 insertions(+), 60 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index b4d2bef5de..988f872e15 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2012 Xtensive LLC. +// Copyright (C) 2003-2012 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Denis Krjuchkov @@ -61,10 +61,6 @@ private ref struct ValCounters private static readonly CounterIncrementer[] IncrementerByRank; private static readonly PositionUpdater[] PositionUpdaterByRank; - public static Type[] KnownTypes => ValueAccessors.Keys.Where(t => !t.IsGenericType) - .Concat(new[] {typeof(string), typeof(byte[])}) - .ToArray(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ConfigureFieldAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index fae354a6b5..f103f9d9ac 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -28,18 +28,6 @@ namespace Xtensive.Tuples public sealed class TupleDescriptor : IEquatable, IList, IReadOnlyList, ISerializable { private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(Array.Empty()); - [NonSerialized] - private static readonly Dictionary CachedDescriptors1 = - new Dictionary(); - [NonSerialized] - private static readonly Dictionary<(Type, Type), TupleDescriptor> CachedDescriptors2 = - new Dictionary<(Type, Type), TupleDescriptor>(); - [NonSerialized] - private static readonly Dictionary<(Type, Type, Type), TupleDescriptor> CachedDescriptors3 = - new Dictionary<(Type, Type, Type), TupleDescriptor>(); - [NonSerialized] - private static readonly ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor> CachedDescriptors4 = - new ConcurrentDictionary<(Type, Type, Type, Type), TupleDescriptor>(); internal readonly int FieldCount; internal readonly int ValuesLength; @@ -267,32 +255,22 @@ public override string ToString() public static TupleDescriptor Create(Type t1) { - if (CachedDescriptors1.TryGetValue(t1, out var cachedDescriptor)) - return cachedDescriptor; return new TupleDescriptor(new [] {t1}); } public static TupleDescriptor Create(Type t1, Type t2) { - var key = (t1, t2); - if (CachedDescriptors2.TryGetValue(key, out var cachedDescriptor)) - return cachedDescriptor; return new TupleDescriptor(new [] {t1, t2}); } public static TupleDescriptor Create(Type t1, Type t2, Type t3) { - var key = (t1, t2, t3); - if (CachedDescriptors3.TryGetValue(key, out var cachedDescriptor)) - return cachedDescriptor; return new TupleDescriptor(new [] {t1, t2, t3}); } public static TupleDescriptor Create(Type t1, Type t2, Type t3, Type t4) { - var key = (t1, t2, t3, t4); - return CachedDescriptors4.GetOrAdd(key, k => - new TupleDescriptor(new [] {k.Item1, k.Item2, k.Item3, k.Item4})); + return new TupleDescriptor(new [] {t1, t2, t3, t4}); } /// @@ -308,24 +286,6 @@ public static TupleDescriptor Create(Type[] fieldTypes) switch (fieldTypes.Length) { case 0: return EmptyDescriptor; - case 1: - if (CachedDescriptors1.TryGetValue(fieldTypes[0], out var cachedDescriptor)) - return cachedDescriptor; - break; - case 2: - var key2 = (fieldTypes[0], fieldTypes[1]); - if (CachedDescriptors2.TryGetValue(key2, out cachedDescriptor)) - return cachedDescriptor; - break; - case 3: - var key3 = (fieldTypes[0], fieldTypes[1], fieldTypes[2]); - if (CachedDescriptors3.TryGetValue(key3, out cachedDescriptor)) - return cachedDescriptor; - break; - case 4: - var key4 = (fieldTypes[0], fieldTypes[1], fieldTypes[2], fieldTypes[3]); - return CachedDescriptors4.GetOrAdd(key4, k => - new TupleDescriptor(new [] {k.Item1, k.Item2, k.Item3, k.Item4})); } return new TupleDescriptor(fieldTypes); } @@ -431,19 +391,5 @@ public TupleDescriptor(SerializationInfo info, StreamingContext context) TupleLayout.ConfigureFieldAccessor(ref FieldDescriptors[i], FieldTypes[i]); } } - - static TupleDescriptor() - { - var types = TupleLayout.KnownTypes; - foreach (var type1 in types) { - CachedDescriptors1.Add(type1, new TupleDescriptor(new[] {type1})); - foreach (var type2 in types) { - CachedDescriptors2.Add((type1, type2), new TupleDescriptor(new[] {type1, type2})); - foreach (var type3 in types) { - CachedDescriptors3.Add((type1, type2, type3), new TupleDescriptor(new[] {type1, type2, type3})); - } - } - } - } } } From 28c23c799bcfae78753f329dcd6428661eb93e4b Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 16:56:29 -0700 Subject: [PATCH 19/31] Introduce ValueFieldAccessorResolver --- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 131 +++++++++++++----- 1 file changed, 96 insertions(+), 35 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 988f872e15..3cf7f4bd91 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -5,8 +5,6 @@ // Created: 2012.12.29 using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; namespace Xtensive.Tuples.Packed @@ -53,19 +51,106 @@ private ref struct ValCounters public int Val128Counter; } + private static class ValueFieldAccessorResolver + { + private static readonly Type BoolType = typeof(bool); + private static readonly Type NullableBoolType = typeof(bool?); + private static readonly Type ByteType = typeof(byte); + private static readonly Type NullableByteType = typeof(byte?); + private static readonly Type SByteType = typeof(sbyte); + private static readonly Type NullableSByteType = typeof(sbyte?); + private static readonly Type Int16Type = typeof(short); + private static readonly Type NullableInt16Type = typeof(short?); + private static readonly Type UInt16Type = typeof(ushort); + private static readonly Type NullableUInt16Type = typeof(ushort?); + private static readonly Type Int32Type = typeof(int); + private static readonly Type NullableInt32Type = typeof(int?); + private static readonly Type UInt32Type = typeof(uint); + private static readonly Type NullableUInt32Type = typeof(uint?); + private static readonly Type Int64Type = typeof(long); + private static readonly Type NullableInt64Type = typeof(long?); + private static readonly Type UInt64Type = typeof(ulong); + private static readonly Type NullableUInt64Type = typeof(ulong?); + private static readonly Type SingleType = typeof(float); + private static readonly Type NullableSingleType = typeof(float?); + private static readonly Type DoubleType = typeof(double); + private static readonly Type NullableDoubleType = typeof(double?); + private static readonly Type DateTimeType = typeof(DateTime); + private static readonly Type NullableDateTimeType = typeof(DateTime?); + private static readonly Type TimeSpanType = typeof(TimeSpan); + private static readonly Type NullableTimeSpanType = typeof(TimeSpan?); + private static readonly Type DecimalType = typeof(decimal); + private static readonly Type NullableDecimalType = typeof(decimal?); + private static readonly Type GuidType = typeof(Guid); + private static readonly Type NullableGuidType = typeof(Guid?); + + private static readonly ValueFieldAccessor BoolAccessor = new BooleanFieldAccessor(); + private static readonly ValueFieldAccessor ByteAccessor = new ByteFieldAccessor(); + private static readonly ValueFieldAccessor SByteAccessor = new SByteFieldAccessor(); + private static readonly ValueFieldAccessor Int16Accessor = new ShortFieldAccessor(); + private static readonly ValueFieldAccessor UInt16Accessor = new UShortFieldAccessor(); + private static readonly ValueFieldAccessor Int32Accessor = new IntFieldAccessor(); + private static readonly ValueFieldAccessor UInt32Accessor = new UIntFieldAccessor(); + private static readonly ValueFieldAccessor Int64Accessor = new LongFieldAccessor(); + private static readonly ValueFieldAccessor UInt64Accessor = new ULongFieldAccessor(); + private static readonly ValueFieldAccessor SingleAccessor = new FloatFieldAccessor(); + private static readonly ValueFieldAccessor DoubleAccessor = new DoubleFieldAccessor(); + private static readonly ValueFieldAccessor DateTimeAccessor = new DateTimeFieldAccessor(); + private static readonly ValueFieldAccessor TimeSpanAccessor = new TimeSpanFieldAccessor(); + private static readonly ValueFieldAccessor DecimalAccessor = new DecimalFieldAccessor(); + private static readonly ValueFieldAccessor GuidAccessor = new GuidFieldAccessor(); + + public static ValueFieldAccessor GetValue(Type probeType) + { + ValueFieldAccessor ResolveByType(Type type) => + ReferenceEquals(type, BoolType) ? BoolAccessor : + ReferenceEquals(type, ByteType) ? ByteAccessor : + ReferenceEquals(type, SByteType) ? SByteAccessor : + ReferenceEquals(type, Int16Type) ? Int16Accessor : + ReferenceEquals(type, UInt16Type) ? UInt16Accessor : + ReferenceEquals(type, Int32Type) ? Int32Accessor : + ReferenceEquals(type, UInt32Type) ? UInt32Accessor : + ReferenceEquals(type, Int64Type) ? Int64Accessor : + ReferenceEquals(type, UInt64Type) ? UInt64Accessor : + ReferenceEquals(type, SingleType) ? SingleAccessor : + ReferenceEquals(type, DoubleType) ? DoubleAccessor : + ReferenceEquals(type, DateTimeType) ? DateTimeAccessor : + ReferenceEquals(type, TimeSpanType) ? TimeSpanAccessor : + ReferenceEquals(type, DecimalType) ? DecimalAccessor : + ReferenceEquals(type, GuidType) ? GuidAccessor : null; + + ValueFieldAccessor ResolveByNullableType(Type type) => + ReferenceEquals(type, NullableBoolType) ? BoolAccessor : + ReferenceEquals(type, NullableByteType) ? ByteAccessor : + ReferenceEquals(type, NullableSByteType) ? SByteAccessor : + ReferenceEquals(type, NullableInt16Type) ? Int16Accessor : + ReferenceEquals(type, NullableUInt16Type) ? UInt16Accessor : + ReferenceEquals(type, NullableInt32Type) ? Int32Accessor : + ReferenceEquals(type, NullableUInt32Type) ? UInt32Accessor : + ReferenceEquals(type, NullableInt64Type) ? Int64Accessor : + ReferenceEquals(type, NullableUInt64Type) ? UInt64Accessor : + ReferenceEquals(type, NullableSingleType) ? SingleAccessor : + ReferenceEquals(type, NullableDoubleType) ? DoubleAccessor : + ReferenceEquals(type, NullableDateTimeType) ? DateTimeAccessor : + ReferenceEquals(type, NullableTimeSpanType) ? TimeSpanAccessor : + ReferenceEquals(type, NullableDecimalType) ? DecimalAccessor : + ReferenceEquals(type, NullableGuidType) ? GuidAccessor : null; + + return probeType.IsGenericType ? ResolveByNullableType(probeType) : ResolveByType(probeType); + } + } + private delegate void CounterIncrementer(ref ValCounters valCounters); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); - private static readonly ObjectFieldAccessor ObjectAccessor; - private static readonly Dictionary ValueAccessors; + private static readonly ObjectFieldAccessor ObjectAccessor = new ObjectFieldAccessor(); private static readonly CounterIncrementer[] IncrementerByRank; private static readonly PositionUpdater[] PositionUpdaterByRank; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ConfigureFieldAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => - descriptor.Accessor = ValueAccessors.TryGetValue(fieldType, out var valueAccessor) - ? (PackedFieldAccessor) valueAccessor - : ObjectAccessor; + descriptor.Accessor = (PackedFieldAccessor) ValueFieldAccessorResolver.GetValue(fieldType) ?? ObjectAccessor; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, @@ -129,13 +214,14 @@ private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descripto } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConfigureFieldPhase1( - ref PackedFieldDescriptor descriptor, ref ValCounters counters, Type[] fieldTypes, int fieldIndex) + private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + Type[] fieldTypes, int fieldIndex) { descriptor.StateIndex = fieldIndex >> Val032Rank; // d.FieldIndex / 32 descriptor.StateBitOffset = (fieldIndex & Modulo032RemainderMask) << 1; - if (ValueAccessors.TryGetValue(fieldTypes[fieldIndex], out var valueAccessor)) { + var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[fieldIndex]); + if (valueAccessor != null) { descriptor.Accessor = valueAccessor; descriptor.PackingType = FieldPackingType.Value; descriptor.Rank = valueAccessor.Rank; @@ -164,31 +250,6 @@ private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, r static TupleLayout() { - void RegisterAccessor(ValueFieldAccessor accessor) - where T : struct, IEquatable - { - ValueAccessors.Add(typeof(T), accessor); - ValueAccessors.Add(typeof(T?), accessor); - } - - ObjectAccessor = new ObjectFieldAccessor(); - ValueAccessors = new Dictionary(); - RegisterAccessor(new BooleanFieldAccessor()); - RegisterAccessor(new ByteFieldAccessor()); - RegisterAccessor(new SByteFieldAccessor()); - RegisterAccessor(new ShortFieldAccessor()); - RegisterAccessor(new UShortFieldAccessor()); - RegisterAccessor(new IntFieldAccessor()); - RegisterAccessor(new UIntFieldAccessor()); - RegisterAccessor(new LongFieldAccessor()); - RegisterAccessor(new ULongFieldAccessor()); - RegisterAccessor(new FloatFieldAccessor()); - RegisterAccessor(new DoubleFieldAccessor()); - RegisterAccessor(new DateTimeFieldAccessor()); - RegisterAccessor(new TimeSpanFieldAccessor()); - RegisterAccessor(new DecimalFieldAccessor()); - RegisterAccessor(new GuidFieldAccessor()); - IncrementerByRank = new CounterIncrementer[] { (ref ValCounters valueCounters) => valueCounters.Val001Counter++, (ref ValCounters valueCounters) => throw new NotSupportedException(), From 337191f1f81adf78a056b54e5d7b809983bd8d12 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 17:01:59 -0700 Subject: [PATCH 20/31] Make TupleDescriptor IReadonlyList instead of IList --- Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs | 2 +- Orm/Xtensive.Orm/Tuples/Tuple.cs | 2 +- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 67 +++------------------- Orm/Xtensive.Orm/Tuples/TupleExtensions.cs | 2 +- 4 files changed, 10 insertions(+), 63 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs b/Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs index 2cff1537ae..21a91307ad 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs @@ -31,7 +31,7 @@ public OwnerWrapper(TOwner owner) } } - public static Expression> BuildFilterLambda(int startIndex, IList keyColumnTypes, Parameter keyParameter) + public static Expression> BuildFilterLambda(int startIndex, IReadOnlyList keyColumnTypes, Parameter keyParameter) { Expression filterExpression = null; var tupleParameter = Expression.Parameter(typeof (Tuple), "tuple"); diff --git a/Orm/Xtensive.Orm/Tuples/Tuple.cs b/Orm/Xtensive.Orm/Tuples/Tuple.cs index 662aaaa183..3c1b206657 100644 --- a/Orm/Xtensive.Orm/Tuples/Tuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Tuple.cs @@ -38,7 +38,7 @@ public abstract class Tuple : ITuple, IEquatable public virtual int Count { [DebuggerStepThrough] - get { return Descriptor.FieldCount; } + get { return Descriptor.Count; } } /// diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index f103f9d9ac..cc66d5e442 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -4,18 +4,16 @@ // Created by: Nick Svetlov // Created: 2007.05.30 + using System; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Runtime.Serialization; using System.Text; using Xtensive.Core; using Xtensive.Linq.SerializableExpressions.Internals; using Xtensive.Reflection; - using Xtensive.Tuples.Packed; namespace Xtensive.Tuples @@ -25,11 +23,11 @@ namespace Xtensive.Tuples /// Provides information about structure. /// [Serializable] - public sealed class TupleDescriptor : IEquatable, IList, IReadOnlyList, ISerializable + public sealed class TupleDescriptor : IEquatable, IReadOnlyList, ISerializable { private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(Array.Empty()); - internal readonly int FieldCount; + private readonly int FieldCount; internal readonly int ValuesLength; internal readonly int ObjectsLength; @@ -37,7 +35,7 @@ public sealed class TupleDescriptor : IEquatable, IList, internal readonly PackedFieldDescriptor[] FieldDescriptors; [field: NonSerialized] - internal Type[] FieldTypes { get; } + private Type[] FieldTypes { get; } /// /// Gets the empty tuple descriptor. @@ -91,63 +89,12 @@ public int Count get => FieldCount; } - /// - public int IndexOf(Type item) - => FieldTypes.IndexOf(item, true); - - /// - public void Insert(int index, Type item) - { - throw Exceptions.CollectionIsReadOnly(null); - } - - /// - public void RemoveAt(int index) - { - throw Exceptions.CollectionIsReadOnly(null); - } - - /// - public void Add(Type item) - { - throw Exceptions.CollectionIsReadOnly(null); - } - - /// - public void Clear() - { - throw Exceptions.CollectionIsReadOnly(null); - } - - /// - public bool Contains(Type item) - { - return FieldTypes.IndexOf(item, true) >= 0; - } - - /// - public void CopyTo(Type[] array, int arrayIndex) - { - FieldTypes.Copy(array, arrayIndex); - } - - /// - public bool Remove(Type item) - { - throw Exceptions.CollectionIsReadOnly(null); - } - - /// - public bool IsReadOnly - { - get { return true; } - } - /// public IEnumerator GetEnumerator() { - for (int i = 0; i < FieldCount; i++) - yield return FieldTypes[i]; + for (var index = 0; index < FieldCount; index++) { + yield return FieldTypes[index]; + } } /// diff --git a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs index 33bb483fc0..fa46d55451 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs @@ -206,7 +206,7 @@ public static Tuple GetSegment(this Tuple tuple, Segment segment) for (var index = 0; index < map.Length; index++) { var sourceIndex = segment.Offset + index; map[index] = sourceIndex; - fieldTypes[index] = tuple.Descriptor.FieldTypes[sourceIndex]; + fieldTypes[index] = tuple.Descriptor[sourceIndex]; } var descriptor = TupleDescriptor.Create(fieldTypes); var transform = new MapTransform(false, descriptor, map); From ec1fe114088db03950a85fa2af4647941c64d9bc Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 17:04:50 -0700 Subject: [PATCH 21/31] Make separate configuration methods for descriptors of length 1 and 2 --- .../Tuples/Packed/FieldPackingType.cs | 4 +- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 105 ++++++++++++++---- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 21 +++- 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/FieldPackingType.cs b/Orm/Xtensive.Orm/Tuples/Packed/FieldPackingType.cs index 7acbb07fda..738c731729 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/FieldPackingType.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/FieldPackingType.cs @@ -8,7 +8,7 @@ namespace Xtensive.Tuples.Packed { internal enum FieldPackingType { - Object, - Value, + Object = 0, + Value = 1 } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 3cf7f4bd91..4bd33fa5b3 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2012 Xtensive LLC. +// Copyright (C) 2003-2012 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Denis Krjuchkov @@ -152,6 +152,73 @@ ValueFieldAccessor ResolveByNullableType(Type type) => public static void ConfigureFieldAccessor(ref PackedFieldDescriptor descriptor, Type fieldType) => descriptor.Accessor = (PackedFieldAccessor) ValueFieldAccessorResolver.GetValue(fieldType) ?? ObjectAccessor; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ConfigureLen1(Type[] fieldTypes, ref PackedFieldDescriptor descriptor, out int valuesLength, + out int objectsLength) + { + var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[0]); + if (valueAccessor != null) { + descriptor.Accessor = valueAccessor; + descriptor.PackingType = FieldPackingType.Value; + descriptor.Rank = valueAccessor.Rank; + descriptor.ValueIndex = 1; + + var valBitCount = 1 << valueAccessor.Rank; + valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + objectsLength = 0; + fieldTypes[0] = valueAccessor.FieldType; + return; + } + + descriptor.Accessor = ObjectAccessor; + valuesLength = 1; + objectsLength = 1; + } + + public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor descriptor1, + ref PackedFieldDescriptor descriptor2, out int valuesLength, out int objectsLength) + { + var valCounters = new ValCounters(); + ConfigureFieldPhase1(ref descriptor1, ref valCounters, fieldTypes, 0); + ConfigureFieldPhase1(ref descriptor2, ref valCounters, fieldTypes, 1); + objectsLength = valCounters.ObjectCounter; + int valBitCount; + switch (objectsLength) { + case 2: + valuesLength = 1; + return; + case 1: { + if (descriptor2.PackingType == FieldPackingType.Value) { + descriptor2.ValueIndex = 1; + valBitCount = 1 << descriptor2.Rank; + } + else { + descriptor1.ValueIndex = 1; + valBitCount = 1 << descriptor1.Rank; + } + valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + return; + } + } + // Both descriptors are value descriptors + int rank1 = descriptor1.Rank, rank2 = descriptor2.Rank; + if (rank2 > rank1) { + descriptor2.ValueIndex = 1; + valBitCount = 1 << rank2; + descriptor1.ValueIndex = 1 + (valBitCount >> Val064Rank); + descriptor1.ValueBitOffset = valBitCount & Modulo064RemainderMask; + valBitCount += 1 << rank1; + } + else { + descriptor1.ValueIndex = 1; + valBitCount = 1 << rank1; + descriptor2.ValueIndex = 1 + (valBitCount >> Val064Rank); + descriptor2.ValueBitOffset = valBitCount & Modulo064RemainderMask; + valBitCount += 1 << rank2; + } + valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, out int objectsLength) @@ -165,36 +232,29 @@ public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDes const int stateBitCount = 2; const int statesPerLong = Val064BitCount / stateBitCount; - var valPointers = new ValPointers { - Val128Pointer = new ValPointer { - Index = (fieldCount + (statesPerLong - 1)) / statesPerLong, - Offset = 0 - } + var vPointers = new ValPointers { + Val128Pointer = new ValPointer {Index = (fieldCount + (statesPerLong - 1)) >> Val032Rank} }; - InitValPointer(ref valPointers.Val064Pointer, ref valPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); - InitValPointer(ref valPointers.Val032Pointer, ref valPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); - InitValPointer(ref valPointers.Val016Pointer, ref valPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); - InitValPointer(ref valPointers.Val008Pointer, ref valPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); - InitValPointer(ref valPointers.Val001Pointer, ref valPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); + InitValPointer(ref vPointers.Val064Pointer, ref vPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); + InitValPointer(ref vPointers.Val032Pointer, ref vPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); + InitValPointer(ref vPointers.Val016Pointer, ref vPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); + InitValPointer(ref vPointers.Val008Pointer, ref vPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); + InitValPointer(ref vPointers.Val001Pointer, ref vPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); var valuesEndPointer = new ValPointer(); - InitValPointer(ref valuesEndPointer, ref valPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); - - const int max032Shift = Val032BitCount - 1; - // Expression ((N - 1) >> max032Shift) evaluates to 0 for all N > 0; for N <= 0 it evaluates to -1 - // This means we add one element to values array if Offset is positive; otherwise we don't - valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset - 1) >> max032Shift) + 1; - - objectsLength = valCounters.ObjectCounter; + InitValPointer(ref valuesEndPointer, ref vPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref valPointers); + ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref vPointers); } + + valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset + (Val064BitCount - 1)) >> Val064Rank); + objectsLength = valCounters.ObjectCounter; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InitValPointer( - ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, int prevRank) + private static void InitValPointer(ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, + int prevRank) { var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; @@ -233,7 +293,6 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r } descriptor.Accessor = ObjectAccessor; - descriptor.PackingType = FieldPackingType.Object; descriptor.ValueIndex = counters.ObjectCounter++; } diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index cc66d5e442..8247a3e8e6 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -313,13 +313,28 @@ public static TupleDescriptor Create() private TupleDescriptor(Type[] fieldTypes) { - ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); - FieldTypes = fieldTypes; FieldCount = fieldTypes.Length; FieldDescriptors = new PackedFieldDescriptor[FieldCount]; - TupleLayout.Configure(fieldTypes, FieldDescriptors, out ValuesLength, out ObjectsLength); + switch (FieldCount) { + case 0: + return; + case 1: + TupleLayout.ConfigureLen1(FieldTypes, + ref FieldDescriptors[0], + out ValuesLength, out ObjectsLength); + break; + case 2: + TupleLayout.ConfigureLen2(FieldTypes, + ref FieldDescriptors[0], ref FieldDescriptors[1], + out ValuesLength, out ObjectsLength); + break; + default: + TupleLayout.Configure(FieldTypes, FieldDescriptors, out ValuesLength, out ObjectsLength); + break; + } + } public TupleDescriptor(SerializationInfo info, StreamingContext context) From a865d162490ab67839e86a7dadbd1a1a674b0d83 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 17:05:47 -0700 Subject: [PATCH 22/31] TupleDescriptor code cleanup --- Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs | 49 +--------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index 8247a3e8e6..abc91cdcd1 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -47,32 +47,6 @@ public static TupleDescriptor Empty get => EmptyDescriptor; } - /// - /// Gets the length of the common part. - /// - /// The other descriptor. - public int GetCommonPartLength(TupleDescriptor other) - { - ArgumentValidator.EnsureArgumentNotNull(other, "other"); - var minCount = FieldCount < other.FieldCount ? FieldCount : other.FieldCount; - for (int i = 0; i < minCount; i++) { - if (FieldTypes[i] != other.FieldTypes[i]) - return i; - } - return minCount; - } - - /// - /// Determines whether the specified field is a value type field. - /// - /// Index of the field to check. - /// - /// if specified field is a value type field; - /// otherwise, . - /// - public bool IsValueType(int fieldIndex) - => FieldTypes[fieldIndex].IsValueType; - #region IList members /// @@ -138,7 +112,7 @@ public override int GetHashCode() return result; } - public static bool operator==(TupleDescriptor left, TupleDescriptor right) + public static bool operator ==(TupleDescriptor left, TupleDescriptor right) { if (ReferenceEquals(left, right)) return true; @@ -180,24 +154,6 @@ public override string ToString() return string.Format(Strings.TupleDescriptorFormat, sb); } - //[OnSerializing] - //private void OnSerializing(StreamingContext context) - //{ - // fieldTypeNames = new string[FieldTypes.Length]; - // for (var i = 0; i < fieldTypeNames.Length; i++) - // fieldTypeNames[i] = FieldTypes[i].ToSerializableForm(); - //} - - //[OnDeserialized] - //private void OnDeserialized(StreamingContext context) - //{ - // fieldTypes = new Type[fieldTypeNames.Length]; - // for (int i = 0; i < fieldTypeNames.Length; i++) - // FieldTypes[i] = fieldTypeNames[i].GetTypeFromSerializableForm(); - // for (int i = 0; i < FieldCount; i++) - // PackedFieldAccessorFactory.ProvideAccessor(FieldTypes[i], FieldDescriptors[i]); - //} - #region Create methods (base) public static TupleDescriptor Create(Type t1) @@ -230,8 +186,7 @@ public static TupleDescriptor Create(Type t1, Type t2, Type t3, Type t4) public static TupleDescriptor Create(Type[] fieldTypes) { ArgumentValidator.EnsureArgumentNotNull(fieldTypes, nameof(fieldTypes)); - switch (fieldTypes.Length) { - case 0: + if (fieldTypes.Length == 0) { return EmptyDescriptor; } return new TupleDescriptor(fieldTypes); From 38f1efc7aa25fa2e96718de62d44adb9bd15dff5 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 30 Mar 2020 16:09:13 -0700 Subject: [PATCH 23/31] Use MetadataToken to detect if type is nullable (this is a little bit faster than IsGeneric) --- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 4bd33fa5b3..43099ce11b 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -100,6 +100,8 @@ private static class ValueFieldAccessorResolver private static readonly ValueFieldAccessor DecimalAccessor = new DecimalFieldAccessor(); private static readonly ValueFieldAccessor GuidAccessor = new GuidFieldAccessor(); + private static readonly int NullableTypeMetadataToken = typeof(Nullable<>).MetadataToken; + public static ValueFieldAccessor GetValue(Type probeType) { ValueFieldAccessor ResolveByType(Type type) => @@ -136,7 +138,9 @@ ValueFieldAccessor ResolveByNullableType(Type type) => ReferenceEquals(type, NullableDecimalType) ? DecimalAccessor : ReferenceEquals(type, NullableGuidType) ? GuidAccessor : null; - return probeType.IsGenericType ? ResolveByNullableType(probeType) : ResolveByType(probeType); + return (probeType.MetadataToken ^ NullableTypeMetadataToken)==0 + ? ResolveByNullableType(probeType) + : ResolveByType(probeType); } } From 8bf9e1fce9766bbff4726c36a4cf2c7e0b81ca96 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 17:42:17 -0700 Subject: [PATCH 24/31] Move Rank, ValueBitCount and ValueBitMask properties to Accessor to simplify PackedFieldDescriptor implementation --- .../Tuples/Packed/PackedFieldAccessor.cs | 50 +++++++++---- .../Tuples/Packed/PackedFieldDescriptor.cs | 72 +++++-------------- Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs | 4 +- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 66 +++++++---------- 4 files changed, 85 insertions(+), 107 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index 2e6121b0bd..63c6cc81b5 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -30,6 +30,10 @@ internal abstract class PackedFieldAccessor /// protected Delegate NullableSetter; + public readonly int Rank; + public readonly int ValueBitCount; + protected readonly long ValueBitMask; + public void SetValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, bool isNullable, T value) { var setter = (isNullable ? NullableSetter : Setter) as SetValueDelegate; @@ -65,6 +69,25 @@ public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor lef PackedTuple right, ref PackedFieldDescriptor rightDescriptor); public abstract int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor); + + protected PackedFieldAccessor(int rank) + { + Rank = rank; + ValueBitCount = 1 << Rank; + + // What we want here is to shift 1L by ValueBitCount to left and then subtract 1 + // This gives us a mask. For example if bit count = 4 then + // 0000_0001 << 4 = 0001_0000 + // 0001_000 - 1 = 0000_1111 + // However in case bit count equal to data type size left shift doesn't work as we want + // e.g. for Int8 : 0000_0001 << 8 = 0000_0001 but we would like it to be 0000_0000 + // because 0000_0000 - 1 = 1111_1111 and this is exactly what we need. + // As a workaround we do left shift in two steps. In the example above + // 0000_0001 << 7 = 1000_0000 + // and then + // 1000_0000 << 1 = 0000_0000 + ValueBitMask = (1L << (ValueBitCount - 1) << 1) - 1; + } } internal sealed class ObjectFieldAccessor : PackedFieldAccessor @@ -73,12 +96,12 @@ public override object GetUntypedValue(PackedTuple tuple, ref PackedFieldDescrip { var state = tuple.GetFieldState(ref descriptor); fieldState = state; - return state==TupleFieldState.Available ? tuple.Objects[descriptor.ValueIndex] : null; + return state==TupleFieldState.Available ? tuple.Objects[descriptor.ObjectIndex] : null; } public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescriptor descriptor, object value) { - tuple.Objects[descriptor.ValueIndex] = value; + tuple.Objects[descriptor.ObjectIndex] = value; if (value!=null) tuple.SetFieldState(ref descriptor, TupleFieldState.Available); else @@ -88,27 +111,29 @@ public override void SetUntypedValue(PackedTuple tuple, ref PackedFieldDescripto public override void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, PackedTuple target, ref PackedFieldDescriptor targetDescriptor) { - target.Objects[targetDescriptor.ValueIndex] = source.Objects[sourceDescriptor.ValueIndex]; + target.Objects[targetDescriptor.ObjectIndex] = source.Objects[sourceDescriptor.ObjectIndex]; } public override bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor, PackedTuple right, ref PackedFieldDescriptor rightDescriptor) { - var leftValue = left.Objects[leftDescriptor.ValueIndex]; - var rightValue = right.Objects[rightDescriptor.ValueIndex]; + var leftValue = left.Objects[leftDescriptor.ObjectIndex]; + var rightValue = right.Objects[rightDescriptor.ObjectIndex]; return leftValue.Equals(rightValue); } public override int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor) { - return tuple.Objects[descriptor.ValueIndex].GetHashCode(); + return tuple.Objects[descriptor.ObjectIndex].GetHashCode(); } + + public ObjectFieldAccessor() + : base(-1) + { } } internal abstract class ValueFieldAccessor : PackedFieldAccessor { - public readonly int Rank; - public Type FieldType { get; protected set; } private static int GetRank(int bitSize) @@ -122,9 +147,8 @@ private static int GetRank(int bitSize) } protected ValueFieldAccessor(int bitCount) - { - Rank = GetRank(bitCount); - } + : base(GetRank(bitCount)) + {} } internal abstract class ValueFieldAccessor : ValueFieldAccessor @@ -217,7 +241,7 @@ private void Store(PackedTuple tuple, ref PackedFieldDescriptor d, T value) var encoded = Encode(value); var block = tuple.Values[d.ValueIndex]; - var mask = d.ValueBitMask << d.ValueBitOffset; + var mask = ValueBitMask << d.ValueBitOffset; tuple.Values[d.ValueIndex] = (block & ~mask) | ((encoded << d.ValueBitOffset) & mask); } @@ -227,7 +251,7 @@ private T Load(PackedTuple tuple, ref PackedFieldDescriptor d) return Decode(tuple.Values, d.ValueIndex); } - var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & d.ValueBitMask; + var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & ValueBitMask; return Decode(encoded); } diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index f11738b391..1cefc08e1e 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -5,76 +5,42 @@ // Created: 2012.12.29 using System; +using System.Runtime.CompilerServices; namespace Xtensive.Tuples.Packed { [Serializable] internal struct PackedFieldDescriptor { - private const int IndexBitCount = 20; - private const int IndexMask = (1 << IndexBitCount) - 1; - private const int OffsetBitCount = 7; - private const int OffsetMask = ((1 << OffsetBitCount) - 1) << IndexBitCount; + private const int OffsetBitCount = 6; + private const int OffsetMask = (1 << OffsetBitCount) - 1; - private const int MaskBitCount = (sizeof(int) * 8) - (IndexBitCount + OffsetBitCount); - private const int GetValueMask = (1 << MaskBitCount) - 1; - private const int SetValueMask = GetValueMask << (IndexBitCount + OffsetBitCount); - - private int data1; - private int data2; + private int indexField; + private int stateField; [NonSerialized] public PackedFieldAccessor Accessor; - public int ValueIndex - { - get => data1 & IndexMask; - set => data1 = (data1 & ~IndexMask) | (value & IndexMask); - } + public bool IsObjectField => Accessor.Rank < 0; - public int ValueBitOffset + public int ObjectIndex { - get => (data1 & OffsetMask) >> IndexBitCount; - set => data1 = (data1 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask); + get => indexField; + set => indexField = value; } - public int Rank - { - get => (data1 >> (IndexBitCount + OffsetBitCount)) & GetValueMask; - set => data1 = (data1 & ~SetValueMask) | ((value << (IndexBitCount + OffsetBitCount)) & SetValueMask); - } + public int ValueIndex => indexField >> OffsetBitCount; + public int ValueBitOffset => indexField & OffsetMask; - public int ValueBitCount => 1 << Rank; + public int StateIndex => stateField >> OffsetBitCount; + public int StateBitOffset => stateField & OffsetMask; - // What we want here is to shift 1L by ValueBitCount to left and then subtract 1 - // This gives us a mask. For example if bit count = 4 then - // 0000_0001 << 4 = 0001_0000 - // 0001_000 - 1 = 0000_1111 - // However in case bit count equal to data type size left shift doesn't work as we want - // e.g. for Int8 : 0000_0001 << 8 = 0000_0001 but we would like it to be 0000_0000 - // because 0000_0000 - 1 = 1111_1111 and this is exactly what we need. - // As a workaround we do left shift in two steps. In the example above - // 0000_0001 << 7 = 1000_0000 - // and then - // 1000_0000 << 1 = 0000_0000 - public long ValueBitMask => (1L << (ValueBitCount - 1) << 1) - 1; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetValueBitOffset(int totalBitOffset) + => indexField = totalBitOffset; - public int StateIndex - { - get => data2 & IndexMask; - set => data2 = (data2 & ~IndexMask) | (value & IndexMask); - } - - public int StateBitOffset - { - get => (data2 & OffsetMask) >> IndexBitCount; - set => data2 = (data2 & ~OffsetMask) | ((value << IndexBitCount) & OffsetMask); - } - - public FieldPackingType PackingType - { - get => (FieldPackingType)((data2 >> (IndexBitCount + OffsetBitCount)) & GetValueMask); - set => data2 = (data2 & ~SetValueMask) | (((int)value << (IndexBitCount + OffsetBitCount)) & SetValueMask); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateTotalBitOffset(int stateBitOffset) + => stateField = stateBitOffset; } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs index 4d0f1ab79c..7f615636ed 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs @@ -108,8 +108,8 @@ public void SetFieldState(ref PackedFieldDescriptor d, TupleFieldState fieldStat var block = Values[d.StateIndex]; Values[d.StateIndex] = (block & ~(3L << d.StateBitOffset)) | (bits << d.StateBitOffset); - if (fieldState!=TupleFieldState.Available && d.PackingType==FieldPackingType.Object) { - Objects[d.ValueIndex] = null; + if (fieldState!=TupleFieldState.Available && d.IsObjectField) { + Objects[d.ObjectIndex] = null; } } diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 43099ce11b..f911ae09ab 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2012 Xtensive LLC. +// Copyright (C) 2003-2012 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Denis Krjuchkov @@ -163,12 +163,9 @@ public static void ConfigureLen1(Type[] fieldTypes, ref PackedFieldDescriptor de var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[0]); if (valueAccessor != null) { descriptor.Accessor = valueAccessor; - descriptor.PackingType = FieldPackingType.Value; - descriptor.Rank = valueAccessor.Rank; - descriptor.ValueIndex = 1; + descriptor.SetValueBitOffset(Val064BitCount); - var valBitCount = 1 << valueAccessor.Rank; - valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + valuesLength = ((1 << valueAccessor.Rank) + ((Val064BitCount * 2) - 1)) >> Val064Rank; objectsLength = 0; fieldTypes[0] = valueAccessor.FieldType; return; @@ -186,41 +183,36 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de ConfigureFieldPhase1(ref descriptor1, ref valCounters, fieldTypes, 0); ConfigureFieldPhase1(ref descriptor2, ref valCounters, fieldTypes, 1); objectsLength = valCounters.ObjectCounter; - int valBitCount; + int val1BitCount, val2BitCount; switch (objectsLength) { case 2: valuesLength = 1; return; case 1: { - if (descriptor2.PackingType == FieldPackingType.Value) { - descriptor2.ValueIndex = 1; - valBitCount = 1 << descriptor2.Rank; + if (descriptor1.IsObjectField) { + descriptor2.SetValueBitOffset(Val064BitCount); + val1BitCount = descriptor2.Accessor.ValueBitCount; } else { - descriptor1.ValueIndex = 1; - valBitCount = 1 << descriptor1.Rank; + descriptor1.SetValueBitOffset(Val064BitCount); + val1BitCount = descriptor1.Accessor.ValueBitCount; } - valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + valuesLength = 1 + ((val1BitCount + (Val064BitCount - 1)) >> Val064Rank); return; } } // Both descriptors are value descriptors - int rank1 = descriptor1.Rank, rank2 = descriptor2.Rank; - if (rank2 > rank1) { - descriptor2.ValueIndex = 1; - valBitCount = 1 << rank2; - descriptor1.ValueIndex = 1 + (valBitCount >> Val064Rank); - descriptor1.ValueBitOffset = valBitCount & Modulo064RemainderMask; - valBitCount += 1 << rank1; + val1BitCount = descriptor1.Accessor.ValueBitCount; + val2BitCount = descriptor2.Accessor.ValueBitCount; + if (val2BitCount > val1BitCount) { + descriptor2.SetValueBitOffset(Val064BitCount); + descriptor1.SetValueBitOffset(Val064BitCount + val2BitCount); } else { - descriptor1.ValueIndex = 1; - valBitCount = 1 << rank1; - descriptor2.ValueIndex = 1 + (valBitCount >> Val064Rank); - descriptor2.ValueBitOffset = valBitCount & Modulo064RemainderMask; - valBitCount += 1 << rank2; + descriptor1.SetValueBitOffset(Val064BitCount); + descriptor2.SetValueBitOffset(Val064BitCount + val1BitCount); } - valuesLength = 1 + ((valBitCount + (Val064BitCount - 1)) >> Val064Rank); + valuesLength = (val1BitCount + val2BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -269,26 +261,22 @@ private static void InitValPointer(ref ValPointer pointer, ref ValPointer prevPo [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) { - descriptor.ValueIndex = valPointer.Index; - descriptor.ValueBitOffset = valPointer.Offset; - - var increasedOffset = valPointer.Offset + descriptor.ValueBitCount; - valPointer.Index += increasedOffset >> Val064Rank; - valPointer.Offset = increasedOffset & Modulo064RemainderMask; + var totalBitCount = (valPointer.Index << Val064Rank) + valPointer.Offset; + descriptor.SetValueBitOffset(totalBitCount); + totalBitCount += descriptor.Accessor.ValueBitCount; + valPointer.Index = totalBitCount >> Val064Rank; + valPointer.Offset = totalBitCount & Modulo064RemainderMask; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref ValCounters counters, Type[] fieldTypes, int fieldIndex) { - descriptor.StateIndex = fieldIndex >> Val032Rank; // d.FieldIndex / 32 - descriptor.StateBitOffset = (fieldIndex & Modulo032RemainderMask) << 1; + descriptor.SetStateTotalBitOffset(fieldIndex << 1); var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[fieldIndex]); if (valueAccessor != null) { descriptor.Accessor = valueAccessor; - descriptor.PackingType = FieldPackingType.Value; - descriptor.Rank = valueAccessor.Rank; IncrementerByRank[valueAccessor.Rank].Invoke(ref counters); @@ -297,18 +285,18 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r } descriptor.Accessor = ObjectAccessor; - descriptor.ValueIndex = counters.ObjectCounter++; + descriptor.ObjectIndex = counters.ObjectCounter++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) { - if (descriptor.PackingType == FieldPackingType.Object) { + if (descriptor.IsObjectField) { return; } // d.PackingType == FieldPackingType.Value - PositionUpdaterByRank[descriptor.Rank].Invoke(ref descriptor, ref valPointers); + PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref valPointers); } static TupleLayout() From 4bb6b2ba188e2b28219f67893d5a5440eee34dda Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 17:43:17 -0700 Subject: [PATCH 25/31] Get rid of ValuePointer structure to improve performance # Conflicts: # Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs --- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 80 +++++++++---------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index f911ae09ab..2ce6c6e4fd 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2012 Xtensive LLC. +// Copyright (C) 2003-2012 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Denis Krjuchkov @@ -16,27 +16,20 @@ internal static class TupleLayout private const int Val032Rank = 5; private const int Val016Rank = 4; private const int Val008Rank = 3; - private const int Val001Rank = 0; private const int Val064BitCount = 1 << Val064Rank; private const int Val032BitCount = 1 << Val032Rank; private const int Modulo064RemainderMask = Val064BitCount - 1; private const int Modulo032RemainderMask = Val032BitCount - 1; - private ref struct ValPointer - { - public int Index; - public int Offset; - } - private ref struct ValPointers { - public ValPointer Val001Pointer; - public ValPointer Val008Pointer; - public ValPointer Val016Pointer; - public ValPointer Val032Pointer; - public ValPointer Val064Pointer; - public ValPointer Val128Pointer; + public int Val001Pointer; + public int Val008Pointer; + public int Val016Pointer; + public int Val032Pointer; + public int Val064Pointer; + public int Val128Pointer; } private ref struct ValCounters @@ -197,7 +190,7 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de descriptor1.SetValueBitOffset(Val064BitCount); val1BitCount = descriptor1.Accessor.ValueBitCount; } - valuesLength = 1 + ((val1BitCount + (Val064BitCount - 1)) >> Val064Rank); + valuesLength = (val1BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; return; } } @@ -219,53 +212,56 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, out int objectsLength) { - var valCounters = new ValCounters(); var fieldCount = fieldTypes.Length; + const int statesPerLong = Val064BitCount / 2; + var stateBitCount = ((fieldCount + (statesPerLong - 1)) >> Val032Rank) << Val064Rank; + + var valCounters = new ValCounters(); for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref valCounters, fieldTypes, fieldIndex); } - const int stateBitCount = 2; - const int statesPerLong = Val064BitCount / stateBitCount; - - var vPointers = new ValPointers { - Val128Pointer = new ValPointer {Index = (fieldCount + (statesPerLong - 1)) >> Val032Rank} - }; - InitValPointer(ref vPointers.Val064Pointer, ref vPointers.Val128Pointer, valCounters.Val128Counter, Val128Rank); - InitValPointer(ref vPointers.Val032Pointer, ref vPointers.Val064Pointer, valCounters.Val064Counter, Val064Rank); - InitValPointer(ref vPointers.Val016Pointer, ref vPointers.Val032Pointer, valCounters.Val032Counter, Val032Rank); - InitValPointer(ref vPointers.Val008Pointer, ref vPointers.Val016Pointer, valCounters.Val016Counter, Val016Rank); - InitValPointer(ref vPointers.Val001Pointer, ref vPointers.Val008Pointer, valCounters.Val008Counter, Val008Rank); - - var valuesEndPointer = new ValPointer(); - InitValPointer(ref valuesEndPointer, ref vPointers.Val001Pointer, valCounters.Val001Counter, Val001Rank); + var vPointers = new ValPointers(); + var totalBitCount = InitValPointers(stateBitCount, ref valCounters, ref vPointers); for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref vPointers); } - valuesLength = valuesEndPointer.Index + ((valuesEndPointer.Offset + (Val064BitCount - 1)) >> Val064Rank); + valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; objectsLength = valCounters.ObjectCounter; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void InitValPointer(ref ValPointer pointer, ref ValPointer prevPointer, int prevValueCount, - int prevRank) + private static int InitValPointers(int stateBitCount, ref ValCounters valCounters, ref ValPointers vPointers) { - var prevBitCountWithOffset = (prevValueCount << prevRank) + prevPointer.Offset; + var totalBitCount = stateBitCount; + vPointers.Val128Pointer = totalBitCount; + + totalBitCount += valCounters.Val128Counter << Val128Rank; + vPointers.Val064Pointer = totalBitCount; + + totalBitCount += valCounters.Val064Counter << Val064Rank; + vPointers.Val032Pointer = totalBitCount; + + totalBitCount += valCounters.Val032Counter << Val032Rank; + vPointers.Val016Pointer = totalBitCount; + + totalBitCount += valCounters.Val016Counter << Val016Rank; + vPointers.Val008Pointer = totalBitCount; + + totalBitCount += valCounters.Val008Counter << Val008Rank; + vPointers.Val001Pointer = totalBitCount; - pointer.Index = prevPointer.Index + (prevBitCountWithOffset >> Val064Rank); - pointer.Offset = prevBitCountWithOffset & Modulo064RemainderMask; + totalBitCount += valCounters.Val001Counter; + return totalBitCount; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref ValPointer valPointer) + private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref int valPointer) { - var totalBitCount = (valPointer.Index << Val064Rank) + valPointer.Offset; - descriptor.SetValueBitOffset(totalBitCount); - totalBitCount += descriptor.Accessor.ValueBitCount; - valPointer.Index = totalBitCount >> Val064Rank; - valPointer.Offset = totalBitCount & Modulo064RemainderMask; + descriptor.SetValueBitOffset(valPointer); + valPointer += descriptor.Accessor.ValueBitCount; } [MethodImpl(MethodImplOptions.AggressiveInlining)] From bb7a67c536b60f2b7e18c3e7dc47abf66de7373b Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Tue, 31 Mar 2020 21:53:19 -0700 Subject: [PATCH 26/31] Get rid of ValuePointerS structure to decrease stack allocation size and to improve performance --- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 100 ++++++++---------- 1 file changed, 42 insertions(+), 58 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 2ce6c6e4fd..569042edc2 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -18,19 +18,6 @@ internal static class TupleLayout private const int Val008Rank = 3; private const int Val064BitCount = 1 << Val064Rank; - private const int Val032BitCount = 1 << Val032Rank; - private const int Modulo064RemainderMask = Val064BitCount - 1; - private const int Modulo032RemainderMask = Val032BitCount - 1; - - private ref struct ValPointers - { - public int Val001Pointer; - public int Val008Pointer; - public int Val016Pointer; - public int Val032Pointer; - public int Val064Pointer; - public int Val128Pointer; - } private ref struct ValCounters { @@ -139,7 +126,7 @@ ValueFieldAccessor ResolveByNullableType(Type type) => private delegate void CounterIncrementer(ref ValCounters valCounters); - private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValCounters valCounters); private static readonly ObjectFieldAccessor ObjectAccessor = new ObjectFieldAccessor(); private static readonly CounterIncrementer[] IncrementerByRank; @@ -213,48 +200,45 @@ public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDes out int objectsLength) { var fieldCount = fieldTypes.Length; - const int statesPerLong = Val064BitCount / 2; - var stateBitCount = ((fieldCount + (statesPerLong - 1)) >> Val032Rank) << Val064Rank; - var valCounters = new ValCounters(); for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref valCounters, fieldTypes, fieldIndex); } - var vPointers = new ValPointers(); - var totalBitCount = InitValPointers(stateBitCount, ref valCounters, ref vPointers); + const int statesPerLong = Val064BitCount / 2; - for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref vPointers); - } + var totalBitCount = ((fieldCount + (statesPerLong - 1)) >> Val032Rank) << Val064Rank; + var prevCount = valCounters.Val128Counter; + valCounters.Val128Counter = totalBitCount; - valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; - objectsLength = valCounters.ObjectCounter; - } + totalBitCount += prevCount << Val128Rank; + prevCount = valCounters.Val064Counter; + valCounters.Val064Counter = totalBitCount; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int InitValPointers(int stateBitCount, ref ValCounters valCounters, ref ValPointers vPointers) - { - var totalBitCount = stateBitCount; - vPointers.Val128Pointer = totalBitCount; + totalBitCount += prevCount << Val064Rank; + prevCount = valCounters.Val032Counter; + valCounters.Val032Counter = totalBitCount; - totalBitCount += valCounters.Val128Counter << Val128Rank; - vPointers.Val064Pointer = totalBitCount; + totalBitCount += prevCount << Val032Rank; + prevCount = valCounters.Val016Counter; + valCounters.Val016Counter = totalBitCount; - totalBitCount += valCounters.Val064Counter << Val064Rank; - vPointers.Val032Pointer = totalBitCount; + totalBitCount += prevCount << Val016Rank; + prevCount = valCounters.Val008Counter; + valCounters.Val008Counter = totalBitCount; - totalBitCount += valCounters.Val032Counter << Val032Rank; - vPointers.Val016Pointer = totalBitCount; + totalBitCount += prevCount << Val008Rank; + prevCount = valCounters.Val001Counter; + valCounters.Val001Counter = totalBitCount; - totalBitCount += valCounters.Val016Counter << Val016Rank; - vPointers.Val008Pointer = totalBitCount; + totalBitCount += prevCount; - totalBitCount += valCounters.Val008Counter << Val008Rank; - vPointers.Val001Pointer = totalBitCount; + for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref valCounters); + } - totalBitCount += valCounters.Val001Counter; - return totalBitCount; + valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; + objectsLength = valCounters.ObjectCounter; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -285,14 +269,14 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) { if (descriptor.IsObjectField) { return; } // d.PackingType == FieldPackingType.Value - PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref valPointers); + PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref valCounters); } static TupleLayout() @@ -309,22 +293,22 @@ static TupleLayout() }; PositionUpdaterByRank = new PositionUpdater[] { - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val001Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val001Counter), + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val008Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val016Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val032Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val064Pointer), - (ref PackedFieldDescriptor descriptor, ref ValPointers valPointers) - => UpdateDescriptorPosition(ref descriptor, ref valPointers.Val128Pointer) + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val008Counter), + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val016Counter), + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val032Counter), + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val064Counter), + (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val128Counter) }; } } From 8cfbc2096045ab6f4b7ded016b206be6a500e634 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 13:30:42 -0700 Subject: [PATCH 27/31] Directly write to PackedFieldDescriptor fields to save on setter calls --- .../Tuples/Packed/PackedFieldDescriptor.cs | 27 +--- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 125 +++++++++--------- 2 files changed, 69 insertions(+), 83 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index 1cefc08e1e..24c7f16c35 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -5,7 +5,6 @@ // Created: 2012.12.29 using System; -using System.Runtime.CompilerServices; namespace Xtensive.Tuples.Packed { @@ -15,32 +14,20 @@ internal struct PackedFieldDescriptor private const int OffsetBitCount = 6; private const int OffsetMask = (1 << OffsetBitCount) - 1; - private int indexField; - private int stateField; + internal int DataPosition; + internal int StatePosition; [NonSerialized] public PackedFieldAccessor Accessor; public bool IsObjectField => Accessor.Rank < 0; - public int ObjectIndex - { - get => indexField; - set => indexField = value; - } + public int ObjectIndex => DataPosition; - public int ValueIndex => indexField >> OffsetBitCount; - public int ValueBitOffset => indexField & OffsetMask; + public int ValueIndex => DataPosition >> OffsetBitCount; + public int ValueBitOffset => DataPosition & OffsetMask; - public int StateIndex => stateField >> OffsetBitCount; - public int StateBitOffset => stateField & OffsetMask; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetValueBitOffset(int totalBitOffset) - => indexField = totalBitOffset; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetStateTotalBitOffset(int stateBitOffset) - => stateField = stateBitOffset; + public int StateIndex => StatePosition >> OffsetBitCount; + public int StateBitOffset => StatePosition & OffsetMask; } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 569042edc2..39d9334d83 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -19,7 +19,7 @@ internal static class TupleLayout private const int Val064BitCount = 1 << Val064Rank; - private ref struct ValCounters + private ref struct Counters { public int ObjectCounter; @@ -118,15 +118,15 @@ ValueFieldAccessor ResolveByNullableType(Type type) => ReferenceEquals(type, NullableDecimalType) ? DecimalAccessor : ReferenceEquals(type, NullableGuidType) ? GuidAccessor : null; - return (probeType.MetadataToken ^ NullableTypeMetadataToken)==0 + return (probeType.MetadataToken ^ NullableTypeMetadataToken) == 0 ? ResolveByNullableType(probeType) : ResolveByType(probeType); } } - private delegate void CounterIncrementer(ref ValCounters valCounters); + private delegate void CounterIncrementer(ref Counters counters); - private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref ValCounters valCounters); + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref Counters counters); private static readonly ObjectFieldAccessor ObjectAccessor = new ObjectFieldAccessor(); private static readonly CounterIncrementer[] IncrementerByRank; @@ -143,9 +143,9 @@ public static void ConfigureLen1(Type[] fieldTypes, ref PackedFieldDescriptor de var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[0]); if (valueAccessor != null) { descriptor.Accessor = valueAccessor; - descriptor.SetValueBitOffset(Val064BitCount); + descriptor.DataPosition = Val064BitCount; - valuesLength = ((1 << valueAccessor.Rank) + ((Val064BitCount * 2) - 1)) >> Val064Rank; + valuesLength = (valueAccessor.ValueBitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; objectsLength = 0; fieldTypes[0] = valueAccessor.FieldType; return; @@ -159,10 +159,10 @@ public static void ConfigureLen1(Type[] fieldTypes, ref PackedFieldDescriptor de public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor descriptor1, ref PackedFieldDescriptor descriptor2, out int valuesLength, out int objectsLength) { - var valCounters = new ValCounters(); - ConfigureFieldPhase1(ref descriptor1, ref valCounters, fieldTypes, 0); - ConfigureFieldPhase1(ref descriptor2, ref valCounters, fieldTypes, 1); - objectsLength = valCounters.ObjectCounter; + var counters = new Counters(); + ConfigureFieldPhase1(ref descriptor1, ref counters, fieldTypes, 0); + ConfigureFieldPhase1(ref descriptor2, ref counters, fieldTypes, 1); + objectsLength = counters.ObjectCounter; int val1BitCount, val2BitCount; switch (objectsLength) { case 2: @@ -170,11 +170,11 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de return; case 1: { if (descriptor1.IsObjectField) { - descriptor2.SetValueBitOffset(Val064BitCount); + descriptor2.DataPosition = Val064BitCount; val1BitCount = descriptor2.Accessor.ValueBitCount; } else { - descriptor1.SetValueBitOffset(Val064BitCount); + descriptor1.DataPosition = Val064BitCount; val1BitCount = descriptor1.Accessor.ValueBitCount; } valuesLength = (val1BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; @@ -185,12 +185,12 @@ public static void ConfigureLen2(Type[] fieldTypes, ref PackedFieldDescriptor de val1BitCount = descriptor1.Accessor.ValueBitCount; val2BitCount = descriptor2.Accessor.ValueBitCount; if (val2BitCount > val1BitCount) { - descriptor2.SetValueBitOffset(Val064BitCount); - descriptor1.SetValueBitOffset(Val064BitCount + val2BitCount); + descriptor2.DataPosition = Val064BitCount; + descriptor1.DataPosition = Val064BitCount + val2BitCount; } else { - descriptor1.SetValueBitOffset(Val064BitCount); - descriptor2.SetValueBitOffset(Val064BitCount + val1BitCount); + descriptor1.DataPosition = Val064BitCount; + descriptor2.DataPosition = Val064BitCount + val1BitCount; } valuesLength = (val1BitCount + val2BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; } @@ -200,59 +200,59 @@ public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDes out int objectsLength) { var fieldCount = fieldTypes.Length; - var valCounters = new ValCounters(); + var counters = new Counters(); for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref valCounters, fieldTypes, fieldIndex); + ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref counters, fieldTypes, fieldIndex); } const int statesPerLong = Val064BitCount / 2; var totalBitCount = ((fieldCount + (statesPerLong - 1)) >> Val032Rank) << Val064Rank; - var prevCount = valCounters.Val128Counter; - valCounters.Val128Counter = totalBitCount; + var prevCount = counters.Val128Counter; + counters.Val128Counter = totalBitCount; totalBitCount += prevCount << Val128Rank; - prevCount = valCounters.Val064Counter; - valCounters.Val064Counter = totalBitCount; + prevCount = counters.Val064Counter; + counters.Val064Counter = totalBitCount; totalBitCount += prevCount << Val064Rank; - prevCount = valCounters.Val032Counter; - valCounters.Val032Counter = totalBitCount; + prevCount = counters.Val032Counter; + counters.Val032Counter = totalBitCount; totalBitCount += prevCount << Val032Rank; - prevCount = valCounters.Val016Counter; - valCounters.Val016Counter = totalBitCount; + prevCount = counters.Val016Counter; + counters.Val016Counter = totalBitCount; totalBitCount += prevCount << Val016Rank; - prevCount = valCounters.Val008Counter; - valCounters.Val008Counter = totalBitCount; + prevCount = counters.Val008Counter; + counters.Val008Counter = totalBitCount; totalBitCount += prevCount << Val008Rank; - prevCount = valCounters.Val001Counter; - valCounters.Val001Counter = totalBitCount; + prevCount = counters.Val001Counter; + counters.Val001Counter = totalBitCount; totalBitCount += prevCount; for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref valCounters); + ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref counters); } valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; - objectsLength = valCounters.ObjectCounter; + objectsLength = counters.ObjectCounter; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref int valPointer) + private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref int bitCounter) { - descriptor.SetValueBitOffset(valPointer); - valPointer += descriptor.Accessor.ValueBitCount; + descriptor.DataPosition = bitCounter; + bitCounter += descriptor.Accessor.ValueBitCount; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref ValCounters counters, + private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref Counters counters, Type[] fieldTypes, int fieldIndex) { - descriptor.SetStateTotalBitOffset(fieldIndex << 1); + descriptor.StatePosition = fieldIndex << 1; var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[fieldIndex]); if (valueAccessor != null) { @@ -265,50 +265,49 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r } descriptor.Accessor = ObjectAccessor; - descriptor.ObjectIndex = counters.ObjectCounter++; + descriptor.DataPosition = counters.ObjectCounter++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref Counters counters) { if (descriptor.IsObjectField) { return; } - // d.PackingType == FieldPackingType.Value - PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref valCounters); + PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref counters); } static TupleLayout() { IncrementerByRank = new CounterIncrementer[] { - (ref ValCounters valueCounters) => valueCounters.Val001Counter++, - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => throw new NotSupportedException(), - (ref ValCounters valueCounters) => valueCounters.Val008Counter++, - (ref ValCounters valueCounters) => valueCounters.Val016Counter++, - (ref ValCounters valueCounters) => valueCounters.Val032Counter++, - (ref ValCounters valueCounters) => valueCounters.Val064Counter++, - (ref ValCounters valueCounters) => valueCounters.Val128Counter++ + (ref Counters counters) => counters.Val001Counter++, + (ref Counters counters) => throw new NotSupportedException(), + (ref Counters counters) => throw new NotSupportedException(), + (ref Counters counters) => counters.Val008Counter++, + (ref Counters counters) => counters.Val016Counter++, + (ref Counters counters) => counters.Val032Counter++, + (ref Counters counters) => counters.Val064Counter++, + (ref Counters counters) => counters.Val128Counter++ }; PositionUpdaterByRank = new PositionUpdater[] { - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val001Counter), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val001Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) + (ref PackedFieldDescriptor descriptor, ref Counters counters) => throw new NotSupportedException(), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val008Counter), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val016Counter), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val032Counter), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val064Counter), - (ref PackedFieldDescriptor descriptor, ref ValCounters valCounters) - => UpdateDescriptorPosition(ref descriptor, ref valCounters.Val128Counter) + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val008Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val016Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val032Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val064Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val128Counter) }; } } From 515628476d906b2d28a08c722ed35fcb6f7e1a24 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 19:00:45 -0700 Subject: [PATCH 28/31] Bump version to 6.0.3 'tupledescriptor-nocache' --- Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Version.props b/Version.props index a74ce738a2..dc8069ff4b 100644 --- a/Version.props +++ b/Version.props @@ -2,8 +2,8 @@ - 6.0.2 - tupledescriptor + 6.0.3 + tupledescriptor-nocache From 404a5f3df941e65d0ed736e97ec526c2a887671f Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Wed, 1 Apr 2020 20:57:41 -0700 Subject: [PATCH 29/31] Remove version suffix --- Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version.props b/Version.props index dc8069ff4b..64601c8523 100644 --- a/Version.props +++ b/Version.props @@ -3,7 +3,7 @@ 6.0.3 - tupledescriptor-nocache + From 1c2b89f9ac9aad98e75471022280bf3753b36011 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Thu, 2 Apr 2020 16:12:00 -0700 Subject: [PATCH 30/31] Use Array.Empty to get empty array instance --- Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs index 83b9be8a29..4ab2f78dbe 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Tuples/TupleBehaviorTestBase.cs @@ -136,8 +136,7 @@ private static void TestTuple(Xtensive.Tuples.Tuple tuple) public void EmptyFieldsTest() { - var types = new Type[0]; - var d = TupleDescriptor.Create(types); + var d = TupleDescriptor.Create(Array.Empty()); var dummyTuple = new DummyTuple(d); var tuple = CreateTestTuple(d); Assert.AreEqual(0, tuple.Count); From e9e18e7ff3fb0da8175995bc1fe8971803cec61a Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Thu, 2 Apr 2020 20:05:20 -0700 Subject: [PATCH 31/31] Use ref var to avoid field descriptor copying to stack and also to avoid repeating array indexing --- Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs | 30 ++++++++++--------- Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs | 17 ++++------- Orm/Xtensive.Orm/Tuples/Tuple.cs | 8 ++--- Orm/Xtensive.Orm/Tuples/TupleExtensions.cs | 16 +++++----- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs index 7f615636ed..f6e5179d22 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs @@ -46,14 +46,15 @@ public override bool Equals(Tuple other) var fieldDescriptors = PackedDescriptor.FieldDescriptors; var count = Count; for (int i = 0; i < count; i++) { - var thisState = GetFieldState(ref fieldDescriptors[i]); - var otherState = packedOther.GetFieldState(ref fieldDescriptors[i]); + ref var descriptor = ref fieldDescriptors[i]; + var thisState = GetFieldState(ref descriptor); + var otherState = packedOther.GetFieldState(ref descriptor); if (thisState!=otherState) return false; if (thisState!=TupleFieldState.Available) continue; - var accessor = fieldDescriptors[i].Accessor; - if (!accessor.ValueEquals(this, ref fieldDescriptors[i], packedOther, ref fieldDescriptors[i])) + var accessor = descriptor.Accessor; + if (!accessor.ValueEquals(this, ref descriptor, packedOther, ref descriptor)) return false; } @@ -66,10 +67,11 @@ public override int GetHashCode() var fieldDescriptors = PackedDescriptor.FieldDescriptors; int result = 0; for (int i = 0; i < count; i++) { - var accessor = fieldDescriptors[i].Accessor; + ref var descriptor = ref fieldDescriptors[i]; + var accessor = descriptor.Accessor; var state = GetFieldState(ref fieldDescriptors[i]); var fieldHash = state==TupleFieldState.Available - ? accessor.GetValueHashCode(this, ref fieldDescriptors[i]) + ? accessor.GetValueHashCode(this, ref descriptor) : 0; result = HashCodeMultiplier * result ^ fieldHash; } @@ -83,23 +85,23 @@ public override TupleFieldState GetFieldState(int fieldIndex) protected internal override void SetFieldState(int fieldIndex, TupleFieldState fieldState) { - if (fieldState==TupleFieldState.Null) - throw new ArgumentOutOfRangeException("fieldState"); + if (fieldState==TupleFieldState.Null) { + throw new ArgumentOutOfRangeException(nameof(fieldState)); + } - var fieldDescriptors = PackedDescriptor.FieldDescriptors; - SetFieldState(ref fieldDescriptors[fieldIndex], fieldState); + SetFieldState(ref PackedDescriptor.FieldDescriptors[fieldIndex], fieldState); } public override object GetValue(int fieldIndex, out TupleFieldState fieldState) { - var fieldDescriptors = PackedDescriptor.FieldDescriptors; - return fieldDescriptors[fieldIndex].Accessor.GetUntypedValue(this, ref fieldDescriptors[fieldIndex], out fieldState); + ref var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex]; + return descriptor.Accessor.GetUntypedValue(this, ref descriptor, out fieldState); } public override void SetValue(int fieldIndex, object fieldValue) { - var fieldDescriptors = PackedDescriptor.FieldDescriptors; - fieldDescriptors[fieldIndex].Accessor.SetUntypedValue(this, ref fieldDescriptors[fieldIndex], fieldValue); + ref var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex]; + descriptor.Accessor.SetUntypedValue(this, ref descriptor, fieldValue); } public void SetFieldState(ref PackedFieldDescriptor d, TupleFieldState fieldState) diff --git a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs index 39d9334d83..00220fa7f8 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -234,7 +234,12 @@ public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDes totalBitCount += prevCount; for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { - ConfigureFieldPhase2(ref fieldDescriptors[fieldIndex], ref counters); + ref var descriptor = ref fieldDescriptors[fieldIndex]; + if (descriptor.IsObjectField) { + continue; + } + + PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref counters); } valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; @@ -268,16 +273,6 @@ private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, r descriptor.DataPosition = counters.ObjectCounter++; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ConfigureFieldPhase2(ref PackedFieldDescriptor descriptor, ref Counters counters) - { - if (descriptor.IsObjectField) { - return; - } - - PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref counters); - } - static TupleLayout() { IncrementerByRank = new CounterIncrementer[] { diff --git a/Orm/Xtensive.Orm/Tuples/Tuple.cs b/Orm/Xtensive.Orm/Tuples/Tuple.cs index 3c1b206657..678e3b8271 100644 --- a/Orm/Xtensive.Orm/Tuples/Tuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Tuple.cs @@ -112,13 +112,13 @@ public T GetValue(int fieldIndex, out TupleFieldState fieldState) var isNullable = null==default(T); // Is nullable value type or class if (this is PackedTuple packedTuple) { - var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; + ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; return descriptor.Accessor.GetValue(packedTuple, ref descriptor, isNullable, out fieldState); } var mappedContainer = GetMappedContainer(fieldIndex, false); if (mappedContainer.First is PackedTuple mappedTuple) { - var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; + ref var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; return descriptor.Accessor.GetValue(mappedTuple, ref descriptor, isNullable, out fieldState); } @@ -187,14 +187,14 @@ public void SetValue(int fieldIndex, T fieldValue) var isNullable = null==default(T); // Is nullable value type or class if (this is PackedTuple packedTuple) { - var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; + ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; descriptor.Accessor.SetValue(packedTuple, ref descriptor, isNullable, fieldValue); return; } var mappedContainer = GetMappedContainer(fieldIndex, true); if (mappedContainer.First is PackedTuple mappedTuple) { - var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; + ref var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; descriptor.Accessor.SetValue(mappedTuple, ref descriptor, isNullable, fieldValue); return; } diff --git a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs index fa46d55451..6284b9f5f3 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs @@ -437,27 +437,29 @@ private static void CopyValue(Tuple source, int sourceIndex, Tuple target, int t private static void CopyPackedValue(PackedTuple source, int sourceIndex, PackedTuple target, int targetIndex) { - var sourceDescriptors = source.PackedDescriptor.FieldDescriptors; - var targetDescriptors = target.PackedDescriptor.FieldDescriptors; + ref var sourceDescriptor = ref source.PackedDescriptor.FieldDescriptors[sourceIndex]; + ref var targetDescriptor = ref target.PackedDescriptor.FieldDescriptors[targetIndex]; - var fieldState = source.GetFieldState(ref sourceDescriptors[sourceIndex]); - if (!fieldState.IsAvailable()) + var fieldState = source.GetFieldState(ref sourceDescriptor); + if (!fieldState.IsAvailable()) { return; + } if (fieldState.IsAvailableAndNull()) { target.SetValue(targetIndex, null); return; } - var accessor = sourceDescriptors[sourceIndex].Accessor; - if (accessor!=targetDescriptors[targetIndex].Accessor) + var accessor = sourceDescriptor.Accessor; + if (accessor != targetDescriptor.Accessor) { throw new InvalidOperationException(string.Format( Strings.ExInvalidCast, source.PackedDescriptor[sourceIndex], target.PackedDescriptor[targetIndex])); + } target.SetFieldState(targetIndex, TupleFieldState.Available); - accessor.CopyValue(source, ref sourceDescriptors[sourceIndex], target, ref targetDescriptors[targetIndex]); + accessor.CopyValue(source, ref sourceDescriptor, target, ref targetDescriptor); } private static void PartiallyCopyTupleSlow(Tuple source, Tuple target, int sourceStartIndex, int targetStartIndex, int length)