Skip to content

Commit f7688d5

Browse files
authored
Optimize VisitList<>() (#372)
1 parent 38a28f4 commit f7688d5

File tree

3 files changed

+26
-18
lines changed

3 files changed

+26
-18
lines changed

Orm/Xtensive.Orm/Core/Extensions/EnumerableExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,5 +582,11 @@ public static List<TValue> SortTopologically<TValue>(this IEnumerable<TValue> va
582582
var result = TopologicalSorter.Sort(graph);
583583
return result.HasLoops ? null : result.SortedNodes.SelectToList(node => node.Value);
584584
}
585+
586+
internal static IReadOnlyList<T> ToReadOnlyList<T>(this IEnumerable<T> seq) =>
587+
seq switch {
588+
IReadOnlyList<T> roList => roList,
589+
var s => s?.ToList()
590+
};
585591
}
586592
}

Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public abstract class ExpressionVisitor(bool isCaching = false) : System.Linq.Ex
2121
{
2222
private readonly Dictionary<Expression, Expression> cache = isCaching ? new() : null;
2323

24-
protected virtual IReadOnlyList<Expression> VisitExpressionList(IReadOnlyList<Expression> expressions) =>
24+
protected virtual IEnumerable<Expression> VisitExpressionList(IReadOnlyList<Expression> expressions) =>
2525
VisitList(expressions, Visit);
2626

2727
public override Expression Visit(Expression e)
@@ -69,7 +69,7 @@ protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
6969
/// </summary>
7070
/// <param name="original">The original element initializer list.</param>
7171
/// <returns>Visit result.</returns>
72-
protected virtual IReadOnlyList<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original) =>
72+
protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original) =>
7373
VisitList(original, VisitElementInitializer);
7474

7575
/// <inheritdoc/>
@@ -236,29 +236,31 @@ protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBind
236236
/// </summary>
237237
/// <param name="original">The original binding list.</param>
238238
/// <returns>Visit result.</returns>
239-
protected virtual IReadOnlyList<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original) =>
239+
protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original) =>
240240
VisitList(original, VisitBinding);
241241

242-
public static IReadOnlyList<T> VisitList<T>(IReadOnlyList<T> original, Func<T, T> func) where T : class
242+
public static IEnumerable<T> VisitList<T>(IReadOnlyList<T> original, Func<T, T> func) where T : class
243243
{
244-
T[] ar = null;
245-
for (int i = 0, n = original.Count; i < n; i++) {
244+
for (int i = 0, n = original.Count; i < n; ++i) {
246245
var originalValue = original[i];
247-
var p = func(originalValue);
248-
if (ar != null) {
249-
ar[i] = p;
250-
}
251-
else if (!ReferenceEquals(p, originalValue)) {
252-
ar = new T[n];
253-
for (int j = 0; j < i; j++) {
254-
ar[j] = original[j];
255-
}
256-
ar[i] = p;
246+
if (func(originalValue) is var p && !ReferenceEquals(p, originalValue)) {
247+
return VisitListIterator(original, func, p, i);
257248
}
258249
}
259-
return ar?.AsSafeWrapper() ?? original;
250+
return original;
260251
}
261252

253+
private static IEnumerable<T> VisitListIterator<T>(IReadOnlyList<T> original, Func<T, T> func, T p, int pIdx) where T : class
254+
{
255+
for (var i = 0; i < pIdx; ++i) {
256+
yield return original[i];
257+
}
258+
yield return p;
259+
for (int i = pIdx + 1, n = original.Count; i < n; ++i) {
260+
yield return func(original[i]);
261+
}
262+
}
263+
262264
protected override MemberListBinding VisitMemberListBinding(MemberListBinding binding)
263265
{
264266
var bindingInitializers = binding.Initializers;

Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/OwnerRemover.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ internal override Expression VisitConstructorExpression(ConstructorExpression ex
6767
var nativeBingings = expression.NativeBindings
6868
.Zip(newNativeBindings)
6969
.ToDictionary(item => item.First.Key, item => item.Second);
70-
return new ConstructorExpression(expression.Type, bindings, nativeBingings, expression.Constructor, newConstructorArguments);
70+
return new ConstructorExpression(expression.Type, bindings, nativeBingings, expression.Constructor, newConstructorArguments.ToReadOnlyList());
7171
}
7272

7373
internal override Expression VisitEntityExpression(EntityExpression expression)

0 commit comments

Comments
 (0)