Skip to content

Commit 465fbd6

Browse files
committed
Add a Count property.
1 parent 7245c6a commit 465fbd6

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

DependencyQueue.Tests/DependencyQueueTests.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ public void Construct_DefaultComparer()
1616

1717
queue .ShouldBeValid();
1818
queue.Comparer .ShouldBeSameAs(StringComparer.Ordinal);
19+
queue.Count .ShouldBe(0);
1920
queue.Topics .ShouldBeEmpty();
2021
queue.ReadyEntries.ShouldBeEmpty();
2122

2223
using var view = queue.Inspect();
2324

2425
view.Queue .ShouldBeSameAs(queue);
2526
view.Comparer .ShouldBeSameAs(queue.Comparer);
27+
view.Count .ShouldBe(0);
2628
view.Topics.Dictionary .ShouldBeSameAs(queue.Topics);
2729
view.ReadyEntries.Queue.ShouldBeSameAs(queue.ReadyEntries);
2830

@@ -44,13 +46,15 @@ public void Construct_ExplicitComparer()
4446

4547
queue .ShouldBeValid();
4648
queue.Comparer .ShouldBeSameAs(comparer);
49+
queue.Count .ShouldBe(0);
4750
queue.Topics .ShouldBeEmpty();
4851
queue.ReadyEntries.ShouldBeEmpty();
4952

5053
using var view = queue.InspectAsync().GetAwaiter().GetResult();
5154

5255
view.Queue .ShouldBeSameAs(queue);
5356
view.Comparer .ShouldBeSameAs(comparer);
57+
view.Count .ShouldBe(0);
5458
view.Topics.Dictionary .ShouldBeSameAs(queue.Topics);
5559
view.ReadyEntries.Queue.ShouldBeSameAs(queue.ReadyEntries);
5660

@@ -171,8 +175,8 @@ public void Enqueue_IndependentEntry()
171175
entry.Provides.ShouldBe(["a", "b"]); // name is always provided
172176
entry.Requires.ShouldBeEmpty();
173177

178+
queue.Count.ShouldBe(1);
174179
queue.ShouldHaveReadyEntries(entry);
175-
176180
queue.ShouldHaveTopicCount(2);
177181
queue.ShouldHaveTopic("a", providedBy: [entry]);
178182
queue.ShouldHaveTopic("b", providedBy: [entry]);
@@ -191,8 +195,8 @@ public void Enqueue_DependentEntry()
191195
entry.Provides.ShouldBe(["a"]); // name is always provided
192196
entry.Requires.ShouldBe(["b"]);
193197

198+
queue.Count.ShouldBe(1);
194199
queue.ShouldNotHaveReadyEntries();
195-
196200
queue.ShouldHaveTopicCount(2);
197201
queue.ShouldHaveTopic("a", providedBy: [entry]);
198202
queue.ShouldHaveTopic("b", requiredBy: [entry]);
@@ -207,6 +211,7 @@ public void Enqueue_InterdependentEntityNetwork()
207211
var entryB0 = queue.Enqueue("b0", value: new(), provides: ["b"]);
208212
var entryB1 = queue.Enqueue("b1", value: new(), provides: ["b"]);
209213

214+
queue.Count.ShouldBe(3);
210215
queue.ShouldHaveReadyEntries(entryB0, entryB1);
211216
queue.ShouldHaveTopicCount(4);
212217
queue.ShouldHaveTopic("a", providedBy: [entryA]);
@@ -225,6 +230,7 @@ public void Enqueue_DuplicateEntry()
225230

226231
entryA0.ShouldNotBeSameAs(entryA1);
227232

233+
queue.Count.ShouldBe(2);
228234
queue.ShouldHaveReadyEntries(entryA0, entryA1);
229235
queue.ShouldHaveTopicCount(1);
230236
queue.ShouldHaveTopic("a", providedBy: [entryA0, entryA1]);
@@ -333,6 +339,7 @@ public void Dequeue_Empty()
333339
using var queue = new Queue();
334340

335341
queue.Dequeue().ShouldBeNull();
342+
queue.Count.ShouldBe(0);
336343
}
337344

