Skip to content

Commit 820673b

Browse files
committed
Less .AsReadOnly() calls or array based ReadOnlyCollections for memory-efficiency
1 parent 49f3280 commit 820673b

15 files changed

Lines changed: 167 additions & 81 deletions

File tree

Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,27 @@ protected override ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCo
3131
return isChanged ? results.AsReadOnly() : expressions;
3232
}
3333

34+
protected override IReadOnlyList<Expression> VisitExpressionList(IReadOnlyList<Expression> expressions)
35+
{
36+
bool isChanged = false;
37+
var results = new Expression[expressions.Count];
38+
for (int i = 0, n = expressions.Count; i < n; i++) {
39+
var expression = expressions[i];
40+
var p = Visit(expression);
41+
results[i] = p;
42+
isChanged |= !ReferenceEquals(expression, p);
43+
}
44+
return isChanged ? results : expressions;
45+
}
46+
3447
/// <summary>
3548
/// Visits the element initializer expression.
3649
/// </summary>
3750
/// <param name="initializer">The initializer.</param>
3851
/// <returns>Visit result.</returns>
3952
protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
4053
{
41-
ReadOnlyCollection<Expression> arguments = VisitExpressionList(initializer.Arguments);
54+
var arguments = VisitExpressionList((IReadOnlyList<Expression>)initializer.Arguments);
4255
if (arguments!=initializer.Arguments) {
4356
return Expression.ElementInit(initializer.AddMethod, arguments);
4457
}
@@ -63,6 +76,24 @@ protected virtual ReadOnlyCollection<ElementInit> VisitElementInitializerList(Re
6376
return isChanged ? results.AsReadOnly() : original;
6477
}
6578

79+
/// <summary>
80+
/// Visits the element initializer list.
81+
/// </summary>
82+
/// <param name="original">The original element initializer list.</param>
83+
/// <returns>Visit result.</returns>
84+
protected virtual IReadOnlyList<ElementInit> VisitElementInitializerList(IReadOnlyList<ElementInit> original)
85+
{
86+
var results = new ElementInit[original.Count];
87+
bool isChanged = false;
88+
for (int i = 0, n = original.Count; i < n; i++) {
89+
var originalIntializer = original[i];
90+
ElementInit p = VisitElementInitializer(originalIntializer);
91+
results[i] = p;
92+
isChanged |= !ReferenceEquals(originalIntializer, p);
93+
}
94+
return isChanged ? results : original;
95+
}
96+
6697
/// <inheritdoc/>
6798
protected override Expression VisitUnary(UnaryExpression u)
6899
{
@@ -133,7 +164,7 @@ protected override Expression VisitMemberAccess(MemberExpression m)
133164
protected override Expression VisitMethodCall(MethodCallExpression mc)
134165
{
135166
Expression instance = Visit(mc.Object);
136-
IEnumerable<Expression> arguments = VisitExpressionList(mc.Arguments);
167+
IEnumerable<Expression> arguments = VisitExpressionList((IReadOnlyList<Expression>) mc.Arguments);
137168
if ((instance==mc.Object) && (arguments==mc.Arguments))
138169
return mc;
139170
return Expression.Call(instance, mc.Method, arguments);
@@ -164,7 +195,7 @@ protected override Expression VisitLambda(LambdaExpression l)
164195
/// <inheritdoc/>
165196
protected override Expression VisitNew(NewExpression n)
166197
{
167-
IEnumerable<Expression> arguments = VisitExpressionList(n.Arguments);
198+
IEnumerable<Expression> arguments = VisitExpressionList((IReadOnlyList<Expression>) n.Arguments);
168199
if (arguments==n.Arguments)
169200
return n;
170201
if (n.Members!=null)
@@ -176,7 +207,7 @@ protected override Expression VisitNew(NewExpression n)
176207
protected override Expression VisitMemberInit(MemberInitExpression mi)
177208
{
178209
var newExpression = (NewExpression) VisitNew(mi.NewExpression);
179-
IEnumerable<MemberBinding> bindings = VisitBindingList(mi.Bindings);
210+
IEnumerable<MemberBinding> bindings = VisitBindingList((IReadOnlyList<MemberBinding>)mi.Bindings);
180211
if ((newExpression==mi.NewExpression) && (bindings==mi.Bindings))
181212
return mi;
182213
return Expression.MemberInit(newExpression, bindings);
@@ -186,7 +217,7 @@ protected override Expression VisitMemberInit(MemberInitExpression mi)
186217
protected override Expression VisitListInit(ListInitExpression li)
187218
{
188219
var newExpression = (NewExpression) VisitNew(li.NewExpression);
189-
IEnumerable<ElementInit> initializers = VisitElementInitializerList(li.Initializers);
220+
IEnumerable<ElementInit> initializers = VisitElementInitializerList((IReadOnlyList<ElementInit>) li.Initializers);
190221
if ((newExpression==li.NewExpression) && (initializers==li.Initializers))
191222
return li;
192223
return Expression.ListInit(newExpression, initializers);
@@ -195,7 +226,7 @@ protected override Expression VisitListInit(ListInitExpression li)
195226
/// <inheritdoc/>
196227
protected override Expression VisitNewArray(NewArrayExpression na)
197228
{
198-
IEnumerable<Expression> initializers = VisitExpressionList(na.Expressions);
229+
IEnumerable<Expression> initializers = VisitExpressionList((IReadOnlyList<Expression>) na.Expressions);
199230
if (initializers==na.Expressions)
200231
return na;
201232
if (na.NodeType==ExpressionType.NewArrayInit)
@@ -206,7 +237,7 @@ protected override Expression VisitNewArray(NewArrayExpression na)
206237
/// <inheritdoc/>
207238
protected override Expression VisitInvocation(InvocationExpression i)
208239
{
209-
IEnumerable<Expression> arguments = VisitExpressionList(i.Arguments);
240+
IEnumerable<Expression> arguments = VisitExpressionList((IReadOnlyList<Expression>) i.Arguments);
210241
Expression expression = Visit(i.Expression);
211242
if ((arguments==i.Arguments) && (expression==i.Expression))
212243
return i;
@@ -241,7 +272,7 @@ protected virtual MemberBinding VisitBinding(MemberBinding binding)
241272
/// <returns>Visit result.</returns>
242273
protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
243274
{
244-
IEnumerable<MemberBinding> bindings = VisitBindingList(binding.Bindings);
275+
IEnumerable<MemberBinding> bindings = VisitBindingList((IReadOnlyList<MemberBinding>) binding.Bindings);
245276
if (bindings!=binding.Bindings) {
246277
return Expression.MemberBind(binding.Member, bindings);
247278
}
@@ -255,7 +286,7 @@ protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBindi
255286
/// <returns>Visit result.</returns>
256287
protected virtual ReadOnlyCollection<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original)
257288
{
258-
var results = new List<MemberBinding>();
289+
var results = new List<MemberBinding>(original.Count);
259290
bool isChanged = false;
260291
for (int i = 0, n = original.Count; i < n; i++) {
261292
var originalBinding = original[i];
@@ -266,9 +297,27 @@ protected virtual ReadOnlyCollection<MemberBinding> VisitBindingList(ReadOnlyCol
266297
return isChanged ? results.AsReadOnly() : original;
267298
}
268299

300+
/// <summary>
301+
/// Visits the binding list.
302+
/// </summary>
303+
/// <param name="original">The original binding list.</param>
304+
/// <returns>Visit result.</returns>
305+
protected virtual IReadOnlyList<MemberBinding> VisitBindingList(IReadOnlyList<MemberBinding> original)
306+
{
307+
var results = new MemberBinding[original.Count];
308+
bool isChanged = false;
309+
for (int i = 0, n = original.Count; i < n; i++) {
310+
var originalBinding = original[i];
311+
MemberBinding p = VisitBinding(originalBinding);
312+
results[i] = p;
313+
isChanged |= !ReferenceEquals(originalBinding, p);
314+
}
315+
return isChanged ? results : original;
316+
}
317+
269318
protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
270319
{
271-
IEnumerable<ElementInit> initializers = VisitElementInitializerList(binding.Initializers);
320+
IEnumerable<ElementInit> initializers = VisitElementInitializerList((IReadOnlyList<ElementInit>) binding.Initializers);
272321
if (initializers!=binding.Initializers)
273322
return Expression.ListBind(binding.Member, initializers);
274323
return binding;

Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ protected virtual ReadOnlyCollection<TResult> VisitExpressionList(ReadOnlyCollec
152152
return results.AsReadOnly();
153153
}
154154

155+
/// <summary>
156+
/// Visits the expression list.
157+
/// </summary>
158+
/// <param name="expressions">The expression list.</param>
159+
/// <returns>Visit result.</returns>
160+
protected virtual IReadOnlyList<TResult> VisitExpressionList(IReadOnlyList<Expression> expressions)
161+
{
162+
var results = new TResult[expressions.Count];
163+
for (int i = 0, n = expressions.Count; i < n; i++) {
164+
results[i] = Visit(expressions[i]);
165+
}
166+
return results;
167+
}
168+
155169
/// <summary>
156170
/// Visits the unknown expression.
157171
/// </summary>

Orm/Xtensive.Orm/Linq/ExpressionWriter.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
using System;
88
using System.Collections;
9+
using System.Collections.Generic;
910
using System.Diagnostics;
1011
using System.IO;
1112
using System.Linq;
@@ -442,6 +443,20 @@ protected override System.Collections.ObjectModel.ReadOnlyCollection<ElementInit
442443
return original;
443444
}
444445

446+
/// <inheritdoc/>
447+
protected override IReadOnlyList<ElementInit> VisitElementInitializerList(IReadOnlyList<ElementInit> original)
448+
{
449+
for (int i = 0, n = original.Count; i < n; i++) {
450+
VisitElementInitializer(original[i]);
451+
if (i < n - 1) {
452+
Write(",");
453+
WriteLine(IndentType.Same);
454+
}
455+
}
456+
457+
return original;
458+
}
459+
445460
/// <inheritdoc/>
446461
protected override System.Collections.ObjectModel.ReadOnlyCollection<Expression> VisitExpressionList(
447462
System.Collections.ObjectModel.ReadOnlyCollection<Expression> expressions)
@@ -457,6 +472,20 @@ protected override System.Collections.ObjectModel.ReadOnlyCollection<Expression>
457472
return expressions;
458473
}
459474

475+
/// <inheritdoc/>
476+
protected override IReadOnlyList<Expression> VisitExpressionList(IReadOnlyList<Expression> expressions)
477+
{
478+
for (int i = 0, n = expressions.Count; i < n; i++) {
479+
Visit(expressions[i]);
480+
if (i < n - 1) {
481+
Write(",");
482+
WriteLine(IndentType.Same);
483+
}
484+
}
485+
486+
return expressions;
487+
}
488+
460489
/// <inheritdoc/>
461490
protected override InvocationExpression VisitInvocation(InvocationExpression i)
462491
{
@@ -576,7 +605,7 @@ protected override MethodCallExpression VisitMethodCall(MethodCallExpression mc)
576605
if (mc.Method.GetAttributes<ExtensionAttribute>(AttributeSearchOptions.InheritNone).Count > 0) {
577606
// A special case: extension method
578607
Visit(mc.Arguments[0]);
579-
arguments = new System.Collections.ObjectModel.ReadOnlyCollection<Expression>(mc.Arguments.Skip(1).ToList());
608+
arguments = new System.Collections.ObjectModel.ReadOnlyCollection<Expression>(mc.Arguments.Skip(1).ToList(mc.Arguments.Count - 1));
580609
}
581610
else {
582611
Write(GetTypeName(mc.Method.DeclaringType));

Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ public IList<LogConfiguration> Logs {
4343

4444
public override void Lock(bool recursive)
4545
{
46-
if (logs is List<LogConfiguration>nativeList) {
47-
logs = nativeList.AsReadOnly();
48-
}
49-
else {
50-
logs = logs.ToList().AsReadOnly();
51-
}
46+
#if NET8_0_OR_GREATER
47+
logs = logs.AsReadOnly();
48+
#else
49+
logs = logs switch {
50+
List<LogConfiguration> nativeList1 => nativeList1.AsReadOnly(),
51+
_ => logs.ToList().AsReadOnly()
52+
};
53+
#endif
5254
base.Lock(recursive);
5355

5456
foreach (var log in logs) {

Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/IHasNestedNodes.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ namespace Xtensive.Orm.Internals.Prefetch
1111
{
1212
internal interface IHasNestedNodes
1313
{
14-
ReadOnlyCollection<BaseFieldNode> NestedNodes { get; }
14+
IReadOnlyList<BaseFieldNode> NestedNodes { get; }
1515

16-
IReadOnlyCollection<Key> ExtractKeys(object target);
16+
IReadOnlyList<Key> ExtractKeys(object target);
1717

18-
IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection<BaseFieldNode> nestedNodes);
18+
IHasNestedNodes ReplaceNestedNodes(IReadOnlyList<BaseFieldNode> nestedNodes);
1919
}
2020
}

Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/KeyExtractorNode.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ namespace Xtensive.Orm.Internals.Prefetch
1313
{
1414
internal class KeyExtractorNode<T> : Node, IHasNestedNodes
1515
{
16-
public Func<T, IReadOnlyCollection<Key>> KeyExtractor { get; }
16+
public Func<T, IReadOnlyList<Key>> KeyExtractor { get; }
1717

18-
public ReadOnlyCollection<BaseFieldNode> NestedNodes { get; }
18+
public IReadOnlyList<BaseFieldNode> NestedNodes { get; }
1919

20-
IReadOnlyCollection<Key> IHasNestedNodes.ExtractKeys(object target)
20+
IReadOnlyList<Key> IHasNestedNodes.ExtractKeys(object target)
2121
{
2222
return ExtractKeys((T) target);
2323
}
2424

25-
public IReadOnlyCollection<Key> ExtractKeys(T target)
25+
public IReadOnlyList<Key> ExtractKeys(T target)
2626
{
2727
return KeyExtractor.Invoke(target);
2828
}
2929

30-
public IHasNestedNodes ReplaceNestedNodes(ReadOnlyCollection<BaseFieldNode> nestedNodes)
30+
public IHasNestedNodes ReplaceNestedNodes(IReadOnlyList<BaseFieldNode> nestedNodes)
3131
{
3232
return new KeyExtractorNode<T>(KeyExtractor, nestedNodes);
3333
}
@@ -42,7 +42,7 @@ protected override string GetDescription()
4242
return $"KeyExtraction<{typeof(T).Name}>";
4343
}
4444

45-
public KeyExtractorNode(Func<T, IReadOnlyCollection<Key>> extractor, ReadOnlyCollection<BaseFieldNode> nestedNodes)
45+
public KeyExtractorNode(Func<T, IReadOnlyList<Key>> extractor, IReadOnlyList<BaseFieldNode> nestedNodes)
4646
: base("*")
4747
{
4848
ArgumentValidator.EnsureArgumentNotNull(extractor, nameof(extractor));

Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeAggregator.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ public static IList<KeyExtractorNode<T>> Aggregate(IEnumerable<KeyExtractorNode<
1818
var result = source
1919
.GroupBy(ken => ken.Path, (path, @group) =>
2020
(Node) @group.First().ReplaceNestedNodes(
21-
new ReadOnlyCollection<BaseFieldNode>(
22-
@group.SelectMany(ken => ken.NestedNodes).ToList())))
21+
@group.SelectMany(ken => ken.NestedNodes).ToList()))
2322
.Select(aggregator.Visit)
2423
.Cast<KeyExtractorNode<T>>()
2524
.ToList();
2625
return result;
2726
}
2827

29-
public override ReadOnlyCollection<BaseFieldNode> VisitNodeList(ReadOnlyCollection<BaseFieldNode> nodes)
28+
public override IReadOnlyList<BaseFieldNode> VisitNodeList(IReadOnlyList<BaseFieldNode> nodes)
3029
{
3130
var result = new List<BaseFieldNode>();
3231
foreach (var group in nodes.Where(n => n!=null).GroupBy(n => n.Path)) {
@@ -36,11 +35,11 @@ public override ReadOnlyCollection<BaseFieldNode> VisitNodeList(ReadOnlyCollecti
3635
result.Add(node);
3736
else {
3837
var nodeToVisit = (BaseFieldNode) container.ReplaceNestedNodes(
39-
new ReadOnlyCollection<BaseFieldNode>(group.Cast<IHasNestedNodes>().SelectMany(c => c.NestedNodes).ToList()));
38+
group.Cast<IHasNestedNodes>().SelectMany(c => c.NestedNodes).ToList());
4039
result.Add((BaseFieldNode) Visit(nodeToVisit));
4140
}
4241
}
43-
return new ReadOnlyCollection<BaseFieldNode>(result);
42+
return result;
4443
}
4544

4645
// Constructor

Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2012-2020 Xtensive LLC.
1+
// Copyright (C) 2012-2020 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
@@ -34,7 +34,7 @@ public static KeyExtractorNode<T> Build<T, TValue>(DomainModel model, Expression
3434
return new KeyExtractorNode<T>(GetExtractor<T>(), nestedNodes);
3535
}
3636

37-
private static Func<T, IReadOnlyCollection<Key>> GetExtractor<T>()
37+
private static Func<T, IReadOnlyList<Key>> GetExtractor<T>()
3838
{
3939
return target => new[] {((IEntity) target).Key};
4040
}

Orm/Xtensive.Orm/Orm/Internals/Prefetch/Nodes/NodeVisitor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Created by: Alexis Kochetov
55
// Created: 2011.01.14
66

7-
using System.Collections.ObjectModel;
7+
using System.Collections.Generic;
88

99
namespace Xtensive.Orm.Internals.Prefetch
1010
{
@@ -17,7 +17,7 @@ public virtual Node Visit(Node node)
1717
return node.Accept(this);
1818
}
1919

20-
public virtual ReadOnlyCollection<BaseFieldNode> VisitNodeList(ReadOnlyCollection<BaseFieldNode> nodes)
20+
public virtual IReadOnlyList<BaseFieldNode> VisitNodeList(IReadOnlyList<BaseFieldNode> nodes)
2121
{
2222
BaseFieldNode[] list = null;
2323
var index = 0;
@@ -37,7 +37,7 @@ public virtual ReadOnlyCollection<BaseFieldNode> VisitNodeList(ReadOnlyCollectio
3737
}
3838
return list==null
3939
? nodes
40-
: new ReadOnlyCollection<BaseFieldNode>(list);
40+
: list;
4141
}
4242

4343
public virtual Node VisitKeyExtractorNode<T>(KeyExtractorNode<T> keyExtractorNode)

0 commit comments

Comments
 (0)