Last active
December 11, 2015 17:08
-
-
Save vderyagin/4632448 to your computer and use it in GitHub Desktop.
Thread-safe implementation of Stack 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 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() | |
} |
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 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