Skip to content

Commit

Permalink
update the array list
Browse files Browse the repository at this point in the history
  • Loading branch information
architagr committed Jan 13, 2025
1 parent 783cb40 commit 058395b
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 132 deletions.
7 changes: 7 additions & 0 deletions .ci.gofmt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

if [ -n "$(gofmt -l .)" ]; then
echo "Go code is not formatted:"
gofmt -d .
exit 1
fi
5 changes: 5 additions & 0 deletions .ci.govet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

set -e

go vet ./...
21 changes: 18 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,27 @@ on:
branches:
- main

name: run tests
name: All builds
jobs:
build:
strategy:
matrix:
go-version: ["1.18", "1.19", "1.20", "1.21", "1.22", "1.23"]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- run: ./.ci.gofmt.sh
- run: ./.ci.govet.sh
- run: go test -v -race ./...
test:
strategy:
matrix:
go-version: ["1.18", "1.19", "1.20", "1.21", "1.22"]
go-version: ["1.18", "1.19", "1.20", "1.21", "1.22", "1.23"]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand All @@ -23,7 +38,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2
- name: Run tests
run: go test ./... -v -covermode=count
run: go test ./... -race -v -covermode=count

coverage:
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/architagr/golang_collections
module github.com/architagr/golang_collections/v1

go 1.19
go 1.23

require github.com/emirpasic/gods v1.18.1 //use to get benchmark
92 changes: 55 additions & 37 deletions list/array_list.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
package list

import "fmt"

var (
ArrayListCapacity int = 100
growthPercentage = float32(1.0) // growth by 100%
shrinkPercentage = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink)
)

