diff --git a/data_structures/queue.jule b/data_structures/queue.jule new file mode 100644 index 0000000..c77c9fa --- /dev/null +++ b/data_structures/queue.jule @@ -0,0 +1,49 @@ +// Implementation of a generic FIFO (first-in, first-out) queue. +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) + +// Queue is a generic first-in, first-out (FIFO) collection. +struct Queue[T] { + items: []T +} + +impl Queue { + // Enqueue adds an item to the back of the queue. + fn Enqueue(mut *self, item: T) { + self.items = append(self.items, item) + } + + // Dequeue removes and returns the item at the front of the queue. + // The second return value reports whether an item was removed; + // it is false when the queue is empty. + fn Dequeue(mut *self): (item: T, ok: bool) { + if len(self.items) == 0 { + return + } + item = self.items[0] + self.items = self.items[1:] + ok = true + return + } + + // Front returns the item at the front of the queue without removing it. + // The second return value reports whether the queue has an item; + // it is false when the queue is empty. + fn Front(*self): (item: T, ok: bool) { + if len(self.items) == 0 { + return + } + item = self.items[0] + ok = true + return + } + + // Len returns the number of items in the queue. + fn Len(*self): int { + return len(self.items) + } + + // Empty reports whether the queue has no items. + fn Empty(*self): bool { + return len(self.items) == 0 + } +} diff --git a/data_structures/queue_test.jule b/data_structures/queue_test.jule new file mode 100644 index 0000000..65b69b6 --- /dev/null +++ b/data_structures/queue_test.jule @@ -0,0 +1,56 @@ +#build test + +use "std/testing" + +#test +fn testQueueEnqueueDequeue(t: &testing::T) { + mut q := Queue[int]{} + t.Assert(q.Empty(), "new queue should be empty") + t.Assert(q.Len() == 0, "new queue should have length 0") + + q.Enqueue(1) + q.Enqueue(2) + q.Enqueue(3) + t.Assert(!q.Empty(), "queue with items should not be empty") + t.Assert(q.Len() == 3, "queue should have length 3") + + v1, ok1 := q.Dequeue() + t.Assert(ok1 && v1 == 1, "dequeue should return the first enqueued item (1)") + + v2, ok2 := q.Dequeue() + t.Assert(ok2 && v2 == 2, "dequeue should return 2") + + v3, ok3 := q.Dequeue() + t.Assert(ok3 && v3 == 3, "dequeue should return 3") + + t.Assert(q.Empty(), "queue should be empty after dequeuing all items") +} + +#test +fn testQueueDequeueEmpty(t: &testing::T) { + mut q := Queue[int]{} + _, ok := q.Dequeue() + t.Assert(!ok, "dequeue on empty queue should report ok == false") +} + +#test +fn testQueueFront(t: &testing::T) { + mut q := Queue[int]{} + _, ok := q.Front() + t.Assert(!ok, "front on empty queue should report ok == false") + + q.Enqueue(42) + q.Enqueue(7) + v, ok2 := q.Front() + t.Assert(ok2 && v == 42, "front should return the first item (42)") + t.Assert(q.Len() == 2, "front should not remove the item") +} + +#test +fn testQueueGenericString(t: &testing::T) { + mut q := Queue[string]{} + q.Enqueue("a") + q.Enqueue("b") + v, ok := q.Dequeue() + t.Assert(ok && v == "a", "generic string queue should dequeue \"a\"") +}