-
-
Notifications
You must be signed in to change notification settings - Fork 722
/
ObjectResult.cs
252 lines (218 loc) · 6.88 KB
/
ObjectResult.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using HotChocolate.Utilities;
namespace HotChocolate.Execution.Processing;
/// <summary>
/// Represents an optimized object result that is used by the execution engine
/// to store completed values.
/// </summary>
public sealed class ObjectResult
: ResultData
, IReadOnlyDictionary<string, object?>
, IEnumerable<ObjectFieldResult>
{
private ObjectFieldResult[] _buffer = Array.Empty<ObjectFieldResult>();
private int _capacity;
/// <summary>
/// Gets the capacity of this object result.
/// It essentially specifies how many field results can be stored.
/// </summary>
internal int Capacity => _capacity;
/// <summary>
/// This indexer allows direct access to the underlying buffer
/// to access a <see cref="ObjectFieldResult"/>.
/// </summary>
internal ObjectFieldResult this[int index] => _buffer[index];
/// <summary>
/// Gets a reference to the first <see cref="ObjectFieldResult"/> in the buffer.
/// </summary>
internal ref ObjectFieldResult GetReference()
=> ref MemoryMarshal.GetReference(_buffer.AsSpan());
/// <summary>
/// Sets a field value in the buffer.
/// Note: Set will not validate if the buffer has enough space.
/// </summary>
/// <param name="index">
/// The index in the buffer on which the value shall be stored.
/// </param>
/// <param name="name">
/// The name of the field.
/// </param>
/// <param name="value">
/// The field value.
/// </param>
/// <param name="isNullable">
/// Specifies if the value is allowed to be null.
/// </param>
internal void SetValueUnsafe(int index, string name, object? value, bool isNullable = true)
=> _buffer[index].Set(name, value, isNullable);
/// <summary>
/// Sets a field value in the buffer.
/// Note: Set will not validate if the buffer has enough space.
/// </summary>
/// <param name="index">
/// The index in the buffer on which the value shall be stored.
/// </param>
/// <param name="name">
/// The name of the field.
/// </param>
/// <param name="value">
/// The field value.
/// </param>
/// <param name="isNullable">
/// Specifies if the value is allowed to be null.
/// </param>
internal void SetValueUnsafe(int index, string name, ResultData? value, bool isNullable = true)
{
if (value is not null)
{
value.Parent = this;
}
_buffer[index].Set(name, value, isNullable);
}
/// <summary>
/// Removes a field value from the buffer.
/// Note: Remove will not validate if the buffer has enough space.
/// </summary>
/// <param name="index">
/// The index in the buffer on which the value shall be removed.
/// </param>
internal void RemoveValueUnsafe(int index)
=> _buffer[index].Reset();
/// <summary>
/// Searches within the capacity of the buffer to find a field value that matches
/// the specified <paramref name="name"/>.
/// </summary>
/// <param name="name">
/// The name of the field to search for.
/// </param>
/// <param name="index">
/// The index on the buffer where the field value is located.
/// </param>
/// <returns>
/// Returns the field value or null.
/// </returns>
internal ObjectFieldResult? TryGetValue(string name, out int index)
{
ref var searchSpace = ref MemoryMarshal.GetReference(_buffer.AsSpan());
for(var i = 0; i < _capacity; i++)
{
var item = Unsafe.Add(ref searchSpace, i);
if (name.EqualsOrdinal(item.Name))
{
index = i;
return item;
}
}
index = -1;
return default;
}
/// <summary>
/// Ensures that the result object has enough capacity on the buffer
/// to store the expected fields.
/// </summary>
/// <param name="capacity">
/// The capacity needed.
/// </param>
internal void EnsureCapacity(int capacity)
{
if (_capacity > 0)
{
Reset();
}
if (_buffer.Length < capacity)
{
var oldCapacity = _buffer.Length;
Array.Resize(ref _buffer, capacity);
for (var i = oldCapacity; i < _buffer.Length; i++)
{
var field = new ObjectFieldResult();
_buffer[i] = field;
}
}
_capacity = capacity;
}
/// <summary>
/// Resets the result object.
/// </summary>
internal void Reset()
{
ref var searchSpace = ref MemoryMarshal.GetReference(_buffer.AsSpan());
for(var i = 0; i < _capacity; i++)
{
Unsafe.Add(ref searchSpace, i).Reset();
}
_capacity = 0;
}
object? IReadOnlyDictionary<string, object?>.this[string key]
=> TryGetValue(key, out _)?.Value;
IEnumerable<string> IReadOnlyDictionary<string, object?>.Keys
{
get
{
for (var i = 0; i < _capacity; i++)
{
var field = _buffer[i];
if (field.IsInitialized)
{
yield return field.Name;
}
}
}
}
IEnumerable<object?> IReadOnlyDictionary<string, object?>.Values
{
get
{
for (var i = 0; i < _capacity; i++)
{
var field = _buffer[i];
if (field.IsInitialized)
{
yield return field.Value;
}
}
}
}
int IReadOnlyCollection<KeyValuePair<string, object?>>.Count => _capacity;
bool IReadOnlyDictionary<string, object?>.ContainsKey(string key)
=> TryGetValue(key, out _)?.Name is not null;
bool IReadOnlyDictionary<string, object?>.TryGetValue(string key, out object? value)
{
var field = TryGetValue(key, out _);
if (field?.Name is not null)
{
value = field.Value;
return true;
}
value = null;
return true;
}
public IEnumerator<ObjectFieldResult> GetEnumerator()
{
for (var i = 0; i < _capacity; i++)
{
var field = _buffer[i];
if (field.IsInitialized)
{
yield return field;
}
}
}
IEnumerator<KeyValuePair<string, object?>>
IEnumerable<KeyValuePair<string, object?>>.GetEnumerator()
{
for (var i = 0; i < _capacity; i++)
{
var field = _buffer[i];
if (field.IsInitialized)
{
yield return new KeyValuePair<string, object?>(field.Name, field.Value);
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}