338345
[Test]
@@ -372,12 +379,14 @@ public void Dequeue_Ok()
372379
var entry = queue.Enqueue("a", value: new());
373380

374381
queue.ShouldBeValid();
382+
queue.Count.ShouldBe(1);
375383
queue.ShouldHaveReadyEntries([entry]);
376384
queue.ShouldHaveTopicCount(1);
377385
queue.ShouldHaveTopic("a", providedBy: [entry]);
378386

379387
queue.Dequeue().ShouldBeSameAs(entry);
380388

389+
queue.Count.ShouldBe(0);
381390
queue.ShouldNotHaveReadyEntries(); // removed when dequeued
382391
queue.ShouldHaveTopicCount(1); // remains until completed
383392
queue.ShouldHaveTopic("a", providedBy: [entry]); // remains until completed
@@ -397,6 +406,7 @@ public void Dequeue_WaitForRequiredEntries()
397406
queue.Dequeue().ShouldBeSameAs(entryB1);
398407
queue.Dequeue().ShouldBeSameAs(entryC);
399408

409+
queue.Count.ShouldBe(1);
400410
queue.ShouldNotHaveReadyEntries();
401411
queue.ShouldHaveTopicCount(5);
402412
queue.ShouldHaveTopic("a", providedBy: [entryA]);
@@ -439,6 +449,7 @@ void CompleteEntryC()
439449
dequeuedEntry .ShouldBeSameAs(entryA);
440450
stopwatch.Elapsed.ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(600));
441451

452+
queue.Count.ShouldBe(0);
442453
queue.ShouldNotHaveReadyEntries();
443454
queue.ShouldHaveTopicCount(1);
444455
queue.ShouldHaveTopic("a", providedBy: [entryA]);
@@ -469,6 +480,7 @@ bool ReturnTrueOnSecondInvocation(Value value)
469480
testedValues .ShouldBe([entry.Value, entry.Value], ignoreOrder: true);
470481
stopwatch.Elapsed.ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(950));
471482

483+
queue.Count.ShouldBe(0);
472484
queue.ShouldNotHaveReadyEntries();
473485
queue.ShouldHaveTopicCount(1);
474486
queue.ShouldHaveTopic("a", providedBy: [entry]);
@@ -508,6 +520,7 @@ void CompleteEntryB()
508520
dequeuedEntries .ShouldBe([entryA, null], ignoreOrder: true);
509521
stopwatch.Elapsed.ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(75));
510522

523+
queue.Count.ShouldBe(0);
511524
queue.ShouldNotHaveReadyEntries();
512525
queue.ShouldHaveTopicCount(0);
513526
}
@@ -560,6 +573,7 @@ public async Task DequeueAsync_Ok()
560573

561574
(await queue.DequeueAsync()).ShouldBeSameAs(entry);
562575

576+
queue.Count.ShouldBe(0);
563577
queue.ShouldNotHaveReadyEntries(); // removed when dequeued
564578
queue.ShouldHaveTopicCount(1); // remains until completed
565579
queue.ShouldHaveTopic("a", providedBy: [entry]); // remains until completed
@@ -579,9 +593,9 @@ public async Task DequeueAsync_WaitForRequiredEntries()
579593
(await queue.DequeueAsync()).ShouldBeSameAs(entryB1);
580594
(await queue.DequeueAsync()).ShouldBeSameAs(entryC);
581595

596+
queue.Count.ShouldBe(1);
582597
queue.ShouldNotHaveReadyEntries();
583598
queue.ShouldHaveTopicCount(5);
584-
585599
queue.ShouldHaveTopic("a", providedBy: [entryA]);
586600
queue.ShouldHaveTopic("b", providedBy: [entryB0, entryB1], requiredBy: [entryA]);
587601
queue.ShouldHaveTopic("b0", providedBy: [entryB0]);
@@ -627,6 +641,7 @@ await Task.WhenAll(
627641
dequeuedEntry .ShouldBeSameAs(entryA);
628642
stopwatch.Elapsed.ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(600));
629643

