Add new feature in collection framework:

- Implemented slice data structure
- Defined new interfaces Collection, List and Set
This commit is contained in:
Fabio Scotto di Santolo
2023-01-08 20:04:13 +01:00
parent 50f4b83504
commit 43a5c8b244
10 changed files with 724 additions and 54 deletions

View File

@@ -12,3 +12,6 @@ dep:
vet:
go vet
build:
go build -o ./build

View File

@@ -0,0 +1,36 @@
package collection
type Iterator[E any] interface {
HasNext() bool
Next() E
NextWithIndex() (int, E)
}
type Iterable[E any] interface {
Iterator() Iterator[E]
}
type Collection[E any] interface {
Iterable[E]
Empty() bool
Size() int
Push(item E)
Contains(item E) bool
Delete(item E) error
}
type List[E any] interface {
Collection[E]
Back() (E, error)
Front() (E, error)
PushBack(item E)
PushFront(item E)
Index(item E) (int, error)
GetAt(pos int) (E, error)
PushAt(item E, pos int)
DeleteAt(pos int) error
}
type Set[E comparable] interface {
Collection[E]
}

26
pkg/collection/errors.go Normal file
View File

@@ -0,0 +1,26 @@
package collection
import "fmt"
var (
ErrPositionNegative = fmt.Errorf("position can not be negative")
ErrEmptyCollection = fmt.Errorf("this collection is empty")
ErrNodeNotFound = fmt.Errorf("node not found")
)
type ErrIndexOutOfBound struct {
index int
size int
}
func (e ErrIndexOutOfBound) Error() string {
return fmt.Sprintf("index %d out of bound from range %d and %d", e.index, 0, e.size-1)
}
type ErrItemNotFound struct {
item any
}
func (e ErrItemNotFound) Error() string {
return fmt.Sprintf("item %v not found", e.item)
}

View File

@@ -1,11 +0,0 @@
package collection
type Iterator[E any] interface {
HasNext() bool
Next() E
NextWithIndex() (int, E)
}
type Iterable[E any] interface {
Iterator() Iterator[E]
}

View File

