Skip to content

Commit d722296

Browse files
authored
Merge pull request #128 from dlmelendez/rel/9.0
TableQueryBuilder refactor
2 parents 4ad8939 + 749e22d commit d722296

File tree

2 files changed

+58
-24
lines changed

2 files changed

+58
-24
lines changed

src/ElCamino.Azure.Data.Tables/TableQueryBuilder.cs

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public ref struct TableQueryBuilder
1818
/// </summary>
1919
public TableQueryBuilder() { }
2020

21-
private Span<char> _currentQuery = [];
21+
private const int BufferSize = 1024;
22+
private Span<char> _bufferQuery = new(new char[BufferSize]);
23+
private int _currentQueryLength = 0;
2224
private uint _filterCount = 0;
2325
private uint _beginGroupCount = 0;
2426
private uint _endGroupCount = 0;
@@ -28,21 +30,42 @@ public TableQueryBuilder() { }
2830
/// </summary>
2931
public bool HasFilter => _filterCount > 0;
3032

33+
/// <summary>
34+
/// Gets the current query filter.
35+
/// </summary>
36+
public ReadOnlySpan<char> QueryFilter => _bufferQuery.Slice(0, _currentQueryLength);
37+
38+
private void AllocateBuffer(int lengthToAdd)
39+
{
40+
if ((_currentQueryLength + lengthToAdd > _bufferQuery.Length))
41+
{
42+
Span<char> newBuffer = stackalloc char[_bufferQuery.Length + BufferSize];
43+
QueryFilter.CopyTo(newBuffer);
44+
_bufferQuery = new Span<char>([..newBuffer]);
45+
}
46+
}
47+
3148
private void AppendCondition(ReadOnlySpan<char> condition)
3249
{
33-
if(_currentQuery.IsEmpty)
50+
int segmentLength = condition.Length + 2;
51+
52+
if (_currentQueryLength <= 0)
3453
{
35-
_currentQuery = new Span<char>(['(', .. condition, ')']);
54+
_bufferQuery[0] = '(';
55+
condition.CopyTo(_bufferQuery[1..]);
56+
_bufferQuery[^1] = ')';
3657
}
3758
else
3859
{
39-
Span<char> temp = stackalloc char[_currentQuery.Length + condition.Length + 2];
40-
_currentQuery.CopyTo(temp);
41-
temp[_currentQuery.Length] = '(';
42-
condition.CopyTo(temp[(_currentQuery.Length + 1)..]);
60+
Span<char> temp = stackalloc char[_currentQueryLength + segmentLength];
61+
AllocateBuffer(segmentLength);
62+
QueryFilter.CopyTo(temp);
63+
temp[_currentQueryLength] = '(';
64+
condition.CopyTo(temp[(_currentQueryLength + 1)..]);
4365
temp[^1] = ')';
44-
_currentQuery = new Span<char>(temp.ToArray());
66+
temp.CopyTo(_bufferQuery);
4567
}
68+
_currentQueryLength += segmentLength;
4669
_filterCount++;
4770
_beginGroupCount++;
4871
_endGroupCount++;
@@ -137,43 +160,53 @@ public TableQueryBuilder GroupAll()
137160

138161
private void AppendBeginGroup()
139162
{
140-
Span<char> temp = stackalloc char[_currentQuery.Length + 1];
141-
_currentQuery.CopyTo(temp);
163+
AllocateBuffer(1);
164+
Span<char> temp = stackalloc char[_currentQueryLength + 1];
165+
QueryFilter.CopyTo(temp);
142166
temp[^1] = '(';
143-
_currentQuery = new Span<char>(temp.ToArray());
167+
temp.CopyTo(_bufferQuery);
168+
_currentQueryLength++;
144169
_beginGroupCount++;
145170
}
146171

147172
private void AppendEndGroup()
148173
{
149174
ThrowIfNoFilter();
150-
Span<char> temp = stackalloc char[_currentQuery.Length + 1];
151-
_currentQuery.CopyTo(temp);
175+
AllocateBuffer(1);
176+
Span<char> temp = stackalloc char[_currentQueryLength + 1];
177+
QueryFilter.CopyTo(temp);
152178
temp[^1] = ')';
153-
_currentQuery = new Span<char>(temp.ToArray());
179+
temp.CopyTo(_bufferQuery);
180+
_currentQueryLength++;
154181
_endGroupCount++;
155182
}
156183

157184
private void PrependAppendGroupAll()
158185
{
159186
ThrowIfNoFilter();
160-
Span<char> temp = stackalloc char[_currentQuery.Length + 2];
187+
AllocateBuffer(2);
188+
Span<char> temp = stackalloc char[_currentQueryLength + 2];
161189
temp[0] = '(';
162-
_currentQuery.CopyTo(temp[1..]);
190+
QueryFilter.CopyTo(temp[1..]);
163191
_beginGroupCount++;
164192
temp[^1] = ')';
165193
_endGroupCount++;
166-
_currentQuery = new Span<char>(temp.ToArray());
194+
temp.CopyTo(_bufferQuery);
195+
_currentQueryLength += 2;
167196
}
168197

169198
private void AppendTableOperator(TableOperator tableOperator)
170199
{
171200
ThrowIfNoFilter();
172201
ReadOnlySpan<char> tableOperatorSpan = $" {TableOperators.GetOperator(tableOperator)} ".AsSpan();
173-
Span<char> temp = stackalloc char[_currentQuery.Length + tableOperatorSpan.Length];
174-
_currentQuery.CopyTo(temp);
175-
tableOperatorSpan.CopyTo(temp[_currentQuery.Length..]);
176-
_currentQuery = new Span<char>(temp.ToArray());
202+
int segmentLength = tableOperatorSpan.Length;
203+
AllocateBuffer(segmentLength);
204+
205+
Span<char> temp = stackalloc char[_currentQueryLength + segmentLength];
206+
QueryFilter.CopyTo(temp);
207+
tableOperatorSpan.CopyTo(temp[_currentQueryLength..]);
208+
temp.CopyTo(_bufferQuery);
209+
_currentQueryLength += segmentLength;
177210
}
178211

179212
private void ThrowIfNoFilter()
@@ -190,7 +223,7 @@ private void ThrowIfNoFilter()
190223
/// <returns>Returns an Odata Azure Table Storage query or an empty string</returns>
191224
public override string ToString()
192225
{
193-
return _currentQuery.ToString();
226+
return QueryFilter.ToString();
194227
}
195228
}
196229
}

tests/ElCamino.Azure.Data.Tables.Tests/TableQueryBuilderTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public void QueryBuilderNullMemory()
130130
TableQuery.CombineFilters(filterByPartitionKey, TableOperators.And, filterByRowKey),
131131
TableOperators.And,
132132
filterByNullProperty).ToString();
133-
for (int trial = 0; trial < 100; trial++)
133+
for (int trial = 0; trial < 150; trial++)
134134
{
135135
filterNull = TableQuery.CombineFilters(filterNull, TableOperators.And, filterByNullProperty).ToString();
136136
}
@@ -151,7 +151,7 @@ public void QueryBuilderNullMemory()
151151
.EndGroup()
152152
.CombineFilters(TableOperator.And)
153153
.AddFilter(new QueryCondition<string>(propertyName, QueryComparison.Equal, null));
154-
for (int trial = 0; trial < 100; trial++)
154+
for (int trial = 0; trial < 150; trial++)
155155
{
156156
queryBuilderNull = queryBuilderNull
157157
.GroupAll()
@@ -164,6 +164,7 @@ public void QueryBuilderNullMemory()
164164

165165
_output.WriteLine($"{nameof(filterNullBuilder)}: {sw.Elapsed.TotalMilliseconds}ms, Alloc: {mem / 1024.0 / 1024:N2}mb");
166166
_output.WriteLine($"{nameof(filterNullBuilder)}:{filterNullBuilder}");
167+
_output.WriteLine($"{nameof(filterNullBuilder)}:{filterNullBuilder.Length}");
167168

168169
//Assert
169170
Assert.Equal(filterNull, filterNullBuilder);

0 commit comments

Comments
 (0)