644+
queue.Count.ShouldBe(0);
630645
queue.ShouldNotHaveReadyEntries();
631646
queue.ShouldHaveTopicCount(1);
632647
queue.ShouldHaveTopic("a", providedBy: [entryA]);
@@ -657,6 +672,7 @@ bool ReturnTrueOnSecondInvocation(Value value)
657672
testedValues.ToArray().ShouldBe([entry.Value, entry.Value]);
658673
stopwatch.Elapsed .ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(900));
659674

675+
queue.Count.ShouldBe(0);
660676
queue.ShouldNotHaveReadyEntries();
661677
queue.ShouldHaveTopicCount(1);
662678
queue.ShouldHaveTopic("a", providedBy: [entry]);
@@ -700,6 +716,7 @@ await Task.WhenAll(
700716
dequeuedEntries .ShouldBe([entryA, null], ignoreOrder: true);
701717
stopwatch.Elapsed.ShouldBeGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(75));
702718

719+
queue.Count.ShouldBe(0);
703720
queue.ShouldNotHaveReadyEntries();
704721
queue.ShouldHaveTopicCount(0);
705722
}
@@ -810,6 +827,7 @@ public void Clear_Ok()
810827
queue.ShouldBeValid();
811828
queue.Clear();
812829

830+
queue.Count.ShouldBe(0);
813831
queue.ShouldNotHaveReadyEntries();
814832
queue.ShouldHaveTopicCount(0);
815833
queue.Dequeue().ShouldBeNull();

DependencyQueue/DependencyQueue.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public class DependencyQueue<T> : IDisposable
2525
// Thing that an execution context must lock exclusively to access queue state
2626
private readonly AsyncMonitor _monitor;
2727

28+
// Count of items in the queue
29+
private int _count;
30+
2831
// Whether the dependency graph is valid, invalid, or of unknown validity
2932
private Validity _validity;
3033

@@ -64,6 +67,11 @@ public DependencyQueue(StringComparer? comparer = null)
6467
/// </summary>
6568
public StringComparer Comparer => _comparer;
6669

70+
/// <summary>
71+
/// Gets the count of items in the queue.
72+
/// </summary>
73+
public int Count => _count;
74+
6775
/// <summary>
6876
/// Creates a builder that can create and enqueue entries in the queue
6977
/// incrementally.
@@ -169,6 +177,7 @@ internal void Enqueue(DependencyQueueEntry<T> entry)
169177
if (entry.Requires.Count == 0)
170178
_ready.Enqueue(entry);
171179

180+
_count++;
172181
_validity = Validity.Unknown;
173182
_monitor.PulseAll();
174183
}
@@ -244,7 +253,10 @@ internal void Enqueue(DependencyQueueEntry<T> entry)
244253

245254
// Check if the ready queue has an entry to dequeue that the caller accepts
246255
if (_ready.TryDequeue(GetValue, predicate, out var entry))
256+
{
257+
_count--;
247258
return entry;
259+
}
248260

249261
// Some entries are in progress, and either there are no more ready
250262
// entries, or the predicate rejected all of them. Wait for any
@@ -377,7 +389,10 @@ internal void Enqueue(DependencyQueueEntry<T> entry)
377389

378390
// Check if the ready queue has an entry to dequeue that the caller accepts
379391
if (_ready.TryDequeue(GetValue, predicate, out var entry))
392+
{
393+
_count--;
380394
return entry;
395+
}
381396

382397
// Some entries are in progress, and either there are no more ready
383398
// entries, or the predicate rejected all of them. Wait for any
@@ -489,6 +504,8 @@ public void Clear()
489504

490505
_ready .Clear();
491506
_topics.Clear();
507+
508+
_count = 0;
492509
_validity = Validity.Valid;
493510

494511
_monitor.PulseAll();
@@ -688,6 +705,9 @@ internal View(DependencyQueue<T> queue, AsyncMonitor.Lock @lock)
688705
/// <inheritdoc cref="DependencyQueue{T}.Comparer"/>
689706
public StringComparer Comparer => _queue.Comparer;
690707

708+
/// <inheritdoc cref="DependencyQueue{T}.Count"/>
709+
public int Count => _queue.Count;
710+
691711
/// <inheritdoc cref="DependencyQueue{T}.ReadyEntries"/>
692712
/// <exception cref="ObjectDisposedException">
693713
/// The underlying lock has been released.

0 commit comments

Comments
 (0)