@@ -2,25 +2,10 @@ package collection
import (
"fmt"
"log"
"reflect"
"strings"
)
var (
ErrPositionNegative = fmt.Errorf("position can not be negative")
ErrEmptyList = fmt.Errorf("no nodes in list")
ErrNodeNotFound = fmt.Errorf("node not found")
)
type ErrIndexOutOfBound struct {
index int
size int
}
func (e ErrIndexOutOfBound) Error() string {
return fmt.Sprintf("index %d out of bound from range %d and %d", e.index, 0, e.size-1)
}
type node[E any] struct {
value E
prev *node[E]
@@ -112,7 +97,7 @@ func (l *LinkedList[E]) GetAt(pos int) (E, error) {
// findNode returns node at given position from linked list
func (l *LinkedList[E]) findNode(pos int) (*node[E], error) {
if l.Empty() {
return nil, ErrEmptyList
return nil, ErrEmptyCollection
}
ptr := l.head
@@ -131,6 +116,30 @@ func (l *LinkedList[E]) findNode(pos int) (*node[E], error) {
return ptr, nil
}
func (l *LinkedList[E]) Contains(item E) bool {
for it := l.Iterator(); it.HasNext(); {
x := it.Next()
if reflect.DeepEqual(item, x) {
return true
}
}
return false
}
func (l *LinkedList[E]) Index(item E) (int, error) {
for it := l.Iterator(); it.HasNext(); {
i, x := it.NextWithIndex()
if reflect.DeepEqual(item, x) {
return i, nil
}
}
return 0, ErrItemNotFound{item}
}
func (l *LinkedList[E]) Push(item E) {
l.PushBack(item)
}
func (l *LinkedList[E]) PushFront(item E) {
l.PushAt(item, 0)
}
@@ -175,17 +184,23 @@ func (l *LinkedList[E]) PushAt(item E, pos int) {
l.size++
}
func (l *LinkedList[E]) Delete(item E) error {
pos, err := l.Index(item)
if err != nil {
return err
}
return l.DeleteAt(pos)
}
// DeleteAt deletes node at given position from linked list
func (l *LinkedList[E]) DeleteAt(pos int) error {
// validate the position
if pos < 0 {
log.Println("position can not be negative")
return ErrPositionNegative
}
if l.size == 0 {
log.Println("no nodes in list")
return ErrEmptyList
return ErrEmptyCollection
}
if pos == 0 {
@@ -199,7 +214,6 @@ func (l *LinkedList[E]) DeleteAt(pos int) error {
} else {
prevNode, _ := l.findNode(pos - 1)
if prevNode == nil {
log.Println("node not found")
return ErrNodeNotFound
}
myNode, err := l.findNode(pos)

View File

@@ -54,14 +54,14 @@ func TestLinkedList_GetAt(t *testing.T) {
{description: "get middle item", list: NewLinkedList(1, 2, 3), pos: 1, want: 2, err: nil},
{description: "get last item", list: NewLinkedList(1, 2, 3), pos: 2, want: 3, err: nil},
{description: "get last item", list: NewLinkedList(1, 2, 3), pos: 2, want: 3, err: nil},
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), pos: 0, want: 0, err: ErrEmptyList},
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), pos: 0, want: 0, err: ErrEmptyCollection},
{description: "get item with negative position", list: NewLinkedList(1, 2, 3), pos: -1, want: 0, err: ErrPositionNegative},
{description: "get item with index out of bound", list: NewLinkedList(1, 2, 3), pos: 4, want: 0, err: ErrIndexOutOfBound{4, 3}},
}
for _, tt := range useCases {
result, err := tt.list.GetAt(tt.pos)
if result != tt.want && err != tt.err {
if result != tt.want || err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
@@ -74,14 +74,14 @@ func TestLinkedList_Back(t *testing.T) {
err error
want int
}{
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), want: 0, err: ErrEmptyList},
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), want: 0, err: ErrEmptyCollection},
{description: "singleton list return first element", list: NewLinkedList(1), want: 1},
{description: "get last item", list: NewLinkedList(1, 2, 3), want: 3},
}
for _, tt := range useCases {
result, err := tt.list.Back()
if result != tt.want && err != tt.err {
if result != tt.want || err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
@@ -94,19 +94,44 @@ func TestLinkedList_Front(t *testing.T) {
err error
want int
}{
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), want: 0, err: ErrEmptyList},
{description: "no items in list return zero value of the type", list: NewLinkedList[int](), want: 0, err: ErrEmptyCollection},
{description: "singleton list return first element", list: NewLinkedList(1), want: 1},
{description: "get first item", list: NewLinkedList(1, 2, 3), want: 1},
}
for _, tt := range useCases {
result, err := tt.list.Front()
if result != tt.want && err != tt.err {
if result != tt.want || err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
}
func TestLinkedList_Push(t *testing.T) {
useCases := []struct {
description string
original *LinkedList[int]
modified *LinkedList[int]
item int
}{
{description: "push item in empty slice",
original: NewLinkedList[int](),
modified: NewLinkedList(1),
item: 1},
{description: "push item in slice with item in last position",
original: NewLinkedList(1, 2),
modified: NewLinkedList(1, 2, 3),
item: 3},
}
for _, tt := range useCases {
tt.original.Push(tt.item)
if !compareLists(tt.original, tt.modified) {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestLinkedList_PushAt(t *testing.T) {
useCases := []struct {
description string
@@ -205,6 +230,41 @@ func TestLinkedList_PushFront(t *testing.T) {
}
}
func TestLinkedList_Delete(t *testing.T) {
useCases := []struct {
description string
original *LinkedList[int]
modified *LinkedList[int]
item int
err error
}{
{description: "delete item in empty list",
original: NewLinkedList[int](),
modified: NewLinkedList[int](),
item: 0,
err: ErrItemNotFound{0}},
{description: "delete item in list with item in first position",
original: NewLinkedList(1, 2, 3),
modified: NewLinkedList(2, 3),
item: 1},
{description: "delete item in list with item in middle position",
original: NewLinkedList(1, 2, 3),
modified: NewLinkedList(1, 3),
item: 2},
{description: "delete item in list with item in last position",
original: NewLinkedList(1, 2, 3),
modified: NewLinkedList(1, 2),
item: 3},
}
for _, tt := range useCases {
err := tt.original.Delete(tt.item)
if !compareLists(tt.original, tt.modified) || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.modified, tt.err, tt.original, err)
}
}
}
func TestLinkedList_DeleteAt(t *testing.T) {
useCases := []struct {
description string
@@ -215,17 +275,17 @@ func TestLinkedList_DeleteAt(t *testing.T) {
}{
{description: "delete item with negative position",
original: NewLinkedList[int](),
modified: nil,
modified: NewLinkedList[int](),
pos: -1,
err: ErrPositionNegative},
{description: "delete item in empty list",
original: NewLinkedList[int](),
modified: nil,
modified: NewLinkedList[int](),
pos: 0,
err: ErrEmptyList},
err: ErrEmptyCollection},
{description: "delete item in position not found",
original: NewLinkedList(1, 2, 3),
modified: NewLinkedList[int](),
modified: NewLinkedList(1, 2, 3),
pos: 5,
err: ErrNodeNotFound},
{description: "delete item in first position",
@@ -247,8 +307,49 @@ func TestLinkedList_DeleteAt(t *testing.T) {
for _, tt := range useCases {
err := tt.original.DeleteAt(tt.pos)
if !compareLists(tt.original, tt.modified) && err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
if !compareLists(tt.original, tt.modified) || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.modified, tt.err, tt.original, err)
}
}
}
func TestLinkedList_Contains(t *testing.T) {
useCases := []struct {
description string
list *LinkedList[int]
item int
want bool
}{
{description: "empty linked list contain item", list: NewLinkedList[int](), item: 0, want: false},
{description: "linked list with items search item no found", list: NewLinkedList[int](1, 2, 3), item: 0, want: false},
{description: "linked list with items search item found", list: NewLinkedList[int](1, 2, 3), item: 3, want: true},
}
for _, tt := range useCases {
result := tt.list.Contains(tt.item)
if result != tt.want {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
}
func TestLinkedList_Index(t *testing.T) {
useCases := []struct {
description string
list *LinkedList[int]
item int
pos int
err error
}{
{description: "empty linked list contain item", list: NewLinkedList[int](), item: 0, pos: 0, err: ErrItemNotFound{0}},
{description: "linked list with items search item no found", list: NewLinkedList[int](1, 2, 3), item: 0, pos: 0, err: ErrItemNotFound{0}},
{description: "linked list with items search item found", list: NewLinkedList[int](1, 2, 3), item: 3, pos: 2, err: nil},
}
for _, tt := range useCases {
pos, err := tt.list.Index(tt.item)
if pos != tt.pos || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.pos, tt.err, pos, err)
}
}
}

176
pkg/collection/slice.go Normal file
View File

@@ -0,0 +1,176 @@
package collection
import (
"fmt"
"math"
"reflect"
"strings"
)
type sliceIterator[E any] struct {
index int
slice []E
}
func (it *sliceIterator[E]) HasNext() bool {
return it.index < len(it.slice)
}
func (it *sliceIterator[E]) Next() E {
item := it.slice[it.index]
it.index += 1
return item
}
func (it *sliceIterator[E]) NextWithIndex() (int, E) {
index := it.index
item := it.slice[index]
it.index += 1
return index, item
}
type Slice[E any] struct {
inner []E
}
func NewSlice[E any](items ...E) *Slice[E] {
return &Slice[E]{items}
}
func (s *Slice[E]) Iterator() Iterator[E] {
if s.Empty() {
return &emptyListIterator[E]{}
}
return &sliceIterator[E]{0, s.inner}
}
func (s *Slice[E]) Empty() bool {
return s.Size() == 0
}
func (s *Slice[E]) Size() int {
return len(s.inner)
}
func (s *Slice[E]) Back() (E, error) {
return s.GetAt(s.Size() - 1)
}
func (s *Slice[E]) Front() (E, error) {
return s.GetAt(0)
}
func (s *Slice[E]) GetAt(pos int) (E, error) {
if s.Empty() {
return *new(E), ErrEmptyCollection
}
if pos < 0 {
return *new(E), ErrPositionNegative
}
if pos < 0 || pos >= s.Size() {
return *new(E), ErrIndexOutOfBound{pos, s.Size()}
}
return s.inner[pos], nil
}
func (s *Slice[E]) Push(item E) {
s.PushBack(item)
}
func (s *Slice[E]) PushBack(item E) {
pos := int(math.Max(0.0, float64(s.Size())))
s.PushAt(item, pos)
}
func (s *Slice[E]) PushFront(item E) {
s.PushAt(item, 0)
}
func (s *Slice[E]) PushAt(item E, pos int) {
s.inner = insert(s.inner, item, pos)
}
func insert[E any](slice []E, item E, pos int) []E {
// found https://stackoverflow.com/questions/46128016/insert-a-value-in-a-slice-at-a-given-index
n := len(slice)
if pos < 0 {
pos = (pos%n + n) % n
}
switch {
case pos == n: // nil or empty slice or after last element
return append(slice, item)
case pos < n: // pos < len(slice)
slice = append(slice[:pos+1], slice[pos:]...)
slice[pos] = item
return slice
case pos < cap(slice): // pos > len(slice)
slice = slice[:pos+1]
var zero E
for i := n; i < pos; i++ {
slice[i] = zero
}
slice[pos] = item
return slice
default:
b := make([]E, pos+1) // malloc
if n > 0 {
copy(b, slice)
}
b[pos] = item
return b
}
}
func (s *Slice[E]) Delete(item E) error {
pos, err := s.Index(item)
if err != nil {
return err
}
return s.DeleteAt(pos)
}
func (s *Slice[E]) DeleteAt(pos int) error {
if s.Empty() {
return ErrEmptyCollection
}
s.inner = append(s.inner[:pos], s.inner[pos+1:]...)
return nil
}
func (s *Slice[E]) Contains(item E) bool {
for _, elem := range s.inner {
if reflect.DeepEqual(elem, item) {
return true
}
}
return false
}
func (s *Slice[E]) Index(item E) (int, error) {
for i, x := range s.inner {
if reflect.DeepEqual(x, item) {
return i, nil
}
}
return 0, ErrItemNotFound{item}
}
func (s *Slice[E]) String() string {
var sb strings.Builder
sb.WriteString("[")
for i := 0; i < s.Size(); i++ {
var str string
item, _ := s.GetAt(i)
if i >= s.Size()-1 {
str = fmt.Sprintf("%v", item)
} else {
str = fmt.Sprintf("%v, ", item)
}
sb.WriteString(str)
}
sb.WriteString("]")
return sb.String()
}

View File

@@ -0,0 +1,330 @@
package collection
import (
"reflect"
"testing"
)
func TestSlice_Empty(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
want bool
}{
{description: "empty slice", slice: NewSlice[int](), want: true},
{description: "full slice", slice: NewSlice[int](1, 2, 3), want: false},
}
for _, tt := range useCases {
result := tt.slice.Empty()
if result != tt.want {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
}
func TestSlice_Size(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
want int
}{
{description: "empty slice", slice: NewSlice[int](), want: 0},
{description: "full slice", slice: NewSlice[int](1, 2, 3), want: 3},
}
for _, tt := range useCases {
result := tt.slice.Size()
if result != tt.want {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
}
func TestSlice_GetAt(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
pos int
item int
err error
}{
{description: "get item on empty slice", slice: NewSlice[int](), pos: 0, item: 0, err: ErrEmptyCollection},
{description: "get item on full slice with out of bound index", slice: NewSlice[int](1, 2, 3), pos: 5, item: 0, err: ErrIndexOutOfBound{5, 3}},
{description: "get item on full slice with negative index", slice: NewSlice[int](1, 2, 3), pos: -1, item: 0, err: ErrPositionNegative},
{description: "get item on full slice in first position", slice: NewSlice[int](1, 2, 3), pos: 0, item: 1, err: nil},
{description: "get item on full slice in middle position", slice: NewSlice[int](1, 2, 3), pos: 1, item: 2, err: nil},
{description: "get item on full slice in last position", slice: NewSlice[int](1, 2, 3), pos: 2, item: 3, err: nil},
}
for _, tt := range useCases {
result, err := tt.slice.GetAt(tt.pos)
if result != tt.item || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.item, tt.err, result, err)
}
}
}
func TestSlice_Back(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
pos int
item int
err error
}{
{description: "get item on empty slice", slice: NewSlice[int](), pos: 0, item: 0, err: ErrEmptyCollection},
{description: "get item on full slice in last position", slice: NewSlice[int](1, 2, 3), pos: 2, item: 3, err: nil},
}
for _, tt := range useCases {
result, err := tt.slice.Back()
if result != tt.item || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.item, tt.err, result, err)
}
}
}
func TestSlice_Front(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
pos int
item int
err error
}{
{description: "get item on empty slice", slice: NewSlice[int](), pos: 0, item: 0, err: ErrEmptyCollection},
{description: "get item on full slice in first position", slice: NewSlice[int](1, 2, 3), pos: 2, item: 1, err: nil},
}
for _, tt := range useCases {
result, err := tt.slice.Front()
if result != tt.item || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.item, tt.err, result, err)
}
}
}
func TestSlice_PushAt(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
item int
pos int
}{
{description: "push item in empty slice",
original: NewSlice[int](),
modified: NewSlice(1),
item: 1,
pos: 0},
{description: "push item in slice with item in first position",
original: NewSlice(1, 2, 3),
modified: NewSlice(0, 1, 2, 3),
item: 0,
pos: 0},
{description: "push item in slice with item in middle position",
original: NewSlice(1, 3),
modified: NewSlice(1, 2, 3),
item: 2,
pos: 1},
{description: "push item in slice with item in last position",
original: NewSlice(1, 2),
modified: NewSlice(1, 2, 3),
item: 3,
pos: 2},
}
for _, tt := range useCases {
tt.original.PushAt(tt.item, tt.pos)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_Push(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
item int
}{
{description: "push item in empty slice",
original: NewSlice[int](),
modified: NewSlice(1),
item: 1},
{description: "push item in slice with item in last position",
original: NewSlice(1, 2),
modified: NewSlice(1, 2, 3),
item: 3},
}
for _, tt := range useCases {
tt.original.Push(tt.item)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_PushBack(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
item int
}{
{description: "push item in empty slice",
original: NewSlice[int](),
modified: NewSlice(1),
item: 1},
{description: "push item in slice with item in last position",
original: NewSlice(1, 2),
modified: NewSlice(1, 2, 3),
item: 3},
}
for _, tt := range useCases {
tt.original.PushBack(tt.item)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_PushFront(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
item int
}{
{description: "push item in empty slice",
original: NewSlice[int](),
modified: NewSlice(1),
item: 1},
{description: "push item in slice with item in first position",
original: NewSlice(2, 3),
modified: NewSlice(1, 2, 3),
item: 1},
}
for _, tt := range useCases {
tt.original.PushFront(tt.item)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_Delete(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
item int
err error
}{
{description: "delete item in empty slice",
original: NewSlice[int](),
modified: NewSlice[int](),
item: 0,
err: ErrItemNotFound{0}},
{description: "delete item in slice with item in first position",
original: NewSlice(1, 2, 3),
modified: NewSlice(2, 3),
item: 1},
{description: "delete item in slice with item in middle position",
original: NewSlice(1, 2, 3),
modified: NewSlice(1, 3),
item: 2},
{description: "delete item in slice with item in last position",
original: NewSlice(1, 2, 3),
modified: NewSlice(1, 2),
item: 3},
}
for _, tt := range useCases {
err := tt.original.Delete(tt.item)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) || err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_DeleteAt(t *testing.T) {
useCases := []struct {
description string
original *Slice[int]
modified *Slice[int]
pos int
err error
}{
{description: "delete item in empty slice",
original: NewSlice[int](),
modified: NewSlice[int](),
pos: 0,
err: ErrEmptyCollection},
{description: "delete item in slice with item in first position",
original: NewSlice(1, 2, 3),
modified: NewSlice(2, 3),
pos: 0},
{description: "delete item in slice with item in middle position",
original: NewSlice(1, 2, 3),
modified: NewSlice(1, 3),
pos: 1},
{description: "delete item in slice with item in last position",
original: NewSlice(1, 2, 3),
modified: NewSlice(1, 2),
pos: 2},
}
for _, tt := range useCases {
err := tt.original.DeleteAt(tt.pos)
if !reflect.DeepEqual(tt.original.inner, tt.modified.inner) || err != tt.err {
t.Errorf("test: %s want %v got %v", tt.description, tt.modified, tt.original)
}
}
}
func TestSlice_Contains(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
item int
want bool
}{
{description: "empty slice contain item", slice: NewSlice[int](), item: 0, want: false},
{description: "slice with items search item no found", slice: NewSlice[int](1, 2, 3), item: 0, want: false},
{description: "slice with items search item found", slice: NewSlice[int](1, 2, 3), item: 3, want: true},
}
for _, tt := range useCases {
result := tt.slice.Contains(tt.item)
if result != tt.want {
t.Errorf("test: %s want %v got %v", tt.description, tt.want, result)
}
}
}
func TestSlice_Index(t *testing.T) {
useCases := []struct {
description string
slice *Slice[int]
item int
pos int
err error
}{
{description: "empty slice contain item", slice: NewSlice[int](), item: 0, pos: 0, err: ErrItemNotFound{0}},
{description: "slice with items search item no found", slice: NewSlice[int](1, 2, 3), item: 0, pos: 0, err: ErrItemNotFound{0}},
{description: "slice with items search item found", slice: NewSlice[int](1, 2, 3), item: 3, pos: 2, err: nil},
}
for _, tt := range useCases {
pos, err := tt.slice.Index(tt.item)
if pos != tt.pos || err != tt.err {
t.Errorf("test: %s want {%v, %v} got {%v, %v}", tt.description, tt.pos, tt.err, pos, err)
}
}
}

View File

@@ -5,11 +5,6 @@ import (
"strings"
)
var (
// ErrEmptyStack is error when you have an empty stack structure
ErrEmptyStack = fmt.Errorf("this stack is empty")
)
// Stack is an structure with method for handle underlying slice as a stack.
type Stack[E any] struct {
items []E
@@ -35,16 +30,16 @@ func (s *Stack[E]) Empty() bool {
}
// Top get first item in the stack structure, but
// if stack is empty well this method return ErrEmptyStack error.
// if stack is empty well this method return ErrEmptyCollection error.
func (s *Stack[E]) Top() (E, error) {
if s.Empty() {
return *new(E), ErrEmptyStack
return *new(E), ErrEmptyCollection
}
return s.items[s.Size()-1], nil
}
// Pop get and remove first item in the stack structure, but
// if stack is empty well this method return ErrEmptyStack error.
// if stack is empty well this method return ErrEmptyCollection error.
func (s *Stack[E]) Pop() (E, error) {
item, err := s.Top()
if err != nil {

View File

@@ -16,7 +16,7 @@ var staticTests = []struct {
size int
top pair
}{
{"empty stack", NewStack[int](), true, 0, pair{0, ErrEmptyStack}},
{"empty stack", NewStack[int](), true, 0, pair{0, ErrEmptyCollection}},
{"stack with items", NewStack(1, 2, 3), false, 3, pair{3, nil}},
}
@@ -25,7 +25,7 @@ var popTests = []struct {
input *Stack[int]
item pair
}{
{"empty stack pop item", NewStack[int](), pair{0, ErrEmptyStack}},
{"empty stack pop item", NewStack[int](), pair{0, ErrEmptyCollection}},
{"stack with items pop item", NewStack(1, 2, 3), pair{3, nil}},
}