From 9ad0f9bb2bdfe47f144e2a0e8951dcfe6344a4ea Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Sat, 24 Aug 2024 16:58:01 -0400 Subject: Queue --- queue.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ queue_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 queue.go create mode 100644 queue_test.go diff --git a/queue.go b/queue.go new file mode 100644 index 0000000..5e28412 --- /dev/null +++ b/queue.go @@ -0,0 +1,49 @@ +package share + +// Queue is a FIFO queue with an unlimited capacity. +// +// Closing the Enqueue channel closes the Queue. The Queue waits +// until all elements have been drained from the Dequeue channel +// before closing it. +type Queue[T any] struct { + // Sending to Enqueue adds an element to the back of the Queue + // and never blocks. + Enqueue chan<-T + + + // Receiving from Dequeue removes an element from the front + // of the queue or, if the queue is empty, blocks until an element + // is enqueued. + Dequeue <-chan T +} + +func NewQueue[T any]() Queue[T] { + in, out := make(chan T), make(chan T) + + go func() { + defer close(out) + + var queue []T + + for v := range in { + queue = append(queue, v) + + for len(queue) > 0 { + select { + case out <- queue[0]: + queue = queue[1:] + case v, ok := <-in: + if !ok { + for _, x := range queue { + out <- x + } + return + } + queue = append(queue, v) + } + } + } + }() + + return Queue[T]{Enqueue: in, Dequeue: out} +} diff --git a/queue_test.go b/queue_test.go new file mode 100644 index 0000000..33666d8 --- /dev/null +++ b/queue_test.go @@ -0,0 +1,37 @@ +package share_test + +import ( + "testing" + + "git.samanthony.xyz/share" +) + +func TestQueue(t *testing.T) { + q := share.NewQueue[string]() + + vals := []string{"foo", "bar", "baz", "xyz"} + + go func() { + for _, v := range vals { + q.Enqueue <- v + } + close(q.Enqueue) + }() + + go func() { + i := 0 + for front := range q.Dequeue { + t.Log("received", front, "from queue") + if i > len(vals)-1 { + t.Fatal("received too many elements from queue") + } + if front != vals[i] { + t.Fatalf("received %v from queue; wanted %v", front, vals[i]) + } + i++ + } + if i < len(vals) { + t.Fatal("did not receive enough values from queue") + } + }() +} \ No newline at end of file -- cgit v1.2.3