Last active
December 11, 2015 17:08
-
-
Save vderyagin/4632442 to your computer and use it in GitHub Desktop.
Thread-safe implementation of Queue data structure in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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