added helper pkgs
This commit is contained in:
parent
c8f2534112
commit
97014203e4
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/go-ap/jsonld"
|
"github.com/go-ap/jsonld"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"sectorinf.com/emilis/flabk/asf/ap"
|
"sectorinf.com/emilis/flabk/flabk/ap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetExample() ap.Object {
|
func GetExample() ap.Object {
|
||||||
|
|
|
@ -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