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.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..4ab2f78dbe 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,9 @@ 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 d = TupleDescriptor.Create(Array.Empty()); + var dummyTuple = new DummyTuple(d); + var tuple = CreateTestTuple(d); Assert.AreEqual(0, tuple.Count); } @@ -162,25 +153,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 +224,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/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/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/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/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/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>( diff --git a/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs b/Orm/Xtensive.Orm/Orm/Linq/ItemToTupleConverter{TItem}.cs index bbbbeb9e5c..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); + Expression = (Expression) BuildField(itemType, ref index, types); + TupleDescriptor = TupleDescriptor.Create(types.ToArray(types.Count)); } else { - Xtensive.Collections.ISet processedTypes = new Set(); - LocalCollectionExpression itemExpression = BuildLocalCollectionExpression(itemType, processedTypes, ref index, null, ref types); - TupleDescriptor = TupleDescriptor.Create(types); + 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) @@ -247,4 +270,4 @@ public ItemToTupleConverter(Func> enumerableFunc, DomainModel BuildConverter(); } } -} \ No newline at end of file +} 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/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..93bfb1e71f 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() @@ -810,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); } @@ -859,4 +861,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..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); } @@ -71,9 +71,21 @@ public ColumnCollection Alias(string alias) /// /// Collection of items to add. public ColumnCollection(IEnumerable collection) - : base (collection.ToList()) + : base(collection.ToList()) { - Initialize(); + nameIndex = new Dictionary(Count); + BuildNameIndex(); + } + + /// + /// Initializes a new instance of this class. + /// + /// Collection of items to add. + public ColumnCollection(List collection) + : base(collection) + { + nameIndex = new Dictionary(Count); + BuildNameIndex(); } } -} \ 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..f50f484112 100644 --- a/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs +++ b/Orm/Xtensive.Orm/Orm/Rse/Providers/Compilable/IncludeProvider.cs @@ -62,13 +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 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 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, BoolTupleDescriptor); return newHeader; } @@ -99,4 +105,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..11c97f0f23 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/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/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/PackedFieldAccessor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs index 491c90bc16..63c6cc81b5 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs @@ -30,224 +30,235 @@ internal abstract class PackedFieldAccessor /// protected Delegate NullableSetter; - public void SetValue(PackedTuple tuple, PackedFieldDescriptor descriptor, bool isNullable, T value) + 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; 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, ref PackedFieldDescriptor descriptor, object value); + + public abstract void CopyValue(PackedTuple source, ref PackedFieldDescriptor sourceDescriptor, + PackedTuple target, ref PackedFieldDescriptor targetDescriptor); - public abstract void SetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, object value); + public abstract bool ValueEquals(PackedTuple left, ref PackedFieldDescriptor leftDescriptor, + PackedTuple right, ref PackedFieldDescriptor rightDescriptor); - public abstract void CopyValue(PackedTuple source, PackedFieldDescriptor sourceDescriptor, - PackedTuple target, PackedFieldDescriptor targetDescriptor); + public abstract int GetValueHashCode(PackedTuple tuple, ref PackedFieldDescriptor descriptor); - public abstract bool ValueEquals(PackedTuple left, PackedFieldDescriptor leftDescriptor, - PackedTuple right, PackedFieldDescriptor rightDescriptor); + protected PackedFieldAccessor(int rank) + { + Rank = rank; + ValueBitCount = 1 << Rank; - public abstract int GetValueHashCode(PackedTuple tuple, PackedFieldDescriptor descriptor); + // 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 { - 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; + return state==TupleFieldState.Available ? tuple.Objects[descriptor.ObjectIndex] : 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; + tuple.Objects[descriptor.ObjectIndex] = 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]; + target.Objects[targetDescriptor.ObjectIndex] = source.Objects[sourceDescriptor.ObjectIndex]; } - 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]; + var leftValue = left.Objects[leftDescriptor.ObjectIndex]; + var rightValue = right.Objects[rightDescriptor.ObjectIndex]; 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(); + return tuple.Objects[descriptor.ObjectIndex].GetHashCode(); } + + public ObjectFieldAccessor() + : base(-1) + { } } internal abstract class ValueFieldAccessor : PackedFieldAccessor { - public readonly int BitCount; - public readonly long BitMask; + public Type FieldType { get; protected set; } - private static long GetMask(int bits) + private static int GetRank(int bitSize) { - long result = 0; - - for (int i = 0; i < bits; i++) { - result <<= 1; - result |= 1; + var rank = 0; + while ((bitSize >>= 1) > 0) { + rank++; } - return result; + return rank; } - protected ValueFieldAccessor(int bits) - { - BitCount = bits; - - if (bits <= 64) - BitMask = GetMask(bits); - } + protected ValueFieldAccessor(int bitCount) + : base(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; - 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, 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(ref descriptor, TupleFieldState.Available | TupleFieldState.Null); } - else - tuple.SetFieldState(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) { + if (Rank > 6) { Encode(value, tuple.Values, d.ValueIndex); return; } 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); } - private T Load(PackedTuple tuple, PackedFieldDescriptor d) + 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; + var encoded = (tuple.Values[d.ValueIndex] >> d.ValueBitOffset) & ValueBitMask; return Decode(encoded); } protected ValueFieldAccessor(int bits) : base(bits) { + FieldType = typeof(T); Getter = (GetValueDelegate) GetValue; Setter = (SetValueDelegate) SetValue; diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs deleted file mode 100644 index 42a2ca0637..0000000000 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessorFactory.cs +++ /dev/null @@ -1,63 +0,0 @@ -// 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; - -namespace Xtensive.Tuples.Packed -{ - internal static class PackedFieldAccessorFactory - { - private static readonly PackedFieldAccessor ObjectAccessor; - private static readonly Dictionary ValueAccessors; - - public static IEnumerable KnownTypes { get { return ValueAccessors.Keys; } } - - public static void ProvideAccessor(Type valueType, PackedFieldDescriptor descriptor) - { - ValueFieldAccessor valueAccessor; - if (ValueAccessors.TryGetValue(valueType, out valueAccessor)) { - descriptor.PackingType = FieldPackingType.Value; - descriptor.Accessor = valueAccessor; - descriptor.ValueBitCount = valueAccessor.BitCount; - descriptor.ValueBitMask = valueAccessor.BitMask; - } - else { - descriptor.Accessor = ObjectAccessor; - descriptor.PackingType = FieldPackingType.Object; - } - } - - private static void RegisterAccessor(ValueFieldAccessor accessor) - where T : struct, IEquatable - { - 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()); - } - } -} \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs index ef5a5d5a7b..24c7f16c35 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs @@ -9,22 +9,25 @@ namespace Xtensive.Tuples.Packed { [Serializable] - internal sealed class PackedFieldDescriptor + internal struct PackedFieldDescriptor { - public FieldPackingType PackingType; + private const int OffsetBitCount = 6; + private const int OffsetMask = (1 << OffsetBitCount) - 1; + + internal int DataPosition; + internal int StatePosition; [NonSerialized] public PackedFieldAccessor Accessor; - public int FieldIndex; + public bool IsObjectField => Accessor.Rank < 0; - public int ValueIndex; - public int ValueBitOffset; - public int ValueBitCount; + public int ObjectIndex => DataPosition; - public long ValueBitMask; + public int ValueIndex => DataPosition >> OffsetBitCount; + public int ValueBitOffset => DataPosition & OffsetMask; - public int StateIndex; - public int 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/PackedTuple.cs b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs index 07ff1ae59f..f6e5179d22 100644 --- a/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs +++ b/Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs @@ -43,16 +43,18 @@ 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); + 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; - if (!descriptor.Accessor.ValueEquals(this, descriptor, packedOther, descriptor)) + var accessor = descriptor.Accessor; + if (!accessor.ValueEquals(this, ref descriptor, packedOther, ref descriptor)) return false; } @@ -62,12 +64,14 @@ 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); + ref var descriptor = ref fieldDescriptors[i]; + var accessor = descriptor.Accessor; + var state = GetFieldState(ref fieldDescriptors[i]); var fieldHash = state==TupleFieldState.Available - ? descriptor.Accessor.GetValueHashCode(this, descriptor) + ? accessor.GetValueHashCode(this, ref descriptor) : 0; result = HashCodeMultiplier * result ^ fieldHash; } @@ -76,42 +80,42 @@ 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) { - if (fieldState==TupleFieldState.Null) - throw new ArgumentOutOfRangeException("fieldState"); - - var descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - SetFieldState(descriptor, fieldState); + if (fieldState==TupleFieldState.Null) { + throw new ArgumentOutOfRangeException(nameof(fieldState)); + } - if (fieldState!=TupleFieldState.Available && descriptor.PackingType==FieldPackingType.Object) - Objects[descriptor.ValueIndex] = null; + SetFieldState(ref PackedDescriptor.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); + 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 descriptor = PackedDescriptor.FieldDescriptors[fieldIndex]; - descriptor.Accessor.SetUntypedValue(this, descriptor, fieldValue); + ref var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex]; + descriptor.Accessor.SetUntypedValue(this, ref descriptor, 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.IsObjectField) { + Objects[d.ObjectIndex] = 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/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/Packed/TupleLayout.cs b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs new file mode 100644 index 0000000000..00220fa7f8 --- /dev/null +++ b/Orm/Xtensive.Orm/Tuples/Packed/TupleLayout.cs @@ -0,0 +1,309 @@ +// 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.Runtime.CompilerServices; + +namespace Xtensive.Tuples.Packed +{ + 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 Val064BitCount = 1 << Val064Rank; + + private ref struct Counters + { + public int ObjectCounter; + + public int Val001Counter; + public int Val008Counter; + public int Val016Counter; + public int Val032Counter; + public int Val064Counter; + 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(); + + private static readonly int NullableTypeMetadataToken = typeof(Nullable<>).MetadataToken; + + 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.MetadataToken ^ NullableTypeMetadataToken) == 0 + ? ResolveByNullableType(probeType) + : ResolveByType(probeType); + } + } + + private delegate void CounterIncrementer(ref Counters counters); + + private delegate void PositionUpdater(ref PackedFieldDescriptor descriptor, ref Counters counters); + + 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 = (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.DataPosition = Val064BitCount; + + valuesLength = (valueAccessor.ValueBitCount + ((Val064BitCount * 2) - 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 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: + valuesLength = 1; + return; + case 1: { + if (descriptor1.IsObjectField) { + descriptor2.DataPosition = Val064BitCount; + val1BitCount = descriptor2.Accessor.ValueBitCount; + } + else { + descriptor1.DataPosition = Val064BitCount; + val1BitCount = descriptor1.Accessor.ValueBitCount; + } + valuesLength = (val1BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; + return; + } + } + // Both descriptors are value descriptors + val1BitCount = descriptor1.Accessor.ValueBitCount; + val2BitCount = descriptor2.Accessor.ValueBitCount; + if (val2BitCount > val1BitCount) { + descriptor2.DataPosition = Val064BitCount; + descriptor1.DataPosition = Val064BitCount + val2BitCount; + } + else { + descriptor1.DataPosition = Val064BitCount; + descriptor2.DataPosition = Val064BitCount + val1BitCount; + } + valuesLength = (val1BitCount + val2BitCount + ((Val064BitCount * 2) - 1)) >> Val064Rank; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Configure(Type[] fieldTypes, PackedFieldDescriptor[] fieldDescriptors, out int valuesLength, + out int objectsLength) + { + var fieldCount = fieldTypes.Length; + var counters = new Counters(); + for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + ConfigureFieldPhase1(ref fieldDescriptors[fieldIndex], ref counters, fieldTypes, fieldIndex); + } + + const int statesPerLong = Val064BitCount / 2; + + var totalBitCount = ((fieldCount + (statesPerLong - 1)) >> Val032Rank) << Val064Rank; + var prevCount = counters.Val128Counter; + counters.Val128Counter = totalBitCount; + + totalBitCount += prevCount << Val128Rank; + prevCount = counters.Val064Counter; + counters.Val064Counter = totalBitCount; + + totalBitCount += prevCount << Val064Rank; + prevCount = counters.Val032Counter; + counters.Val032Counter = totalBitCount; + + totalBitCount += prevCount << Val032Rank; + prevCount = counters.Val016Counter; + counters.Val016Counter = totalBitCount; + + totalBitCount += prevCount << Val016Rank; + prevCount = counters.Val008Counter; + counters.Val008Counter = totalBitCount; + + totalBitCount += prevCount << Val008Rank; + prevCount = counters.Val001Counter; + counters.Val001Counter = totalBitCount; + + totalBitCount += prevCount; + + for (var fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + ref var descriptor = ref fieldDescriptors[fieldIndex]; + if (descriptor.IsObjectField) { + continue; + } + + PositionUpdaterByRank[descriptor.Accessor.Rank].Invoke(ref descriptor, ref counters); + } + + valuesLength = (totalBitCount + (Val064BitCount - 1)) >> Val064Rank; + objectsLength = counters.ObjectCounter; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void UpdateDescriptorPosition(ref PackedFieldDescriptor descriptor, ref int bitCounter) + { + descriptor.DataPosition = bitCounter; + bitCounter += descriptor.Accessor.ValueBitCount; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ConfigureFieldPhase1(ref PackedFieldDescriptor descriptor, ref Counters counters, + Type[] fieldTypes, int fieldIndex) + { + descriptor.StatePosition = fieldIndex << 1; + + var valueAccessor = ValueFieldAccessorResolver.GetValue(fieldTypes[fieldIndex]); + if (valueAccessor != null) { + descriptor.Accessor = valueAccessor; + + IncrementerByRank[valueAccessor.Rank].Invoke(ref counters); + + fieldTypes[fieldIndex] = valueAccessor.FieldType; + return; + } + + descriptor.Accessor = ObjectAccessor; + descriptor.DataPosition = counters.ObjectCounter++; + } + + static TupleLayout() + { + IncrementerByRank = new CounterIncrementer[] { + (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 Counters counters) + => UpdateDescriptorPosition(ref descriptor, ref counters.Val001Counter), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => throw new NotSupportedException(), + (ref PackedFieldDescriptor descriptor, ref Counters counters) + => throw new NotSupportedException(), + (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) + }; + } + } +} diff --git a/Orm/Xtensive.Orm/Tuples/Tuple.cs b/Orm/Xtensive.Orm/Tuples/Tuple.cs index 7d256b04f0..678e3b8271 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; } } /// @@ -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) { - var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; - return descriptor.Accessor.GetValue(packedTuple, descriptor, isNullable, out fieldState); + if (this is PackedTuple packedTuple) { + ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; + return descriptor.Accessor.GetValue(packedTuple, ref descriptor, isNullable, out fieldState); } var mappedContainer = GetMappedContainer(fieldIndex, false); - var mappedTuple = mappedContainer.First as PackedTuple; - if (mappedTuple!=null) { - var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; - return descriptor.Accessor.GetValue(mappedTuple, descriptor, isNullable, out fieldState); + if (mappedContainer.First is PackedTuple mappedTuple) { + ref var descriptor = ref mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; + 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) { - var descriptor = packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; - descriptor.Accessor.SetValue(packedTuple, descriptor, isNullable, fieldValue); + if (this is PackedTuple packedTuple) { + ref var descriptor = ref packedTuple.PackedDescriptor.FieldDescriptors[fieldIndex]; + descriptor.Accessor.SetValue(packedTuple, ref descriptor, isNullable, fieldValue); return; } var mappedContainer = GetMappedContainer(fieldIndex, true); - var mappedTuple = mappedContainer.First as PackedTuple; - if (mappedTuple!=null) { - var descriptor = mappedTuple.PackedDescriptor.FieldDescriptors[mappedContainer.Second]; - descriptor.Accessor.SetValue(mappedTuple, descriptor, isNullable, fieldValue); + if (mappedContainer.First is PackedTuple mappedTuple) { + 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/TupleDescriptor.cs b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs index be3b59111d..abc91cdcd1 100644 --- a/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs +++ b/Orm/Xtensive.Orm/Tuples/TupleDescriptor.cs @@ -4,17 +4,16 @@ // Created by: Nick Svetlov // Created: 2007.05.30 + using System; using System.Collections; 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 @@ -24,29 +23,19 @@ namespace Xtensive.Tuples /// Provides information about structure. /// [Serializable] - public sealed class TupleDescriptor : IEquatable, IList, ISerializable + public sealed class TupleDescriptor : IEquatable, IReadOnlyList, ISerializable { - [NonSerialized] - private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(new Type[0]); - [NonSerialized] - private static readonly Dictionary SingleFieldDescriptors = new Dictionary(); - - //private string[] fieldTypeNames; + private static readonly TupleDescriptor EmptyDescriptor = new TupleDescriptor(Array.Empty()); - [NonSerialized] - private Type[] fieldTypes; - - internal readonly int FieldCount; + private readonly int FieldCount; internal readonly int ValuesLength; internal readonly int ObjectsLength; [NonSerialized] internal readonly PackedFieldDescriptor[] FieldDescriptors; - internal Type[] FieldTypes - { - get { return fieldTypes; } - } + [field: NonSerialized] + private Type[] FieldTypes { get; } /// /// Gets the empty tuple descriptor. @@ -55,78 +44,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); - } - } - - /// - /// 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) - { - return FieldTypes[fieldIndex].IsValueType; + get => EmptyDescriptor; } #region IList members @@ -134,76 +52,23 @@ public bool IsValueType(int fieldIndex) /// 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; } - } - - /// - public int IndexOf(Type item) - { - return 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; } + get => FieldCount; } /// 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]; + } } /// @@ -247,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; @@ -289,88 +154,56 @@ 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]); - //} - - 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); + return new TupleDescriptor(new [] {t1}); } - #region Create methods (base) + public static TupleDescriptor Create(Type t1, Type t2) + { + 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); + 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); + return new TupleDescriptor(new [] {t1, t2, t3, t4}); } /// /// 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)); + if (fieldTypes.Length == 0) { + return EmptyDescriptor; + } + 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, nameof(fieldCount)); + var fieldTypes = new Type[fieldCount]; + Array.Copy(FieldTypes, 0, fieldTypes, 0, fieldCount); + return new TupleDescriptor(fieldTypes); } /// @@ -381,8 +214,10 @@ public TupleDescriptor Head(int headFieldCount) /// describing the specified set of fields. public TupleDescriptor Tail(int tailFieldCount) { - ArgumentValidator.EnsureArgumentIsInRange(tailFieldCount, 1, Count, "tailFieldCount"); - return Create(FieldTypes.Skip(Count - tailFieldCount)); + 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 @@ -394,12 +229,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 +238,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 +249,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,136 +260,36 @@ 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"); - - 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; - - var objectIndex = 0; - - var valueIndex = FieldCount / statesPerLong + Math.Min(1, FieldCount % statesPerLong); - var valueBitOffset = 0; - - var stateIndex = 0; - var stateBitOffset = 0; - - for (int i = 0; i < FieldCount; i++) { - var fieldType = fieldTypes[i].StripNullable(); - var descriptor = new PackedFieldDescriptor {FieldIndex = i}; - - PackedFieldAccessorFactory.ProvideAccessor(fieldType, descriptor); - - 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++; + switch (FieldCount) { + case 0: + return; + case 1: + TupleLayout.ConfigureLen1(FieldTypes, + ref FieldDescriptors[0], + out ValuesLength, out ObjectsLength); 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; - } + case 2: + TupleLayout.ConfigureLen2(FieldTypes, + ref FieldDescriptors[0], ref FieldDescriptors[1], + out ValuesLength, out ObjectsLength); break; default: - throw new ArgumentOutOfRangeException("descriptor.PackType"); - } - - if (stateBitOffset + stateBits > longBits) { - stateIndex++; - stateBitOffset = 0; - } - - descriptor.StateIndex = stateIndex; - descriptor.StateBitOffset = stateBitOffset; - stateBitOffset += stateBits; + TupleLayout.Configure(FieldTypes, FieldDescriptors, out ValuesLength, out ObjectsLength); + break; } - ValuesLength = valueIndex + Math.Min(1, valueBitOffset); - ObjectsLength = objectIndex; } public TupleDescriptor(SerializationInfo info, StreamingContext context) @@ -578,23 +298,15 @@ 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[])); + FieldDescriptors = (PackedFieldDescriptor[])info.GetValue( + "FieldDescriptors", typeof(PackedFieldDescriptor[])); - fieldTypes = new Type[typeNames.Length]; - for (int i = 0; i < typeNames.Length; i++) + FieldTypes = new Type[typeNames.Length]; + for (var i = 0; i < typeNames.Length; i++) { FieldTypes[i] = typeNames[i].GetTypeFromSerializableForm(); - for (int i = 0; i < FieldCount; i++) - PackedFieldAccessorFactory.ProvideAccessor(FieldTypes[i], FieldDescriptors[i]); - - } - - - static TupleDescriptor() - { - foreach (var type in PackedFieldAccessorFactory.KnownTypes) - SingleFieldDescriptors.Add(type, new TupleDescriptor(new[] {type})); + TupleLayout.ConfigureFieldAccessor(ref FieldDescriptors[i], FieldTypes[i]); + } } } } diff --git a/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs b/Orm/Xtensive.Orm/Tuples/TupleExtensions.cs index 1f8a7ac6ba..6284b9f5f3 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[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 @@ -442,12 +437,13 @@ 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]; + ref var sourceDescriptor = ref source.PackedDescriptor.FieldDescriptors[sourceIndex]; + ref var targetDescriptor = ref target.PackedDescriptor.FieldDescriptors[targetIndex]; - var fieldState = source.GetFieldState(sourceDescriptor); - if (!fieldState.IsAvailable()) + var fieldState = source.GetFieldState(ref sourceDescriptor); + if (!fieldState.IsAvailable()) { return; + } if (fieldState.IsAvailableAndNull()) { target.SetValue(targetIndex, null); @@ -455,14 +451,15 @@ private static void CopyPackedValue(PackedTuple source, int sourceIndex, PackedT } var accessor = sourceDescriptor.Accessor; - if (accessor!=targetDescriptor.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, sourceDescriptor, target, targetDescriptor); + accessor.CopyValue(source, ref sourceDescriptor, target, ref targetDescriptor); } private static void PartiallyCopyTupleSlow(Tuple source, Tuple target, int sourceStartIndex, int targetStartIndex, int length) @@ -559,4 +556,4 @@ private static void MergeTuplesPreferOriginFast(PackedTuple origin, PackedTuple } } } -} \ No newline at end of file +} 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 @@ - + diff --git a/Version.props b/Version.props index 2ec8dab432..64601c8523 100644 --- a/Version.props +++ b/Version.props @@ -2,7 +2,7 @@ - 6.0.1 + 6.0.3