Skip to content

Commit

Permalink
Merge branch 'nchengyeeshen-fifo-queue'
Browse files Browse the repository at this point in the history
  • Loading branch information
zyedidia committed Dec 22, 2021
2 parents 13c2e08 + bbe2e03 commit dddf9df
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ information about each data structure.
for arrays of bytes, but this rope is generic.
* [`stack`](./stack): a LIFO stack.
* [`trie`](./trie): a ternary search trie.
* [`queue`](./queue): a First In First Out (FIFO) queue.

The package also includes support for iterators, in the `iter` subpackage.
Most data structures provide an iterator API, which can be used with some
Expand Down
86 changes: 86 additions & 0 deletions queue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!-- Code generated by gomarkdoc. DO NOT EDIT -->

# queue

```go
import "github.com/zyedidia/generic/queue"
```

Package queue provides an implementation of a First In First Out \(FIFO\) queue\. The FIFO queue is implemented using a doubly\-linked list found in the 'list' package\.

## Index

- [type FIFOQueue](<#type-fifoqueue>)
- [func New[T any]() *FIFOQueue[T]](<#func-new>)
- [func (q *FIFOQueue[T]) Dequeue() T](<#func-badrecv-dequeue>)
- [func (q *FIFOQueue[T]) Empty() bool](<#func-badrecv-empty>)
- [func (q *FIFOQueue[T]) Enqueue(value T)](<#func-badrecv-enqueue>)
- [func (q *FIFOQueue[T]) Iter() iter.Iter[T]](<#func-badrecv-iter>)
- [func (q *FIFOQueue[T]) Peek() T](<#func-badrecv-peek>)


## type [FIFOQueue](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L12-L14>)

FIFOQueue is a simple First In First Out \(FIFO\) queue\.

```go
type FIFOQueue[T any] struct {
// contains filtered or unexported fields
}
```

### func [New](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L17>)

```go
func New[T any]() *FIFOQueue[T]
```

New returns an empty First In First Out \(FIFO\) queue\.

### func \(\*BADRECV\) [Dequeue](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L31>)

```go
func (q *FIFOQueue[T]) Dequeue() T
```

Dequeue removes and returns the item at the front of the queue\.

A panic occurs if the queue is Empty\.

### func \(\*BADRECV\) [Empty](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L46>)

```go
func (q *FIFOQueue[T]) Empty() bool
```

Empty returns true if the queue is empty\.

### func \(\*BADRECV\) [Enqueue](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L24>)

```go
func (q *FIFOQueue[T]) Enqueue(value T)
```

Enqueue inserts 'value' to the end of the queue\.

### func \(\*BADRECV\) [Iter](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L52>)

```go
func (q *FIFOQueue[T]) Iter() iter.Iter[T]
```

Iter returns a forward iterator\, returning items starting from the front to the back of the queue\.

### func \(\*BADRECV\) [Peek](<https://github.com/nchengyeeshen/generic/blob/master/queue/fifo_queue.go#L41>)

```go
func (q *FIFOQueue[T]) Peek() T
```

Peek returns the item at the front of the queue without removing it\.

A panic occurs if the queue is Empty\.



Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
54 changes: 54 additions & 0 deletions queue/queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Package queue provides an implementation of a First In First Out (FIFO)
// queue. The FIFO queue is implemented using the doubly-linked list from the
// 'list' package.
package queue

import (
"github.com/zyedidia/generic/iter"
"github.com/zyedidia/generic/list"
)

// Queue is a simple First In First Out (FIFO) queue.
type Queue[T any] struct {
list *list.List[T]
}

// New returns an empty First In First Out (FIFO) queue.
func New[T any]() *Queue[T] {
return &Queue[T]{
list: list.New[T](),
}
}

// Enqueue inserts 'value' to the end of the queue.
func (q *Queue[T]) Enqueue(value T) {
q.list.PushBack(value)
}

// Dequeue removes and returns the item at the front of the queue.
//
// A panic occurs if the queue is Empty.
func (q *Queue[T]) Dequeue() T {
value := q.list.Front.Value
q.list.Remove(q.list.Front)

return value
}

// Peek returns the item at the front of the queue without removing it.
//
// A panic occurs if the queue is Empty.
func (q *Queue[T]) Peek() T {
return q.list.Front.Value
}

// Empty returns true if the queue is empty.
func (q *Queue[T]) Empty() bool {
return q.list.Front == nil
}

// Iter returns a forward iterator, returning items starting from the front to
// the back of the queue.
func (q *Queue[T]) Iter() iter.Iter[T] {
return q.list.Front.Iter()
}
215 changes: 215 additions & 0 deletions queue/queue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package queue

import (
"fmt"
"testing"

"github.com/zyedidia/generic/list"
)

func TestQueueEmpty(t *testing.T) {
cases := []struct {
name string
queue *Queue[int]
want bool
}{
{
name: "empty queue",
queue: emptyQueue(),
want: true,
},
{
name: "non-empty queue",
queue: nonEmptyQueue(),
want: false,
},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got := c.queue.Empty()

if got != c.want {
t.Errorf("got %v, want %v", got, c.want)
}
})
}
}

func TestQueuePeek(t *testing.T) {
t.Run("panics on empty queue", func(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Error("peeking on empty queue did not panic")
}
}()

emptyQueue().Peek()
})

t.Run("non-empty queue", func(t *testing.T) {
got := nonEmptyQueue().Peek()
want := 1

if got != want {
t.Errorf("got %v, want %v", got, want)
}
})
}

func TestQueueEnqueue(t *testing.T) {
t.Run("empty queue", func(t *testing.T) {
q := emptyQueue()

q.Enqueue(1)

if q.list.Front == nil {
t.Error("front is nil")
}

if q.list.Front.Value != 1 {
t.Errorf("got %v, want %v for front value", q.list.Front.Value, 1)
}

if q.list.Back == nil {
t.Error("back is nil")
}

if q.list.Front != q.list.Back {
t.Error(("front and back are not the same"))
}
})

t.Run("non-empty queue", func(t *testing.T) {
q := nonEmptyQueue()

q.Enqueue(3)

if q.list.Front.Value != 1 {
t.Errorf("got %v, want %v for front value", q.list.Front.Value, 1)
}

if q.list.Back == nil {
t.Error("back is nil")
}

if q.list.Back.Value != 3 {
t.Errorf("got %v, want %v for back value", q.list.Back.Value, 3)
}
})
}

func TestQueueDequeue(t *testing.T) {
t.Run("panics on empty queue", func(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Error("dequeue on empty queue did not panic")
}
}()

emptyQueue().Dequeue()
})

t.Run("non-empty queue", func(t *testing.T) {
q := nonEmptyQueue()

// Non-empty after dequeue
got := q.Dequeue()

if got != 1 {
t.Errorf("got %v, want %v", got, 1)
}

if q.list.Front.Value == 1 {
t.Error("front of queue is still 1 after dequeue")
}

if q.Empty() {
t.Error("queue is empty")
}

// Empty after dequeue
got = q.Dequeue()

if got != 2 {
t.Errorf("got %v, want %v", got, 2)
}

if !q.Empty() {
t.Error("queue is not empty")
}
})
}

func TestQueueIter(t *testing.T) {
q := nonEmptyQueue()

i := 1
q.Iter().For(func(item int) {
if item != i {
t.Errorf("got %v, want %v", item, i)
}
i++
})
}

func ExampleQueue_Enqueue() {
q := New[int]()
q.Enqueue(1)
}

func ExampleQueue_Peek() {
q := New[int]()
q.Enqueue(1)

fmt.Println(q.Peek())
// Output: 1
}

func ExampleQueue_Dequeue() {
q := New[int]()
q.Enqueue(1)

fmt.Println(q.Dequeue())
// Output: 1
}

func ExampleQueue_Iter() {
q := New[int]()
q.Enqueue(1)
q.Enqueue(2)

q.Iter().For(func(i int) {
fmt.Println(i)
})
// Output:
// 1
// 2
}

func ExampleQueue_Empty_empty() {
q := New[int]()

fmt.Println(q.Empty())
// Output: true
}

func ExampleQueue_Empty_nonempty() {
q := New[int]()
q.Enqueue(1)

fmt.Println(q.Empty())
// Output: false
}

func emptyQueue() *Queue[int] {
return New[int]()
}

func nonEmptyQueue() *Queue[int] {
q := New[int]()
q.list.Front = &list.Node[int]{Value: 1}
q.list.Front.Next = &list.Node[int]{Value: 2, Prev: q.list.Front}
q.list.Back = q.list.Front.Next
return q
}

0 comments on commit dddf9df

Please sign in to comment.