Skip to content

Commit

Permalink
Adds Queue
Browse files Browse the repository at this point in the history
  • Loading branch information
bloudraak committed Dec 10, 2023
1 parent 7deaaf6 commit fb6167f
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 0 deletions.
85 changes: 85 additions & 0 deletions concurrent/queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package concurrent

import (
"errors"
"sync"
)

var (
ErrQueueEmpty = errors.New("queue is empty")
)

// Queue is a first-in-first-out (FIFO) data structure that is safe for concurrent use
type Queue[T any] struct {
items []T
lock *sync.RWMutex
}

// NewQueue creates a new Queue
func NewQueue[T any](items ...T) *Queue[T] {
return &Queue[T]{
items: items,
lock: &sync.RWMutex{},
}
}

// Dequeue removes an element from the queue. If the queue is empty, an error is returned
func (q *Queue[T]) Dequeue() (T, error) {
q.lock.Lock()
defer q.lock.Unlock()

var zero T
if len(q.items) == 0 {
return zero, ErrQueueEmpty
}

item := q.items[0]
q.items = q.items[1:]
return item, nil
}

// Enqueue adds an element to the queue
func (q *Queue[T]) Enqueue(item T) error {
q.lock.Lock()
defer q.lock.Unlock()

q.items = append(q.items, item)
return nil
}

// IsEmpty returns true if the queue is empty
func (q *Queue[T]) IsEmpty() bool {
q.lock.RLock()
defer q.lock.RUnlock()

return len(q.items) == 0
}

// Peek returns the element at the front of the queue without removing it. If the queue is empty, an error is returned
func (q *Queue[T]) Peek() (T, error) {
q.lock.RLock()
defer q.lock.RUnlock()

var zero T
if len(q.items) == 0 {
return zero, ErrQueueEmpty
}

return q.items[0], nil
}

// Len returns the number of elements in the queue
func (q *Queue[T]) Len() int {
q.lock.RLock()
defer q.lock.RUnlock()

return len(q.items)
}

// Clear removes all items from the queue
func (q *Queue[T]) Clear() {
q.lock.Lock()
defer q.lock.Unlock()

q.items = []T{}
}
76 changes: 76 additions & 0 deletions concurrent/queue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package concurrent

import "fmt"

func ExampleNewQueue() {
q := NewQueue[int](1, 2, 3)
_ = q.Enqueue(4)
_ = q.Enqueue(5)
for !q.IsEmpty() {
item, _ := q.Dequeue()
fmt.Println(item)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}

func ExampleQueue_Dequeue() {
q := NewQueue[int](1, 2, 3)
item, _ := q.Dequeue()
fmt.Println(item)
// Output: 1
}

func ExampleQueue_Dequeue_empty() {
q := NewQueue[int]()
_, err := q.Dequeue()
fmt.Println(err)
// Output: queue is empty
}

func ExampleQueue_Enqueue() {
q := NewQueue[int](1, 2, 3)
_ = q.Enqueue(4)
_ = q.Enqueue(5)
for !q.IsEmpty() {
item, _ := q.Dequeue()
fmt.Println(item)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}

func ExampleQueue_IsEmpty() {
q := NewQueue[int](1, 2, 3)
fmt.Println(q.IsEmpty())
_, _ = q.Dequeue()
fmt.Println(q.IsEmpty())
// Output:
// false
// false
}

func ExampleQueue_Len() {
q := NewQueue[int](1, 2, 3)
fmt.Println(q.Len())
_, _ = q.Dequeue()
fmt.Println(q.Len())
// Output:
// 3
// 2
}

func ExampleQueue_Peek() {
q := NewQueue[int](1, 2, 3)
item, _ := q.Peek()
fmt.Println(item)
// Output: 1
}
1 change: 1 addition & 0 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ type List[T comparable] interface {
// RemoveAt removes the item at the specified index from the list. If the index is out of range, an error is returned.
RemoveAt(int) error
}

19 changes: 19 additions & 0 deletions queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package collections

// Queue is a first-in-first-out (FIFO) data structure
type Queue[T any] interface {
// Dequeue removes an element from the queue. If the queue is empty, an error is returned
Dequeue() (T, error)

// Enqueue adds an element to the queue. If the item cannot be added, an error is returned
Enqueue(T) error

// IsEmpty returns true if the queue is empty
IsEmpty() bool

// Peek returns the element at the front of the queue without removing it. If the queue is empty, an error is returned
Peek() (T, error)

// Len returns the number of elements in the queue
Len() int
}
58 changes: 58 additions & 0 deletions unsafe/queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package unsafe

import "errors"

var (
// ErrQueueEmpty is returned when the queue is empty
ErrQueueEmpty = errors.New("queue is empty")
)

// Queue is a first-in-first-out (FIFO) data structure that is unsafe for concurrent use
type Queue[T any] struct {
items []T
}

// NewQueue creates a new Queue
func NewQueue[T any](items ...T) *Queue[T] {
return &Queue[T]{
items: items,
}
}

// Dequeue removes an element from the queue. If the queue is empty, an error is returned
func (q *Queue[T]) Dequeue() (T, error) {
var zero T
if len(q.items) == 0 {
return zero, ErrQueueEmpty
}

item := q.items[0]
q.items = q.items[1:]
return item, nil
}

// Enqueue adds an element to the queue
func (q *Queue[T]) Enqueue(item T) error {
q.items = append(q.items, item)
return nil
}

// IsEmpty returns true if the queue is empty
func (q *Queue[T]) IsEmpty() bool {
return len(q.items) == 0
}

// Peek returns the element at the front of the queue without removing it. If the queue is empty, an error is returned
func (q *Queue[T]) Peek() (T, error) {
var zero T
if len(q.items) == 0 {
return zero, ErrQueueEmpty
}

return q.items[0], nil
}

// Len returns the number of elements in the queue
func (q *Queue[T]) Len() int {
return len(q.items)
}
76 changes: 76 additions & 0 deletions unsafe/queue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package unsafe

import "fmt"

func ExampleNewQueue() {
q := NewQueue[int](1, 2, 3)
_ = q.Enqueue(4)
_ = q.Enqueue(5)
for !q.IsEmpty() {
item, _ := q.Dequeue()
fmt.Println(item)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}

func ExampleQueue_Dequeue() {
q := NewQueue[int](1, 2, 3)
item, _ := q.Dequeue()
fmt.Println(item)
// Output: 1
}

func ExampleQueue_Dequeue_empty() {
q := NewQueue[int]()
_, err := q.Dequeue()
fmt.Println(err)
// Output: queue is empty
}

func ExampleQueue_Enqueue() {
q := NewQueue[int](1, 2, 3)
_ = q.Enqueue(4)
_ = q.Enqueue(5)
for !q.IsEmpty() {
item, _ := q.Dequeue()
fmt.Println(item)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}

func ExampleQueue_IsEmpty() {
q := NewQueue[int](1, 2, 3)
fmt.Println(q.IsEmpty())
_, _ = q.Dequeue()
fmt.Println(q.IsEmpty())
// Output:
// false
// false
}

func ExampleQueue_Len() {
q := NewQueue[int](1, 2, 3)
fmt.Println(q.Len())
_, _ = q.Dequeue()
fmt.Println(q.Len())
// Output:
// 3
// 2
}

func ExampleQueue_Peek() {
q := NewQueue[int](1, 2, 3)
item, _ := q.Peek()
fmt.Println(item)
// Output: 1
}

0 comments on commit fb6167f

Please sign in to comment.