Skip to content

Commit d076a71

Browse files
committed
Improve performance of StructureFieldExpression class
1 parent ed8e13a commit d076a71

1 file changed

Lines changed: 73 additions & 52 deletions

File tree

Orm/Xtensive.Orm/Orm/Linq/Expressions/StructureFieldExpression.cs

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,49 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Linq.Expressions;
10-
using Xtensive.Collections;
1110
using Xtensive.Core;
1211
using Xtensive.Orm.Model;
1312
using System.Linq;
1413

15-
1614
namespace Xtensive.Orm.Linq.Expressions
1715
{
1816
internal sealed class StructureFieldExpression : FieldExpression,
1917
IPersistentExpression
2018
{
2119
private List<PersistentFieldExpression> fields;
22-
public TypeInfo PersistentType { get; private set; }
20+
public TypeInfo PersistentType { get; }
2321

24-
public bool IsNullable
25-
{
26-
get { return Owner != null && Owner.IsNullable; }
27-
}
22+
public bool IsNullable => Owner != null && Owner.IsNullable;
2823

2924
public List<PersistentFieldExpression> Fields
3025
{
31-
get { return fields; }
32-
private set
33-
{
26+
get => fields;
27+
private set {
3428
fields = value;
35-
foreach (var fieldExpression in fields.OfType<FieldExpression>())
29+
foreach (var fieldExpression in fields.OfType<FieldExpression>()) {
3630
fieldExpression.Owner = this;
31+
}
3732
}
3833
}
3934

4035
public override Expression Remap(int offset, Dictionary<Expression, Expression> processedExpressions)
4136
{
42-
if (!CanRemap)
37+
if (!CanRemap) {
4338
return this;
39+
}
4440

45-
Expression value;
46-
if (processedExpressions.TryGetValue(this, out value))
41+
if (processedExpressions.TryGetValue(this, out var value)) {
4742
return value;
43+
}
4844

4945
var newMapping = new Segment<int>(Mapping.Offset + offset, Mapping.Length);
5046
var result = new StructureFieldExpression(PersistentType, Field, newMapping, OuterParameter, DefaultIfEmpty);
5147
processedExpressions.Add(this, result);
52-
var processedFields = Fields
53-
.Select(f => f.Remap(offset, processedExpressions))
54-
.Cast<PersistentFieldExpression>()
55-
.ToList();
48+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
49+
foreach (var field in fields) {
50+
// Do not convert to LINQ. We want to avoid a closure creation here.
51+
processedFields.Add((PersistentFieldExpression) field.Remap(offset, processedExpressions));
52+
}
5653
if (Owner == null) {
5754
result.fields = processedFields;
5855
return result;
@@ -65,27 +62,38 @@ public override Expression Remap(int offset, Dictionary<Expression, Expression>
6562

6663
public override Expression Remap(int[] map, Dictionary<Expression, Expression> processedExpressions)
6764
{
68-
if (!CanRemap)
65+
if (!CanRemap) {
6966
return this;
67+
}
7068

71-
Expression value;
72-
if (processedExpressions.TryGetValue(this, out value))
69+
if (processedExpressions.TryGetValue(this, out var value)) {
7370
return value;
71+
}
7472

75-
var result = new StructureFieldExpression(PersistentType, Field, default(Segment<int>), OuterParameter, DefaultIfEmpty);
73+
var result = new StructureFieldExpression(PersistentType, Field, default, OuterParameter, DefaultIfEmpty);
7674
processedExpressions.Add(this, result);
77-
var processedFields = Fields
78-
.Select(f => f.Remap(map, processedExpressions))
79-
.Where(f => f != null)
80-
.Cast<PersistentFieldExpression>()
81-
.ToList();
75+
var offset = int.MaxValue;
76+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
77+
foreach (var field in fields) {
78+
var mappedField = (PersistentFieldExpression) field.Remap(map, processedExpressions);
79+
if (mappedField == null) {
80+
continue;
81+
}
82+
83+
var mappingOffset = mappedField.Mapping.Offset;
84+
if (mappingOffset < offset) {
85+
offset = mappingOffset;
86+
}
87+
88+
processedFields.Add(mappedField);
89+
}
90+
8291
if (processedFields.Count == 0) {
8392
processedExpressions[this] = null;
8493
return null;
8594
}
86-
var length = processedFields.Select(f => f.Mapping.Offset).Distinct().Count();
87-
var offset = processedFields.Min(f => f.Mapping.Offset);
88-
result.Mapping = new Segment<int>(offset, length);
95+
96+
result.Mapping = new Segment<int>(offset, processedFields.Count);
8997
if (Owner == null) {
9098
result.fields = processedFields;
9199
return result;
@@ -97,16 +105,18 @@ public override Expression Remap(int[] map, Dictionary<Expression, Expression> p
97105

98106
public override Expression BindParameter(ParameterExpression parameter, Dictionary<Expression, Expression> processedExpressions)
99107
{
100-
Expression value;
101-
if (processedExpressions.TryGetValue(this, out value))
108+
if (processedExpressions.TryGetValue(this, out var value)) {
102109
return value;
110+
}
103111

104112
var result = new StructureFieldExpression(PersistentType, Field, Mapping, OuterParameter, DefaultIfEmpty);
105113
processedExpressions.Add(this, result);
106-
var processedFields = Fields
107-
.Select(f => f.BindParameter(parameter, processedExpressions))
108-
.Cast<PersistentFieldExpression>()
109-
.ToList();
114+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
115+
foreach (var field in fields) {
116+
// Do not convert to LINQ. We want to avoid a closure creation here.
117+
processedFields.Add((PersistentFieldExpression) field.BindParameter(parameter, processedExpressions));
118+
}
119+
110120
if (Owner == null) {
111121
result.fields = processedFields;
112122
return result;
@@ -119,16 +129,18 @@ public override Expression BindParameter(ParameterExpression parameter, Dictiona
119129

120130
public override Expression RemoveOuterParameter(Dictionary<Expression, Expression> processedExpressions)
121131
{
122-
Expression value;
123-
if (processedExpressions.TryGetValue(this, out value))
132+
if (processedExpressions.TryGetValue(this, out var value)) {
124133
return value;
134+
}
125135

126136
var result = new StructureFieldExpression(PersistentType, Field, Mapping, OuterParameter, DefaultIfEmpty);
127137
processedExpressions.Add(this, result);
128-
var processedFields = Fields
129-
.Select(f => f.RemoveOuterParameter(processedExpressions))
130-
.Cast<PersistentFieldExpression>()
131-
.ToList();
138+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
139+
foreach (var field in fields) {
140+
// Do not convert to LINQ. We want to avoid a closure creation here.
141+
processedFields.Add((PersistentFieldExpression) field.RemoveOuterParameter(processedExpressions));
142+
}
143+
132144
if (Owner == null) {
133145
result.fields = processedFields;
134146
return result;
@@ -141,26 +153,35 @@ public override Expression RemoveOuterParameter(Dictionary<Expression, Expressio
141153

142154
public override FieldExpression RemoveOwner()
143155
{
144-
if (Owner==null)
156+
if (Owner==null) {
145157
return this;
146-
var result = new StructureFieldExpression(PersistentType, Field, Mapping, OuterParameter, DefaultIfEmpty);
147-
result.fields = fields
148-
.Cast<FieldExpression>()
149-
.Select(f => (PersistentFieldExpression)f.RemoveOwner())
150-
.ToList();
158+
}
159+
160+
var result = new StructureFieldExpression(PersistentType, Field, Mapping, OuterParameter, DefaultIfEmpty) {
161+
fields = new List<PersistentFieldExpression>(fields.Count)
162+
};
163+
foreach (var field in fields) {
164+
result.fields.Add(((FieldExpression) field).RemoveOwner());
165+
}
151166
return result;
152167
}
153168

154169
public static StructureFieldExpression CreateStructure(FieldInfo structureField, int offset)
155170
{
156-
if (!structureField.IsStructure)
171+
if (!structureField.IsStructure) {
157172
throw new ArgumentException(string.Format(Strings.ExFieldIsNotStructure, structureField.Name));
173+
}
174+
158175
var persistentType = structureField.ReflectedType.Model.Types[structureField.ValueType];
159176
var mapping = new Segment<int>(offset + structureField.MappingInfo.Offset, structureField.MappingInfo.Length);
160177
var result = new StructureFieldExpression(persistentType, structureField, mapping, null, false);
161-
result.Fields = persistentType.Fields
162-
.Select(f => BuildNestedFieldExpression(f, offset + structureField.MappingInfo.Offset))
163-
.ToList();
178+
var processedFields = new List<PersistentFieldExpression>(persistentType.Fields.Count);
179+
foreach (var field in persistentType.Fields) {
180+
// Do not convert to LINQ. We want to avoid a closure creation here.
181+
processedFields.Add(BuildNestedFieldExpression(field, offset + structureField.MappingInfo.Offset));
182+
}
183+
184+
result.Fields = processedFields;
164185
return result;
165186
}
166187

0 commit comments

Comments
 (0)