Skip to content

Commit f8ff3f6

Browse files
Merge pull request #3 from cloudnative0x0/stack
Stack: generics implemented.
2 parents 4aa5dd6 + 862afe2 commit f8ff3f6

2 files changed

Lines changed: 67 additions & 58 deletions

File tree

stack/stack.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,61 @@
11
package stack
22

3-
import (
4-
"errors"
5-
)
3+
import "errors"
64

75
var (
8-
ErrOverflow = errors.New("queue is empty")
9-
ErrUnderflow = errors.New("queue is full")
6+
ErrUnderflow = errors.New("stack underflow: cannot pop from empty stack")
7+
ErrOverflow = errors.New("stack overflow: cannot push onto full stack")
8+
ErrInvalidCapacity = errors.New("capacity must be greater than zero")
109
)
1110

12-
type Stack struct {
13-
arr []int
11+
type Stack[T any] struct {
12+
arr []T
1413
top int
1514
n int
1615
}
1716

18-
func NewStack(n int) *Stack {
19-
return &Stack{
20-
arr: make([]int, n+1),
17+
func NewStack[T any](n int) (*Stack[T], error) {
18+
if n <= 0 {
19+
return nil, ErrInvalidCapacity
20+
}
21+
22+
return &Stack[T]{
23+
arr: make([]T, n+1),
2124
top: 0,
2225
n: n,
23-
}
26+
}, nil
2427
}
2528

26-
func (s *Stack) Pop() (int, error) {
29+
func (s *Stack[T]) Pop() (T, error) {
2730
if s.top == 0 {
28-
return 0, ErrUnderflow
31+
var zero T
32+
return zero, ErrUnderflow
2933
}
3034

31-
s.top = s.top - 1
35+
s.top--
3236

3337
return s.arr[s.top+1], nil
3438
}
3539

36-
func (s *Stack) Push(x int) error {
40+
func (s *Stack[T]) Push(x T) error {
3741
if s.IsFull() {
3842
return ErrOverflow
3943
}
4044

41-
s.top = s.top + 1
45+
s.top++
4246
s.arr[s.top] = x
4347

4448
return nil
4549
}
4650

47-
func (s *Stack) IsEmpty() bool {
51+
func (s *Stack[T]) IsEmpty() bool {
4852
return s.top == 0
4953
}
5054

51-
func (s *Stack) IsFull() bool {
55+
func (s *Stack[T]) IsFull() bool {
5256
return s.top == s.n
5357
}
5458

55-
func (s *Stack) Size() int {
59+
func (s *Stack[T]) Size() int {
5660
return s.top
5761
}

stack/stack_test.go

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,20 @@ import (
55
"testing"
66
)
77

8+
func TestNewStackInvalidCapacity(t *testing.T) {
9+
for _, c := range []int{0, -1} {
10+
s, err := NewStack[int](c)
11+
if err != ErrInvalidCapacity {
12+
t.Errorf("capacity %d: expected ErrInvalidCapacity, got %v", c, err)
13+
}
14+
if s != nil {
15+
t.Errorf("capacity %d: expected nil stack, got %v", c, s)
16+
}
17+
}
18+
}
19+
820
func TestPushPop(t *testing.T) {
9-
s := NewStack(5)
21+
s, _ := NewStack[int](5)
1022

1123
if err := s.Push(10); err != nil {
1224
t.Fatalf("unexpected error on push: %v", err)
@@ -22,20 +34,13 @@ func TestPushPop(t *testing.T) {
2234
}
2335

2436
func TestLIFOOrder(t *testing.T) {
25-
s := NewStack(3)
37+
s, _ := NewStack[int](3)
2638

27-
if err := s.Push(1); err != nil {
28-
t.Fatalf("unexpected error on push: %v", err)
29-
}
30-
if err := s.Push(2); err != nil {
31-
t.Fatalf("unexpected error on push: %v", err)
32-
}
33-
if err := s.Push(3); err != nil {
34-
t.Fatalf("unexpected error on push: %v", err)
35-
}
39+
_ = s.Push(1)
40+
_ = s.Push(2)
41+
_ = s.Push(3)
3642

3743
expected := []int{3, 2, 1}
38-
3944
for i, want := range expected {
4045
got, err := s.Pop()
4146
if err != nil {
@@ -48,59 +53,49 @@ func TestLIFOOrder(t *testing.T) {
4853
}
4954

5055
func TestEmptyStack(t *testing.T) {
51-
s := NewStack(3)
56+
s, _ := NewStack[int](3)
5257

5358
if !s.IsEmpty() {
5459
t.Error("new stack should be empty")
5560
}
5661

5762
_, err := s.Pop()
58-
if err == nil {
59-
t.Error("expected underflow error, got nil")
63+
if err != ErrUnderflow {
64+
t.Errorf("expected underflow error, got %v", err)
6065
}
6166
}
6267

6368
func TestFullStack(t *testing.T) {
64-
s := NewStack(2)
69+
s, _ := NewStack[int](2)
6570

66-
if err := s.Push(1); err != nil {
67-
t.Fatalf("unexpected error on push: %v", err)
68-
}
69-
if err := s.Push(2); err != nil {
70-
t.Fatalf("unexpected error on push: %v", err)
71-
}
71+
_ = s.Push(1)
72+
_ = s.Push(2)
7273

7374
if !s.IsFull() {
7475
t.Error("stack should be full")
7576
}
7677

7778
err := s.Push(3)
78-
if err == nil {
79-
t.Error("expected overflow error, got nil")
79+
if err != ErrOverflow {
80+
t.Errorf("expected overflow error, got %v", err)
8081
}
8182
}
8283

8384
func TestSize(t *testing.T) {
84-
s := NewStack(5)
85+
s, _ := NewStack[int](5)
8586

8687
if s.Size() != 0 {
8788
t.Errorf("expected size 0, got %d", s.Size())
8889
}
8990

90-
if err := s.Push(1); err != nil {
91-
t.Fatalf("unexpected error on push: %v", err)
92-
}
93-
if err := s.Push(2); err != nil {
94-
t.Fatalf("unexpected error on push: %v", err)
95-
}
91+
_ = s.Push(1)
92+
_ = s.Push(2)
9693

9794
if s.Size() != 2 {
9895
t.Errorf("expected size 2, got %d", s.Size())
9996
}
10097

101-
if _, err := s.Pop(); err != nil {
102-
t.Fatalf("unexpected error on pop: %v", err)
103-
}
98+
_, _ = s.Pop()
10499

105100
if s.Size() != 1 {
106101
t.Errorf("expected size 1, got %d", s.Size())
@@ -115,7 +110,7 @@ func TestStress(t *testing.T) {
115110
const capacity = 30
116111

117112
for iter := 0; iter < iterations; iter++ {
118-
mine := NewStack(capacity)
113+
mine, _ := NewStack[int](capacity)
119114
var ref []int
120115

121116
for op := 0; op < opsPerIteration; op++ {
@@ -128,12 +123,10 @@ func TestStress(t *testing.T) {
128123
}
129124
ref = append(ref, val)
130125
}
131-
132126
case 1: // pop
133127
if len(ref) > 0 {
134128
want := ref[len(ref)-1]
135129
ref = ref[:len(ref)-1]
136-
137130
got, err := mine.Pop()
138131
if err != nil {
139132
t.Fatalf("iter %d: unexpected pop error: %v", iter, err)
@@ -142,8 +135,7 @@ func TestStress(t *testing.T) {
142135
t.Fatalf("iter %d: mismatch on pop: expected %d, got %d", iter, want, got)
143136
}
144137
}
145-
146-
case 2:
138+
case 2: // size checks
147139
if mine.Size() != len(ref) {
148140
t.Fatalf("iter %d: size mismatch: expected %d, got %d", iter, len(ref), mine.Size())
149141
}
@@ -154,3 +146,16 @@ func TestStress(t *testing.T) {
154146
}
155147
}
156148
}
149+
150+
func TestStackWithStrings(t *testing.T) {
151+
s, _ := NewStack[string](3)
152+
_ = s.Push("a")
153+
_ = s.Push("b")
154+
val, err := s.Pop()
155+
if err != nil {
156+
t.Fatalf("unexpected error: %v", err)
157+
}
158+
if val != "b" {
159+
t.Errorf("expected 'b', got %q", val)
160+
}
161+
}

0 commit comments

Comments
 (0)