type arrayList[deepCopy IDeepCopy[T], T any] struct {
data []deepCopy
type arrayList[T any] struct {
data []T
size int
}

func InitArrayList[deepCopy IDeepCopy[T], T any](data ...deepCopy) IItratorList[deepCopy, T] {
func InitArrayList[T any](data ...T) IItratorList[T] {
size := 0
if len(data) == 0 {
data = make([]deepCopy, ArrayListCapacity)
data = make([]T, ArrayListCapacity)
} else {
size = len(data)
}
l := &arrayList[deepCopy, T]{
l := &arrayList[T]{
data: data,
size: size,
}
return l
}

func (l *arrayList[deepCopy, T]) Add(data deepCopy) (resultIndex int) {
func (l *arrayList[T]) Add(data T) (resultIndex int) {
l.growArrayList(1)
l.data[l.size] = data
l.size++
resultIndex = l.size - 1
return
}

func (l *arrayList[deepCopy, T]) AddAtIndex(index int, data deepCopy) (err error) {
func (l *arrayList[T]) AddAtIndex(index int, data T) (err error) {
err = l.validateIndex(index)
if err != nil {
return
Expand All @@ -45,20 +47,20 @@ func (l *arrayList[deepCopy, T]) AddAtIndex(index int, data deepCopy) (err error
return
}

func (l *arrayList[deepCopy, T]) Remove(data deepCopy) (removedIndex int, err error) {
func (l *arrayList[T]) Remove(data T) (removedIndex int, err error) {
removedIndex = -1
for i := 0; i < l.Count(); i++ {
if data.Equal(l.data[i]) {
if AreEqual(data, l.data[i]) {
l.removeElement(i)
removedIndex = i
return
}
}
err = errDataNotFoundError
err = ErrDataNotFoundError
return
}

func (l *arrayList[deepCopy, T]) RemoveAtIndex(index int) (data deepCopy, err error) {
func (l *arrayList[T]) RemoveAtIndex(index int) (data T, err error) {
err = l.validateIndex(index)
if err != nil {
return
Expand All @@ -68,8 +70,8 @@ func (l *arrayList[deepCopy, T]) RemoveAtIndex(index int) (data deepCopy, err er
return
}

func (l *arrayList[deepCopy, T]) RemoveAll(f Filterfunc[deepCopy, T]) []deepCopy {
removedData := make([]deepCopy, 0, l.Count())
func (l *arrayList[T]) RemoveAll(f Filterfunc[T]) []T {
removedData := make([]T, 0, l.Count())
for i := 0; i < l.Count(); {
val := l.data[i]
if f(val) {
Expand All @@ -82,11 +84,11 @@ func (l *arrayList[deepCopy, T]) RemoveAll(f Filterfunc[deepCopy, T]) []deepCopy
return removedData
}

func (l *arrayList[deepCopy, T]) Count() int {
func (l *arrayList[T]) Count() int {
return l.size
}

func (l *arrayList[deepCopy, T]) Get(index int) (data deepCopy, err error) {
func (l *arrayList[T]) Get(index int) (data T, err error) {
err = l.validateIndex(index)
if err != nil {
return
Expand All @@ -95,7 +97,7 @@ func (l *arrayList[deepCopy, T]) Get(index int) (data deepCopy, err error) {
return
}

func (l *arrayList[deepCopy, T]) Set(index int, data deepCopy) error {
func (l *arrayList[T]) Set(index int, data T) error {
err := l.validateIndex(index)
if err != nil {
return err
Expand All @@ -104,17 +106,27 @@ func (l *arrayList[deepCopy, T]) Set(index int, data deepCopy) error {
return nil
}

func (l *arrayList[deepCopy, T]) Find(data deepCopy) (index int) {
func (l *arrayList[T]) Find(data T) (index int) {
v, implementsDeepCopy := CheckImplementsDeepCopy(data)
index = -1
for i := 0; i < l.size; i++ {
if data.Equal(l.data[i]) {
return i
if implementsDeepCopy {
if v.Equal(l.data[i]) {
index = i
break
}
} else {
if AreEqual(data, l.data[i]) {
index = i
break
}
}
}
return -1
return index
}

func (l *arrayList[deepCopy, T]) Filter(f Filterfunc[deepCopy, T]) []deepCopy {
result := make([]deepCopy, 0, l.Count())
func (l *arrayList[T]) Filter(f Filterfunc[T]) []T {
result := make([]T, 0, l.Count())
for i := 0; i < l.size; i++ {
if f(l.data[i]) {
result = append(result, l.data[i])
Expand All @@ -123,40 +135,46 @@ func (l *arrayList[deepCopy, T]) Filter(f Filterfunc[deepCopy, T]) []deepCopy {
return result
}

func (l *arrayList[deepCopy, T]) DeepCopy() []deepCopy {
result := make([]deepCopy, 0, l.Count())
func (l *arrayList[T]) DeepCopy() ([]T, error) {
if l.Count() == 0 {
return nil, nil
}
if _, ok := CheckImplementsDeepCopy(l.data[0]); !ok {
var o IDeepCopy[T]
return nil, fmt.Errorf("%w %T", ErrDoesNotImplement, o)
}
result := make([]T, 0, l.Count())
for i := 0; i < l.Count(); i++ {
if l.data[i] != nil {
data, ok := (l.data[i].Copy()).(deepCopy)
if ok {
result = append(result, data)
}
v, _ := CheckImplementsDeepCopy(l.data[i])
if v != nil {
data := v.Copy()
result = append(result, data)
}
}
return result
return result, nil
}

func (l *arrayList[deepCopy, T]) removeElement(index int) {
func (l *arrayList[T]) removeElement(index int) {
copy(l.data[index:], l.data[index+1:l.Count()])
l.size--
l.shrinkArrayList()
}

func (l *arrayList[deepCopy, T]) validateIndex(index int) error {
func (l *arrayList[T]) validateIndex(index int) error {
if index < 0 || l.Count()-1 < index {
return errInvalidIndex
return ErrInvalidIndex
}
return nil
}

func (l *arrayList[deepCopy, T]) resizeList(cap int) {
newElements := make([]deepCopy, cap)
func (l *arrayList[T]) resizeList(cap int) {
newElements := make([]T, cap)
copy(newElements, l.data)
l.data = newElements
}

// Expand the array if necessary, i.e. capacity will be reached if we add n elements
func (l *arrayList[deepCopy, T]) growArrayList(n int) {
func (l *arrayList[T]) growArrayList(n int) {
// When capacity is reached, grow by a percentage of growthPercentage and add number of elements
currentCapacity := cap(l.data)
if l.Count()+n >= currentCapacity {
Expand All @@ -167,7 +185,7 @@ func (l *arrayList[deepCopy, T]) growArrayList(n int) {

// Shrink the array if necessary,
// basically when size is shrinkPercentage % of current capacity
func (l *arrayList[deepCopy, T]) shrinkArrayList() {
func (l *arrayList[T]) shrinkArrayList() {
if shrinkPercentage == 0.0 {
return
}
Expand Down
22 changes: 11 additions & 11 deletions list/arraylist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func TestAddingAtIndexNewDataInvalidIndex(t *testing.T) {
name: "test 10",
}
err := userList.AddAtIndex(10, input)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if adding at wrong index")
}

Expand All @@ -134,7 +134,7 @@ func TestAddingAtIndexNewDataNegativeIndex(t *testing.T) {
name: "test 10",
}
err := userList.AddAtIndex(-1, input)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if adding at wring index")
}

Expand Down Expand Up @@ -163,14 +163,14 @@ func TestAddingAtIndexNewData(t *testing.T) {
func TestGetWrongIndex(t *testing.T) {
userList := InitArrayList(getSampleData()...)
_, err := userList.Get(100)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if adding at wrong index")
}
}
func TestGetNegativeIndex(t *testing.T) {
userList := InitArrayList(getSampleData()...)
_, err := userList.Get(-1)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if adding at wrong index")
}
}
Expand All @@ -192,14 +192,14 @@ func TestGet(t *testing.T) {
func TestRemoveAtIndexWrongIndex(t *testing.T) {
userList := InitArrayList(getSampleData()...)
_, err := userList.RemoveAtIndex(100)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if removing at wrong index")
}
}
func TestRemoveAtIndexNegativeIndex(t *testing.T) {
list := InitArrayList(getSampleData()...)
_, err := list.RemoveAtIndex(-1)
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if removing at wrong index")
}
}
Expand Down Expand Up @@ -228,7 +228,7 @@ func TestRemoveNegative(t *testing.T) {
id: 100,
name: "test",
})
if err != errDataNotFoundError {
if err != ErrDataNotFoundError {
t.Fatalf("Array list should through error if removing wrong index")
}
}
Expand Down Expand Up @@ -258,7 +258,7 @@ func TestSetWrongIndex(t *testing.T) {
id: 100,
name: "test",
})
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if removing at wrong index")
}
}
Expand All @@ -268,7 +268,7 @@ func TestSetNegativeIndex(t *testing.T) {
id: 100,
name: "test",
})
if err != errInvalidIndex {
if err != ErrInvalidIndex {
t.Fatalf("Array list should through error if removing at wrong index")
}
}
Expand Down Expand Up @@ -341,7 +341,7 @@ func TestFilter(t *testing.T) {

func TestDeepCopy(t *testing.T) {
userList := InitArrayList(getSampleData()...)
response := userList.DeepCopy()
response, _ := userList.DeepCopy()
if len(response) != len(getSampleData()) {
t.Fatalf("Array list return same data")
}
Expand All @@ -359,7 +359,7 @@ func TestRemoveAll(t *testing.T) {
t.Fatalf("removed some data that was not supposed to be removed")
}
}
response := userList.DeepCopy()
response, _ := userList.DeepCopy()
for _, val := range response {
if val.id%2 == 0 {
t.Fatalf("did not remove data that was not supposed to be removed")
Expand Down
Loading

0 comments on commit 058395b

Please sign in to comment.