Skip to content

Instantly share code, notes, and snippets.

@vderyagin
Last active December 11, 2015 17:08
Show Gist options
  • Save vderyagin/4632448 to your computer and use it in GitHub Desktop.
Save vderyagin/4632448 to your computer and use it in GitHub Desktop.
Thread-safe implementation of Stack data structure in Go
package stack
import (
"bytes"
"errors"
"fmt"
"sync"
)
type node struct {
item interface{}
next *node
}
type stack struct {
head *node
size int
mutex sync.RWMutex
}
func New() *stack {
return new(stack)
}
func (s *stack) Push(item interface{}) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.head = &node{
item: item,
next: s.head,
}
s.size++
}
func (s *stack) Pop() (interface{}, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.size == 0 {
return nil, errors.New("empty stack")
}
item := s.head.item
s.head = s.head.next
s.size--
return item, nil
}
func (s *stack) Peek() (interface{}, error) {
s.mutex.RLock()
defer s.mutex.RUnlock()
if s.size == 0 {
return nil, errors.New("empty stack")
}
item := s.head.item
return item, nil
}
func (s *stack) IsEmpty() bool {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.head == nil
}
func (s *stack) Size() int {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.size
}
func (s *stack) 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 stack
import "testing"
func TestNew(t *testing.T) {
t.Parallel()
s := New()
if s.Size() != 0 {
t.Error("newly created stack should have zero size")
}
}
func TestPush(t *testing.T) {
t.Parallel()
s := New()
s.Push(struct{}{})
if size := s.Size(); size != 1 {
t.Errorf("should have 1 element, has %d instead", size)
}
s.Push(struct{}{})
if size := s.Size(); size != 2 {
t.Errorf("should have 2 element, has %d instead", size)
}
}
func TestPop(t *testing.T) {
t.Parallel()
s := New()
s.Push(1)
s.Push(2)
s.Push(3)
item, err := s.Pop()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 3 {
t.Errorf("%d, %d", i, 3)
}
item, err = s.Pop()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 2 {
t.Errorf("%d, %d", i, 2)
}
item, err = s.Pop()
if err != nil {
t.Error(err)
}
if i := item.(int); i != 1 {
t.Errorf("%d, %d", i, 1)
}
item, err = s.Pop()
if item != nil {
t.Error("pop of empty stack should return nil")
}
if err == nil {
t.Error("pop of empty stack should return error")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment