Skip to content

Instantly share code, notes, and snippets.

@vderyagin
Last active December 11, 2015 17:08
Show Gist options
  • Save vderyagin/4632442 to your computer and use it in GitHub Desktop.
Save vderyagin/4632442 to your computer and use it in GitHub Desktop.
Thread-safe implementation of Queue data structure in Go
package queue
import (
"bytes"
"errors"
"fmt"
"sync"
)
type node struct {
item interface{}
next *node
}
type queue struct {
head *node
last *node
size int
mutex sync.RWMutex
}
func New() *queue {
return new(queue)
}
func (s *queue) Enqueue(item interface{}) {
newLast := &node{item: item}
s.mutex.Lock()
defer s.mutex.Unlock()
if s.size == 0 {
s.head = newLast
} else {
s.last.next = newLast
}
s.last = newLast
s.size++
}
func (s *queue) Dequeue() (interface{}, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.size == 0 {
return nil, errors.New("empty queue")
}
item := s.head.item
s.head = s.head.next
if s.size == 1 {
s.last = nil
}
s.size--
return item, nil
}
func (s *queue) Peek() (interface{}, error) {
s.mutex.RLock()
defer s.mutex.RUnlock()
if s.size == 0 {
return nil, errors.New("empty queue")
}
item := s.head.item
return item, nil
}
func (s *queue) IsEmpty() bool {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.size == 0
}
func (s *queue) Size() int {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.size
}
func (s *queue) String() string {
var str bytes.Buffer
str.WriteString("[ ")
s.mutex.RLock()
defer s.mutex.RUnlock()
for node := s.head; node != nil; node = node.next {
fmt.Fprintf(&str, "%v ", node.item)
}
str.WriteString("]")
return str.String()
}
package queue
import "testing"
func TestNew(t *testing.T) {
t.Parallel()
s := New()
if s.Size() != 0 {
t.Error("newly created queue should have zero size")
}
}
func TestEnqueue(t *testing.T) {
t.Parallel()
s := New()
s.Enqueue(struct{}{})
if size := s.Size(); size != 1 {
t.Errorf("should have 1 element, has %d instead", size)
}
s.Enqueue(struct{}{})
if size := s.Size(); size != 2 {
t.Errorf("should have 2 element, has %d instead", size)
}
}
func TestDequeue(t *testing.T) {
t.Parallel()
s := New()
s.Enqueue(3)
s.Enqueue(2)
s.Enqueue(1)
item, err := s.Dequeue()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 3 {
t.Errorf("%d, %d", i, 3)
}
item, err = s.Dequeue()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 2 {
t.Errorf("%d, %d", i, 2)
}
item, err = s.Dequeue()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 1 {
t.Errorf("%d, %d", i, 1)
}
item, err = s.Dequeue()
if item != nil {
t.Error("dequeue of empty queue should return nil")
}
if err == nil {
t.Error("dequeue of empty queue should return error")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment