parent
c8f2534112
commit
97014203e4
5 changed files with 409 additions and 1 deletions
@ -0,0 +1,19 @@ |
||||
package coll |
||||
|
||||
type Iterator[T any] Vector[T] |
||||
|
||||
func (i Iterator[T]) ForEach(f func(int, T)) { |
||||
for index := 0; index < i.length; index++ { |
||||
f(index, i.array[index]) |
||||
} |
||||
} |
||||
|
||||
func (i Iterator[T]) ForBreak(f func(index int, t T, breaker func())) { |
||||
var broke bool |
||||
brk := func() { |
||||
broke = true |
||||
} |
||||
for index := 0; index < i.length || !broke; index++ { |
||||
f(index, i.array[index], brk) |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
// Package coll provides generic collection types and functions
|
||||
package coll |
||||
|
||||
func Map[T, V any](c Vector[T], f func(T) V) Vector[V] { |
||||
out := make([]V, c.length) |
||||
for index := 0; index < c.length; index++ { |
||||
out[index] = f(c.array[index]) |
||||
} |
||||
|
||||
return From(out) |
||||
} |
||||
|
||||
func Filter[T any](v Vector[T], f func(T) bool) Vector[T] { |
||||
out := WithCap[T](v.length) |
||||
v.Iterate().ForEach(func(_ int, t T) { |
||||
if f(t) { |
||||
out.Push(t) |
||||
} |
||||
}) |
||||
return out |
||||
} |
||||
|
||||
func Take[T any](v Vector[T], howMany int) Vector[T] { |
||||
if v.length == 0 { |
||||
return New[T]() |
||||
} |
||||
if v.length < howMany { |
||||
howMany = v.length |
||||
} |
||||
return From(v.array[:howMany-1]) |
||||
} |
||||
|
||||
func Any[T any](v Vector[T], f func(T) bool) bool { |
||||
var found bool |
||||
v.Iterate().ForBreak(func(_ int, t T, breaker func()) { |
||||
if f(t) { |
||||
found = true |
||||
breaker() |
||||
} |
||||
}) |
||||
return found |
||||
} |
||||
|
||||
type numeric interface { |
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 |
||||
} |
||||
|
||||
func Min[T numeric](v Vector[T]) T { |
||||
var min T |
||||
if v.length == 0 { |
||||
return min |
||||
} |
||||
min = v.array[0] |
||||
v.Iterate().ForEach(func(_ int, t T) { |
||||
if min > t { |
||||
min = t |
||||
} |
||||
}) |
||||
|
||||
return min |
||||
} |
||||
|
||||
func Max[T numeric](v Vector[T]) T { |
||||
var max T |
||||
v.Iterate().ForEach(func(_ int, t T) { |
||||
if max < t { |
||||
max = t |
||||
} |
||||
}) |
||||
|
||||
return max |
||||
} |
@ -0,0 +1,165 @@ |
||||
package coll |
||||
|
||||
import "fmt" |
||||
|
||||
const ( |
||||
DefaultSize = 4 |
||||
) |
||||
|
||||
type Vector[T any] struct { |
||||
array []T |
||||
length int |
||||
capacity int |
||||
} |
||||
|
||||
func New[T any]() Vector[T] { |
||||
return WithCap[T](DefaultSize) |
||||
} |
||||
|
||||
func WithCap[T any](capacity int) Vector[T] { |
||||
return Vector[T]{ |
||||
array: make([]T, capacity), |
||||
length: 0, |
||||
capacity: capacity, |
||||
} |
||||
} |
||||
|
||||
func From[T any](v []T) Vector[T] { |
||||
return Vector[T]{ |
||||
array: v, |
||||
length: len(v), |
||||
capacity: len(v), |
||||
} |
||||
} |
||||
|
||||
func (v Vector[T]) Push(t T) Vector[T] { |
||||
if v.length == v.capacity { |
||||
v = v.upsize() |
||||
} |
||||
|
||||
v.array[v.length] = t |
||||
v.length++ |
||||
return v |
||||
} |
||||
|
||||
func (v Vector[T]) Append(t ...T) Vector[T] { |
||||
if v.capacity-v.length < len(t) { |
||||
v = v.upsizeSpecific(len(t)) |
||||
} |
||||
var tIndex int |
||||
for ; v.length < v.capacity; v.length++ { |
||||
v.array[v.length] = t[tIndex] |
||||
tIndex++ |
||||
} |
||||
return v |
||||
} |
||||
|
||||
func (v Vector[T]) Remove(index int) Vector[T] { |
||||
return From(append(v.array[:index], v.array[index+1:v.length]...)) |
||||
} |
||||
|
||||
// Faster remove function that can be used on vectors where ordering doesn't matter
|
||||
func (v Vector[T]) RemoveUnordered(index int) Vector[T] { |
||||
v.length-- |
||||
v.array[index] = v.array[v.length] |
||||
return v |
||||
} |
||||
|
||||
func (v Vector[T]) upsize() Vector[T] { |
||||
return v.upsizeSpecific(v.capacity) |
||||
} |
||||
|
||||
func (v Vector[T]) upsizeSpecific(extraSize int) Vector[T] { |
||||
v.array = append(v.array, make([]T, extraSize)...) |
||||
v.capacity = len(v.array) |
||||
return v |
||||
} |
||||
|
||||
func (v Vector[T]) Slice() []T { |
||||
if v.length == 0 { |
||||
return []T{} |
||||
} |
||||
return v.array[:v.length] |
||||
} |
||||
|
||||
func (v Vector[T]) panicIndex(index int) { |
||||
min := -1 |
||||
if v.length != 0 { |
||||
min = 0 |
||||
} |
||||
panic(fmt.Sprintf("index %d out of range [%d;%d)", index, min, v.length)) |
||||
} |
||||
|
||||
// GetSoft tries to get the requested index, or returns a default value if
|
||||
// it's out of range
|
||||
func (v Vector[T]) GetSoft(index int) T { |
||||
var result T |
||||
if index < 0 || index >= v.length { |
||||
return result |
||||
} |
||||
return v.array[index] |
||||
} |
||||
|
||||
func (v Vector[T]) Get(index int) T { |
||||
if index < 0 || index >= v.length { |
||||
v.panicIndex(index) |
||||
} |
||||
return v.array[index] |
||||
} |
||||
|
||||
func (v Vector[T]) Set(index int, value T) Vector[T] { |
||||
if index < 0 || index >= v.length { |
||||
v.panicIndex(index) |
||||
} |
||||
v.array[index] = value |
||||
return v |
||||
} |
||||
|
||||
func (v Vector[T]) Len() int { |
||||
return v.length |
||||
} |
||||
|
||||
func (v Vector[T]) Iterate() Iterator[T] { |
||||
return Iterator[T](v) |
||||
} |
||||
|
||||
func (v Vector[T]) Pop() (T, Vector[T]) { |
||||
v.length-- |
||||
t := v.array[v.length] |
||||
return t, v |
||||
} |
||||
|
||||
func (v Vector[T]) Sub(start, end int) Vector[T] { |
||||
if start >= v.length { |
||||
v.panicIndex(start) |
||||
} |
||||
if end >= v.length { |
||||
v.panicIndex(end) |
||||
} |
||||
if start < 0 { |
||||
return From(v.array[:end]) |
||||
} |
||||
if end < 0 { |
||||
return From(v.array[start:]) |
||||
} |
||||
return From(v.array[start:end]) |
||||
} |
||||
|
||||
func (v Vector[T]) Filter(f func(T) bool) Vector[T] { |
||||
return Filter(v, f) |
||||
} |
||||
|
||||
func (v Vector[T]) Any(f func(T) bool) bool { |
||||
return Any(v, f) |
||||
} |
||||
|
||||
func (v Vector[T]) Take(howMany int) Vector[T] { |
||||
return Take(v, howMany) |
||||
} |
||||
|
||||
func (v Vector[T]) Clone() Vector[T] { |
||||
clone := make([]T, len(v.array)) |
||||
copy(clone, v.array) |
||||
v.array = clone |
||||
return v |
||||
} |
@ -0,0 +1,152 @@ |
||||
package coll_test |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
"sectorinf.com/emilis/flabk/pkg/coll" |
||||
) |
||||
|
||||
func TestVector(t *testing.T) { |
||||
tests := map[string]func(that *require.Assertions){ |
||||
"push": func(that *require.Assertions) { |
||||
v := coll.New[int]() |
||||
v = v.Push(0).Push(1).Push(2).Push(3).Push(4).Push(5) |
||||
that.Equal(6, v.Len()) |
||||
that.Len(v.Slice(), 6) |
||||
that.Equal([]int{0, 1, 2, 3, 4, 5}, v.Slice()) |
||||
}, |
||||
"len": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
that.Equal(3, v.Len()) |
||||
that.Len(v.Slice(), v.Len()) |
||||
}, |
||||
"from": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
that.Equal(3, v.Len()) |
||||
that.Len(v.Slice(), 3) |
||||
}, |
||||
"pop": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
t, v := v.Pop() |
||||
that.Equal(3, t) |
||||
that.Equal(2, v.Len()) |
||||
that.Equal([]int{1, 2}, v.Slice()) |
||||
}, |
||||
"withcap": func(that *require.Assertions) { |
||||
v := coll.WithCap[int](3) |
||||
that.Zero(v.Len()) |
||||
that.Len(v.Slice(), 0) |
||||
}, |
||||
"remove": func(that *require.Assertions) { |
||||
v := coll.New[int]().Push(0).Push(1).Push(2) |
||||
r1 := v.Remove(1) |
||||
that.Equal(2, r1.Len()) |
||||
that.Equal([]int{0, 2}, r1.Slice()) |
||||
that.Panics(func() { |
||||
v.Remove(-1) |
||||
}) |
||||
that.Panics(func() { |
||||
v.Remove(100000) |
||||
}) |
||||
}, |
||||
"remove unordered": func(that *require.Assertions) { |
||||
v := coll.New[int]().Push(0).Push(1).Push(2) |
||||
v = v.RemoveUnordered(1) |
||||
that.Equal(2, v.Len()) |
||||
vSlice := v.Slice() |
||||
if vSlice[0] == 0 { |
||||
that.Equal(2, vSlice[1]) |
||||
} else { |
||||
that.Equal(2, vSlice[0]) |
||||
that.Zero(vSlice[1]) |
||||
} |
||||
}, |
||||
"append": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}).Append(4, 5, 6) |
||||
that.Equal(6, v.Len()) |
||||
that.Equal([]int{1, 2, 3, 4, 5, 6}, v.Slice()) |
||||
}, |
||||
"getsoft": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
that.Equal(2, v.GetSoft(1)) |
||||
that.Zero(v.GetSoft(-1000)) |
||||
that.Zero(v.GetSoft(1000)) |
||||
}, |
||||
"get": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
that.Equal(2, v.Get(1)) |
||||
that.Panics(func() { |
||||
v.Get(-1000) |
||||
}) |
||||
that.Panics(func() { |
||||
v.Get(1000) |
||||
}) |
||||
}, |
||||
"clone": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
|
||||
v1 := v.Clone().Set(1, 1) |
||||
that.Equal(3, v1.Len()) |
||||
that.Equal([]int{1, 1, 3}, v1.Slice()) |
||||
that.Equal([]int{1, 2, 3}, v.Slice()) |
||||
}, |
||||
"set": func(that *require.Assertions) { |
||||
v := coll.From([]int{1, 2, 3}) |
||||
|
||||
v1 := v.Clone().Set(1, 1) |
||||
that.Equal(3, v1.Len()) |
||||
that.Equal([]int{1, 1, 3}, v1.Slice()) |
||||
|
||||
v2 := v.Clone().Set(2, 1) |
||||
that.Equal(3, v2.Len()) |
||||
that.Equal([]int{1, 2, 1}, v2.Slice()) |
||||
|
||||
v3 := v.Clone().Set(0, 16) |
||||
that.Equal(3, v3.Len()) |
||||
that.Equal([]int{16, 2, 3}, v3.Slice()) |
||||
|
||||
that.Panics(func() { |
||||
v.Set(-1000, 1) |
||||
}) |
||||
that.Panics(func() { |
||||
v.Set(3, 1) |
||||
}) |
||||
}, |
||||
"sub": func(that *require.Assertions) { |
||||
v := coll.From([]int{0, 1, 2, 3, 4, 5, 6}) |
||||
|
||||
v1 := v.Clone().Sub(2, 4) |
||||
that.Equal(2, v1.Len()) |
||||
that.Equal([]int{2, 3}, v1.Slice()) |
||||
|
||||
v2 := v.Clone().Sub(2, 5) |
||||
that.Equal(3, v2.Len()) |
||||
that.Equal([]int{2, 3, 4}, v2.Slice()) |
||||
|
||||
v3 := v.Clone().Sub(5, -1) |
||||
that.Equal(2, v3.Len()) |
||||
that.Equal([]int{5, 6}, v3.Slice()) |
||||
|
||||
v4 := v.Clone().Sub(-1, 2) |
||||
that.Equal(2, v4.Len()) |
||||
that.Equal([]int{0, 1}, v4.Slice()) |
||||
|
||||
that.Panics(func() { |
||||
v.Sub(0, 1000) |
||||
}) |
||||
that.Panics(func() { |
||||
v.Sub(4000, 4002) |
||||
}) |
||||
that.Panics(func() { |
||||
v.Sub(2, 1) |
||||
}) |
||||
}, |
||||
} |
||||
|
||||
for name, test := range tests { |
||||
t.Run(name, func(tt *testing.T) { |
||||
test(require.New(tt)) |
||||
}) |
||||
} |
||||
} |
Loading…
Reference in new issue