Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
RangesCursor.cs
1using System;
4using System.Threading.Tasks;
7
9{
14 internal class RangesCursor<T> : ICursor<T>
15 {
16 private readonly RangeInfo[] ranges;
17 private readonly IndexBTreeFile index;
18 private readonly IApplicableFilter[] additionalFilters;
19 private RangeInfo[] currentLimits;
20 private ICursor<T> currentRange;
21 private KeyValuePair<string, IApplicableFilter>[] startRangeFilters;
22 private KeyValuePair<string, IApplicableFilter>[] endRangeFilters;
23 private readonly FilesProvider provider;
24 private readonly int nrRanges;
25 private int limitsUpdatedAt;
26 private readonly bool firstAscending;
27 private readonly bool[] ascending;
28 private IObjectSerializer prevSerializer = null;
29 private Type prevType = null;
30
31
40 public RangesCursor(IndexBTreeFile Index, RangeInfo[] Ranges,
41 IApplicableFilter[] AdditionalFilters, FilesProvider Provider)
42 {
43 this.index = Index;
44 this.ranges = Ranges;
45 this.additionalFilters = AdditionalFilters;
46 this.currentRange = null;
47 this.ascending = Index.Ascending;
48 this.firstAscending = this.ascending[0];
49 this.nrRanges = this.ranges.Length;
50 this.provider = Provider;
51
52 this.Reset();
53 }
54
60 public T Current => this.CurrentCursor.Current;
61
62 private ICursor<T> CurrentCursor
63 {
64 get
65 {
66 if (this.currentRange is null)
67 throw new InvalidOperationException("Enumeration not started or has already ended.");
68 else
69 return this.currentRange;
70 }
71 }
72
76 public IObjectSerializer CurrentSerializer => this.CurrentCursor.CurrentSerializer;
77
82 public bool CurrentTypeCompatible => this.CurrentCursor.CurrentTypeCompatible;
83
89 public Guid CurrentObjectId => this.CurrentCursor.CurrentObjectId;
90
94 public void Dispose()
95 {
96 this.currentRange = null;
97 }
98
106 Task<bool> IAsyncEnumerator.MoveNextAsync() => this.MoveNextAsyncLocked();
107
113 object IEnumerator.Current => this.Current;
114
122 public bool MoveNext() => this.MoveNextAsyncLocked().Result;
123
127 public void Reset()
128 {
129 int i;
130
131 this.currentLimits = new RangeInfo[this.nrRanges];
132 this.currentRange = null;
133
134 for (i = 0; i < this.nrRanges; i++)
135 this.currentLimits[i] = this.ranges[i].Copy();
136 }
137
144 public async Task<bool> MoveNextAsyncLocked()
145 {
146 int i;
147
148 while (true)
149 {
150 if (this.currentRange is null)
151 {
155 RangeInfo Range;
156 object Value;
157
158 for (i = 0; i < this.nrRanges; i++)
159 {
160 Range = this.currentLimits[i];
161
162 if (Range.IsPoint)
163 {
164 if (EndFilters is null)
166
167 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Range.Point));
168 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldEqualTo(Range.FieldName, Range.Point)));
169 }
170 else
171 {
172 if (Range.HasMin)
173 {
174 Value = Range.Min;
175
176 if (this.ascending[i])
177 {
178 if (StartFilters is null)
180
181 if (Range.MinInclusive)
182 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
183 else
184 {
185 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
186
187 if (!Comparison.Increment(ref Value))
188 return false;
189 }
190
191 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
192 }
193 else
194 {
195 if (EndFilters is null)
197
198 if (Range.MinInclusive)
199 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
200 else
201 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
202 }
203 }
204
205 if (Range.HasMax)
206 {
207 Value = Range.Max;
208
209 if (this.ascending[i])
210 {
211 if (EndFilters is null)
213
214 if (Range.MaxInclusive)
215 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
216 else
217 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
218 }
219 else
220 {
221 if (StartFilters is null)
223
224 if (Range.MaxInclusive)
225 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
226 else
227 {
228 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
229
230 if (!Comparison.Decrement(ref Value))
231 return false;
232 }
233
234 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
235 }
236 }
237 }
238 }
239
240 if (this.firstAscending)
241 {
242 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(
243 SearchParameters.ToArray());
244 }
245 else
246 {
247 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(
248 SearchParameters.ToArray());
249 }
250
251 this.startRangeFilters = StartFilters?.ToArray();
252 this.endRangeFilters = EndFilters?.ToArray();
253 this.limitsUpdatedAt = this.nrRanges;
254 }
255
256 if (!await this.currentRange.MoveNextAsyncLocked())
257 {
258 this.currentRange = null;
259
260 if (this.limitsUpdatedAt >= this.nrRanges)
261 return false;
262
263 continue;
264 }
265
266 if (!this.currentRange.CurrentTypeCompatible)
267 continue;
268
269 object CurrentValue = this.currentRange.Current;
270 Type CurrentType = CurrentValue.GetType();
271 IObjectSerializer CurrentSerializer = this.currentRange.CurrentSerializer;
272 int OutOfStartRangeFieldIndex = -1;
273 int OutOfEndRangeFieldIndex = -1;
274 bool Ok = true;
275 bool Smaller;
276
277 if (CurrentSerializer.ValueType != CurrentType)
278 {
279 if (CurrentType == this.prevType)
280 CurrentSerializer = this.prevSerializer;
281 else
282 {
283 CurrentSerializer = this.prevSerializer = await this.provider.GetObjectSerializer(CurrentType);
284 this.prevType = CurrentType;
285 }
286 }
287
288 if (!(this.additionalFilters is null))
289 {
290 foreach (IApplicableFilter Filter in this.additionalFilters)
291 {
292 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
293 {
294 Ok = false;
295 break;
296 }
297 }
298 }
299
300 if (!(this.startRangeFilters is null))
301 {
302 i = 0;
303 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.startRangeFilters)
304 {
305 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
306 {
307 OutOfStartRangeFieldIndex = i;
308 Ok = false;
309 break;
310 }
311 else
312 i++;
313 }
314 }
315
316 if (!(this.endRangeFilters is null) && OutOfStartRangeFieldIndex < 0)
317 {
318 i = 0;
319 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.endRangeFilters)
320 {
321 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
322 {
323 OutOfEndRangeFieldIndex = i;
324 Ok = false;
325 break;
326 }
327 else
328 i++;
329 }
330 }
331
332 for (i = 0; i < this.limitsUpdatedAt; i++)
333 {
334 object FieldValue = await CurrentSerializer.TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
335 if (FieldValue is null)
336 continue;
337
338 bool Inclusive = OutOfStartRangeFieldIndex >= 0;
339
340 if (this.ascending[i])
341 {
342 if (this.currentLimits[i].SetMin(FieldValue,
343 Inclusive, out Smaller) && Smaller)
344 {
345 i++;
346 this.limitsUpdatedAt = i;
347
348 while (i < this.nrRanges)
349 {
350 this.ranges[i].CopyTo(this.currentLimits[i]);
351 i++;
352 }
353 }
354 }
355 else
356 {
357 if (this.currentLimits[i].SetMax(FieldValue,
358 Inclusive, out Smaller) && Smaller)
359 {
360 i++;
361 this.limitsUpdatedAt = i;
362
363 while (i < this.nrRanges)
364 {
365 this.ranges[i].CopyTo(this.currentLimits[i]);
366 i++;
367 }
368 }
369 }
370 }
371
372 if (Ok)
373 return true;
374
375 if (OutOfStartRangeFieldIndex >= 0 || OutOfEndRangeFieldIndex >= 0)
376 {
377 this.currentRange = null;
378
379 if (this.limitsUpdatedAt >= this.nrRanges)
380 return false;
381 }
382 }
383 }
384
391 public async Task<bool> MovePreviousAsyncLocked()
392 {
393 int i;
394
395 while (true)
396 {
397 if (this.currentRange is null)
398 {
402 RangeInfo Range;
403 object Value;
404
405 for (i = 0; i < this.nrRanges; i++)
406 {
407 Range = this.currentLimits[i];
408
409 if (Range.IsPoint)
410 {
411 if (EndFilters is null)
413
414 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Range.Point));
415 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldEqualTo(Range.FieldName, Range.Point)));
416 }
417 else
418 {
419 if (Range.HasMin)
420 {
421 Value = Range.Min;
422
423 if (this.ascending[i])
424 {
425 if (EndFilters is null)
427
428 if (Range.MinInclusive)
429 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
430 else
431 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
432 }
433 else
434 {
435 if (StartFilters is null)
437
438 if (Range.MinInclusive)
439 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
440 else
441 {
442 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
443
444 if (!Comparison.Increment(ref Value))
445 return false;
446 }
447
448 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
449 }
450 }
451
452 if (Range.HasMax)
453 {
454 Value = Range.Max;
455
456 if (this.ascending[i])
457 {
458 if (StartFilters is null)
460
461 if (Range.MaxInclusive)
462 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
463 else
464 {
465 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
466
467 if (!Comparison.Decrement(ref Value))
468 return false;
469 }
470
471 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
472 }
473 else
474 {
475 if (EndFilters is null)
477
478 if (Range.MaxInclusive)
479 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
480 else
481 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
482 }
483 }
484 }
485 }
486
487 if (this.firstAscending)
488 {
489 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(
490 SearchParameters.ToArray());
491 }
492 else
493 {
494 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(
495 SearchParameters.ToArray());
496 }
497
498 this.startRangeFilters = StartFilters?.ToArray();
499 this.endRangeFilters = EndFilters?.ToArray();
500 this.limitsUpdatedAt = this.nrRanges;
501 }
502
503 if (!await this.currentRange.MovePreviousAsyncLocked())
504 {
505 this.currentRange = null;
506
507 if (this.limitsUpdatedAt >= this.nrRanges)
508 return false;
509
510 continue;
511 }
512
513 if (!this.currentRange.CurrentTypeCompatible)
514 continue;
515
516 object CurrentValue = this.currentRange.Current;
517 Type CurrentType = CurrentValue.GetType();
518 IObjectSerializer CurrentSerializer = this.currentRange.CurrentSerializer;
519 int OutOfStartRangeFieldIndex = -1;
520 int OutOfEndRangeFieldIndex = -1;
521 bool Ok = true;
522 bool Smaller;
523
524 if (CurrentSerializer.ValueType != CurrentType)
525 {
526 if (CurrentType == this.prevType)
527 CurrentSerializer = this.prevSerializer;
528 else
529 {
530 CurrentSerializer = this.prevSerializer = await this.provider.GetObjectSerializer(CurrentType);
531 this.prevType = CurrentType;
532 }
533 }
534
535 if (!(this.additionalFilters is null))
536 {
537 foreach (IApplicableFilter Filter in this.additionalFilters)
538 {
539 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
540 {
541 Ok = false;
542 break;
543 }
544 }
545 }
546
547 if (!(this.startRangeFilters is null))
548 {
549 i = 0;
550 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.startRangeFilters)
551 {
552 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
553 {
554 OutOfStartRangeFieldIndex = i;
555 Ok = false;
556 break;
557 }
558 else
559 i++;
560 }
561 }
562
563 if (!(this.endRangeFilters is null) && OutOfStartRangeFieldIndex < 0)
564 {
565 i = 0;
566 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.endRangeFilters)
567 {
568 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
569 {
570 OutOfEndRangeFieldIndex = i;
571 Ok = false;
572 break;
573 }
574 else
575 i++;
576 }
577 }
578
579 for (i = 0; i < this.limitsUpdatedAt; i++)
580 {
581 object FieldValue = await CurrentSerializer.TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
582 if (FieldValue is null)
583 continue;
584
585 bool Inclusive = OutOfStartRangeFieldIndex >= 0;
586
587 if (this.ascending[i])
588 {
589 if (this.currentLimits[i].SetMax(FieldValue,
590 Inclusive, out Smaller) && Smaller)
591 {
592 i++;
593 this.limitsUpdatedAt = i;
594
595 while (i < this.nrRanges)
596 {
597 this.ranges[i].CopyTo(this.currentLimits[i]);
598 i++;
599 }
600 }
601 }
602 else
603 {
604 if (this.currentLimits[i].SetMin(FieldValue,
605 Inclusive, out Smaller) && Smaller)
606 {
607 i++;
608 this.limitsUpdatedAt = i;
609
610 while (i < this.nrRanges)
611 {
612 this.ranges[i].CopyTo(this.currentLimits[i]);
613 i++;
614 }
615 }
616 }
617 }
618
619 if (Ok)
620 return true;
621
622 if (OutOfStartRangeFieldIndex >= 0 || OutOfEndRangeFieldIndex >= 0)
623 {
624 this.currentRange = null;
625
626 if (this.limitsUpdatedAt >= this.nrRanges)
627 return false;
628 }
629 }
630 }
631
639 public bool SameSortOrder(string[] ConstantFields, string[] SortOrder)
640 {
641 return this.index.SameSortOrder(ConstantFields, SortOrder);
642 }
643
651 public bool ReverseSortOrder(string[] ConstantFields, string[] SortOrder)
652 {
653 return this.index.ReverseSortOrder(ConstantFields, SortOrder);
654 }
655
660 public Task ContinueAfterLocked(T LastItem)
661 {
662 throw new NotSupportedException("Paginated search is not supported for queries with multiple ranges.");
663 }
664
669 public Task ContinueBeforeLocked(T LastItem)
670 {
671 throw new NotSupportedException("Paginated search is not supported for queries with multiple ranges.");
672 }
673
677 public bool CanSkip => false;
678
684 public Task<bool> Skip(long NrObjects) => Task.FromResult(false);
685 }
686}
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
T[] ToArray()
Returns an array containing all elements of the collection.
Interface for asynchronous enumerators.
Task< bool > MoveNextAsync()
Advances the enumerator to the next element of the collection.
Task< object > TryGetFieldValue(string FieldName, object Object)
Gets the value of a field or property of an object, given its name.
Type ValueType
What type of object is being serialized.