Skip to content

Commit dfad886

Browse files
authored
Convert TranslatorScope from class to readonly ref struct (#25)
This reduces memory traffic and speeds up frequent operations
1 parent f255153 commit dfad886

File tree

4 files changed

+108
-35
lines changed

4 files changed

+108
-35
lines changed

Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
</PropertyGroup>
2323

2424
<PropertyGroup>
25+
<LangVersion>8.0</LangVersion>
2526
<SolutionDir Condition="$(SolutionDir) == ''">$(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/'))\</SolutionDir>
2627
<Configuration Condition="$(Configuration) == ''">Debug</Configuration>
2728
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>

Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ protected override Expression VisitUnary(UnaryExpression u)
111111
return base.VisitUnary(u);
112112
throw new InvalidOperationException(String.Format(Strings.ExDowncastFromXToXNotSupportedUseOfTypeOrAsOperatorInstead, u, u.Operand.Type, u.Type));
113113
}
114-
else if (u.Type==typeof (object) && state.ShouldOmmitConvertToObject) {
114+
else if (u.Type==typeof (object) && state.ShouldOmitConvertToObject) {
115115
var expression = u.StripCasts();
116116
return Visit(expression);
117117
}

Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ private Expression VisitSort(Expression expression)
946946
var sortParameter = sortExpression.Parameters[0];
947947
using (context.Bindings.Add(sortParameter, projection))
948948
using (state.CreateScope()) {
949-
state.ShouldOmmitConvertToObject = true;
949+
state.ShouldOmitConvertToObject = true;
950950
state.CalculateExpressions = true;
951951
var orderByProjector = (ItemProjectorExpression) VisitLambda(sortExpression);
952952
var columns = orderByProjector

Orm/Xtensive.Orm/Orm/Linq/TranslatorState.cs

Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,45 @@
55
// Created: 2010.01.21
66

77
using System;
8-
using System.Linq;
98
using System.Linq.Expressions;
10-
using Xtensive.Collections;
119
using Xtensive.Core;
1210

1311
namespace Xtensive.Orm.Linq
1412
{
1513
internal sealed class TranslatorState
1614
{
15+
[Flags]
16+
private enum TranslatorStateFlags
17+
{
18+
JoinLocalCollectionEntity = 1,
19+
AllowCalculableColumnCombine = 1 << 1,
20+
IsBuildingProjection = 1 << 2,
21+
CalculateExpressions = 1 << 3,
22+
IsGroupingKey = 1 << 4,
23+
IsTailMethod = 1 << 5,
24+
ShouldOmitConvertToObject = 1 << 6,
25+
RequestCalculateExpressions = 1 << 7,
26+
RequestCalculateExpressionsOnce = 1 << 8
27+
}
28+
29+
internal readonly ref struct TranslatorScope
30+
{
31+
private readonly TranslatorState previousState;
32+
private readonly Translator translator;
33+
34+
public void Dispose() => translator.state = previousState;
35+
36+
public TranslatorScope(Translator translator, TranslatorState previousState)
37+
{
38+
this.translator = translator;
39+
this.previousState = previousState;
40+
}
41+
}
42+
1743
private readonly Translator translator;
1844

45+
private TranslatorStateFlags flags;
46+
1947
public ParameterExpression[] Parameters { get; set; }
2048

2149
public ParameterExpression[] OuterParameters { get; set; }
@@ -26,43 +54,96 @@ internal sealed class TranslatorState
2654

2755
public Type TypeOfEntityStoredInKey { get; set; }
2856

29-
public bool JoinLocalCollectionEntity { get; set; }
57+
public bool JoinLocalCollectionEntity
58+
{
59+
get => (flags & TranslatorStateFlags.JoinLocalCollectionEntity) != 0;
60+
set => flags = value
61+
? flags | TranslatorStateFlags.JoinLocalCollectionEntity
62+
: flags & ~TranslatorStateFlags.JoinLocalCollectionEntity;
63+
}
3064

31-
public bool AllowCalculableColumnCombine { get; set; }
65+
public bool AllowCalculableColumnCombine {
66+
get => (flags & TranslatorStateFlags.AllowCalculableColumnCombine) != 0;
67+
set => flags = value
68+
? flags | TranslatorStateFlags.AllowCalculableColumnCombine
69+
: flags & ~TranslatorStateFlags.AllowCalculableColumnCombine;
70+
}
3271

33-
public bool BuildingProjection { get; set; }
72+
public bool BuildingProjection
73+
{
74+
get => (flags & TranslatorStateFlags.IsBuildingProjection) != 0;
75+
set => flags = value
76+
? flags | TranslatorStateFlags.IsBuildingProjection
77+
: flags & ~TranslatorStateFlags.IsBuildingProjection;
78+
}
3479

35-
public bool CalculateExpressions { get; set; }
80+
public bool CalculateExpressions
81+
{
82+
get => (flags & TranslatorStateFlags.CalculateExpressions) != 0;
83+
set => flags = value
84+
? flags | TranslatorStateFlags.CalculateExpressions
85+
: flags & ~TranslatorStateFlags.CalculateExpressions;
86+
}
3687

37-
public bool GroupingKey { get; set; }
88+
public bool GroupingKey
89+
{
90+
get => (flags & TranslatorStateFlags.IsGroupingKey) != 0;
91+
set => flags = value
92+
? flags | TranslatorStateFlags.IsGroupingKey
93+
: flags & ~TranslatorStateFlags.IsGroupingKey;
94+
}
3895

39-
public bool IsTailMethod { get; set; }
96+
public bool IsTailMethod
97+
{
98+
get => (flags & TranslatorStateFlags.IsTailMethod) != 0;
99+
set => flags = value
100+
? flags | TranslatorStateFlags.IsTailMethod
101+
: flags & ~TranslatorStateFlags.IsTailMethod;
102+
}
40103

41-
public bool ShouldOmmitConvertToObject { get; set; }
104+
public bool ShouldOmitConvertToObject
105+
{
106+
get => (flags & TranslatorStateFlags.ShouldOmitConvertToObject) != 0;
107+
set => flags = value
108+
? flags | TranslatorStateFlags.ShouldOmitConvertToObject
109+
: flags & ~TranslatorStateFlags.ShouldOmitConvertToObject;
110+
}
42111

43-
public bool RequestCalculateExpressions { get; set; }
112+
public bool RequestCalculateExpressions
113+
{
114+
get => (flags & TranslatorStateFlags.RequestCalculateExpressions) != 0;
115+
set => flags = value
116+
? flags | TranslatorStateFlags.RequestCalculateExpressions
117+
: flags & ~TranslatorStateFlags.RequestCalculateExpressions;
118+
}
44119

45-
public bool RequestCalculateExpressionsOnce { get; set; }
120+
public bool RequestCalculateExpressionsOnce
121+
{
122+
get => (flags & TranslatorStateFlags.RequestCalculateExpressionsOnce) != 0;
123+
set => flags = value
124+
? flags | TranslatorStateFlags.RequestCalculateExpressionsOnce
125+
: flags & ~TranslatorStateFlags.RequestCalculateExpressionsOnce;
126+
}
46127

47-
public IDisposable CreateScope()
128+
public TranslatorScope CreateScope()
48129
{
49130
var currentState = translator.state;
50-
var newState = new TranslatorState(currentState);
51-
translator.state = newState;
52-
return new Disposable(_ => translator.state = currentState);
131+
translator.state = new TranslatorState(currentState);
132+
return new TranslatorScope(translator, currentState);
53133
}
54134

55-
public IDisposable CreateLambdaScope(LambdaExpression le)
135+
public TranslatorScope CreateLambdaScope(LambdaExpression le)
56136
{
57137
var currentState = translator.state;
58138
var newState = new TranslatorState(currentState);
59-
newState.OuterParameters = newState.OuterParameters.Concat(newState.Parameters).ToArray();
60-
newState.Parameters = Enumerable.ToArray(le.Parameters);
139+
var newOuterParameters = new ParameterExpression[newState.OuterParameters.Length + newState.Parameters.Length];
140+
newState.OuterParameters.CopyTo(newOuterParameters, 0);
141+
newState.Parameters.CopyTo(newOuterParameters, newState.OuterParameters.Length);
142+
newState.OuterParameters = newOuterParameters;
143+
newState.Parameters = le.Parameters.ToArray(le.Parameters.Count);
61144
newState.CurrentLambda = le;
62-
newState.IncludeAlgorithm = IncludeAlgorithm;
63-
newState.IsTailMethod = IsTailMethod;
64145
translator.state = newState;
65-
return new Disposable(_ => translator.state = currentState);
146+
return new TranslatorScope(translator, currentState);
66147
}
67148

68149

@@ -71,30 +152,21 @@ public IDisposable CreateLambdaScope(LambdaExpression le)
71152
public TranslatorState(Translator translator)
72153
{
73154
this.translator = translator;
155+
flags = TranslatorStateFlags.IsBuildingProjection | TranslatorStateFlags.IsTailMethod;
156+
OuterParameters = Parameters = Array.Empty<ParameterExpression>();
74157
IncludeAlgorithm = IncludeAlgorithm.Auto;
75-
BuildingProjection = true;
76-
IsTailMethod = true;
77158
TypeOfEntityStoredInKey = null;
78-
OuterParameters = Parameters = ArrayUtils<ParameterExpression>.EmptyArray;
79159
}
80160

81161
private TranslatorState(TranslatorState currentState)
82162
{
83163
translator = currentState.translator;
164+
flags = currentState.flags;
84165
Parameters = currentState.Parameters;
85166
OuterParameters = currentState.OuterParameters;
86-
CalculateExpressions = currentState.CalculateExpressions;
87-
BuildingProjection = currentState.BuildingProjection;
88167
CurrentLambda = currentState.CurrentLambda;
89-
JoinLocalCollectionEntity = currentState.JoinLocalCollectionEntity;
90-
AllowCalculableColumnCombine = currentState.AllowCalculableColumnCombine;
91168
IncludeAlgorithm = currentState.IncludeAlgorithm;
92-
IsTailMethod = currentState.IsTailMethod;
93-
GroupingKey = currentState.GroupingKey;
94-
RequestCalculateExpressionsOnce = currentState.RequestCalculateExpressionsOnce;
95-
RequestCalculateExpressions = currentState.RequestCalculateExpressions;
96169
TypeOfEntityStoredInKey = currentState.TypeOfEntityStoredInKey;
97-
ShouldOmmitConvertToObject = currentState.ShouldOmmitConvertToObject;
98170
}
99171
}
100172
}

0 commit comments

Comments
 (0)