Optimization for vector

This commit is contained in:
emilis 2022-08-02 15:49:10 +01:00
parent 97014203e4
commit b699d60cfc
4 changed files with 92 additions and 140 deletions

View File

@ -1,19 +0,0 @@
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)
}
}

View File

@ -2,43 +2,41 @@
package coll package coll
func Map[T, V any](c Vector[T], f func(T) V) Vector[V] { func Map[T, V any](c Vector[T], f func(T) V) Vector[V] {
out := make([]V, c.length) out := make([]V, len(c))
for index := 0; index < c.length; index++ { for index := 0; index < len(c); index++ {
out[index] = f(c.array[index]) out[index] = f(c[index])
} }
return From(out) return From(out)
} }
func Filter[T any](v Vector[T], f func(T) bool) Vector[T] { func Filter[T any](v Vector[T], f func(T) bool) Vector[T] {
out := WithCap[T](v.length) out := WithCap[T](len(v))
v.Iterate().ForEach(func(_ int, t T) { for _, t := range v {
if f(t) { if f(t) {
out.Push(t) out = out.Push(t)
}
} }
})
return out return out
} }
func Take[T any](v Vector[T], howMany int) Vector[T] { func Take[T any](v Vector[T], howMany int) Vector[T] {
if v.length == 0 { if len(v) == 0 {
return New[T]() return New[T]()
} }
if v.length < howMany { if len(v) < howMany {
howMany = v.length howMany = len(v)
} }
return From(v.array[:howMany-1]) return From(v[:howMany-1])
} }
func Any[T any](v Vector[T], f func(T) bool) bool { func Any[T any](v Vector[T], f func(T) bool) bool {
var found bool for _, t := range v {
v.Iterate().ForBreak(func(_ int, t T, breaker func()) {
if f(t) { if f(t) {
found = true return true
breaker()
} }
}) }
return found return false
} }
type numeric interface { type numeric interface {
@ -47,26 +45,25 @@ type numeric interface {
func Min[T numeric](v Vector[T]) T { func Min[T numeric](v Vector[T]) T {
var min T var min T
if v.length == 0 { if len(v) == 0 {
return min return min
} }
min = v.array[0] min = v[0]
v.Iterate().ForEach(func(_ int, t T) { for _, t := range v {
if min > t { if min > t {
min = t min = t
} }
}) }
return min return min
} }
func Max[T numeric](v Vector[T]) T { func Max[T numeric](v Vector[T]) T {
var max T var max T
v.Iterate().ForEach(func(_ int, t T) { for _, t := range v {
if max < t { if max < t {
max = t max = t
} }
}) }
return max return max
} }

View File

@ -6,143 +6,116 @@ const (
DefaultSize = 4 DefaultSize = 4
) )
type Vector[T any] struct { type Vector[T any] []T
array []T
length int
capacity int
}
func New[T any]() Vector[T] { func New[T any]() Vector[T] {
return WithCap[T](DefaultSize) return WithCap[T](DefaultSize)
} }
func WithCap[T any](capacity int) Vector[T] { func WithCap[T any](capacity int) Vector[T] {
return Vector[T]{ return make(Vector[T], 0, capacity)
array: make([]T, capacity),
length: 0,
capacity: capacity,
}
} }
func From[T any](v []T) Vector[T] { func From[T any](v []T) Vector[T] {
return Vector[T]{ return Vector[T](v)
array: v,
length: len(v),
capacity: len(v),
}
} }
func (v Vector[T]) Push(t T) Vector[T] { func (v Vector[T]) Push(t T) Vector[T] {
if v.length == v.capacity { if len(v) == cap(v) {
v = v.upsize() v = v.upsize()
} }
v.array[v.length] = t v = v[:len(v)+1]
v.length++ v[len(v)-1] = t
return v return v
} }
func (v Vector[T]) Append(t ...T) Vector[T] { func (v Vector[T]) Append(t ...T) Vector[T] {
if v.capacity-v.length < len(t) { if cap(v)-len(v) < len(t) {
v = v.upsizeSpecific(len(t)) v = v.upsizeSpecific(len(t))
} }
startLen := len(v)
v = v[:len(v)+len(t)]
var tIndex int var tIndex int
for ; v.length < v.capacity; v.length++ { for index := startLen; index < cap(v); index++ {
v.array[v.length] = t[tIndex] v[index] = t[tIndex]
tIndex++ tIndex++
} }
return v return v
} }
func (v Vector[T]) Remove(index int) Vector[T] { func (v Vector[T]) Remove(index int) Vector[T] {
return From(append(v.array[:index], v.array[index+1:v.length]...)) return From(append(v[:index], v[index+1:]...))
} }
// Faster remove function that can be used on vectors where ordering doesn't matter // Faster remove function that can be used on vectors where ordering doesn't matter
func (v Vector[T]) RemoveUnordered(index int) Vector[T] { func (v Vector[T]) RemoveUnordered(index int) Vector[T] {
v.length-- v[index] = v[len(v)-1]
v.array[index] = v.array[v.length] return v[:len(v)-1]
return v
} }
func (v Vector[T]) upsize() Vector[T] { func (v Vector[T]) upsize() Vector[T] {
return v.upsizeSpecific(v.capacity) return v.upsizeSpecific(cap(v))
} }
func (v Vector[T]) upsizeSpecific(extraSize int) Vector[T] { func (v Vector[T]) upsizeSpecific(extraSize int) Vector[T] {
v.array = append(v.array, make([]T, extraSize)...) resized := make([]T, len(v), cap(v)+extraSize)
v.capacity = len(v.array) copy(resized, v)
return v return resized
}
func (v Vector[T]) Slice() []T {
if v.length == 0 {
return []T{}
}
return v.array[:v.length]
} }
func (v Vector[T]) panicIndex(index int) { func (v Vector[T]) panicIndex(index int) {
min := -1 min := -1
if v.length != 0 { if len(v) != 0 {
min = 0 min = 0
} }
panic(fmt.Sprintf("index %d out of range [%d;%d)", index, min, v.length)) panic(fmt.Sprintf("index %d out of range [%d;%d)", index, min, len(v)))
} }
// GetSoft tries to get the requested index, or returns a default value if // GetSoft tries to get the requested index, or returns a default value if
// it's out of range // it's out of range
func (v Vector[T]) GetSoft(index int) T { func (v Vector[T]) GetSoft(index int) T {
var result T var result T
if index < 0 || index >= v.length { if index < 0 || index >= len(v) {
return result return result
} }
return v.array[index] return v[index]
} }
func (v Vector[T]) Get(index int) T { func (v Vector[T]) Get(index int) T {
if index < 0 || index >= v.length { if index < 0 || index >= len(v) {
v.panicIndex(index) v.panicIndex(index)
} }
return v.array[index] return v[index]
} }
func (v Vector[T]) Set(index int, value T) Vector[T] { func (v Vector[T]) Set(index int, value T) Vector[T] {
if index < 0 || index >= v.length { if index < 0 || index >= len(v) {
v.panicIndex(index) v.panicIndex(index)
} }
v.array[index] = value v[index] = value
return v 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]) { func (v Vector[T]) Pop() (T, Vector[T]) {
v.length-- t := v[len(v)-1]
t := v.array[v.length] return t, v[:len(v)-1]
return t, v
} }
func (v Vector[T]) Sub(start, end int) Vector[T] { func (v Vector[T]) Sub(start, end int) Vector[T] {
if start >= v.length { if start >= len(v) {
v.panicIndex(start) v.panicIndex(start)
} }
if end >= v.length { if end >= len(v) {
v.panicIndex(end) v.panicIndex(end)
} }
if start < 0 { if start < 0 {
return From(v.array[:end]) return From(v[:end])
} }
if end < 0 { if end < 0 {
return From(v.array[start:]) return From(v[start:])
} }
return From(v.array[start:end]) return From(v[start:end])
} }
func (v Vector[T]) Filter(f func(T) bool) Vector[T] { func (v Vector[T]) Filter(f func(T) bool) Vector[T] {
@ -158,8 +131,8 @@ func (v Vector[T]) Take(howMany int) Vector[T] {
} }
func (v Vector[T]) Clone() Vector[T] { func (v Vector[T]) Clone() Vector[T] {
clone := make([]T, len(v.array)) clone := make([]T, len(v))
copy(clone, v.array) copy(clone, v)
v.array = clone v = clone
return v return v
} }

View File

@ -12,37 +12,33 @@ func TestVector(t *testing.T) {
"push": func(that *require.Assertions) { "push": func(that *require.Assertions) {
v := coll.New[int]() v := coll.New[int]()
v = v.Push(0).Push(1).Push(2).Push(3).Push(4).Push(5) v = v.Push(0).Push(1).Push(2).Push(3).Push(4).Push(5)
that.Equal(6, v.Len()) that.Len(v, 6)
that.Len(v.Slice(), 6) that.EqualValues([]int{0, 1, 2, 3, 4, 5}, v)
that.Equal([]int{0, 1, 2, 3, 4, 5}, v.Slice())
}, },
"len": func(that *require.Assertions) { "len": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
that.Equal(3, v.Len()) that.Len(v, len(v))
that.Len(v.Slice(), v.Len())
}, },
"from": func(that *require.Assertions) { "from": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
that.Equal(3, v.Len()) that.Len(v, 3)
that.Len(v.Slice(), 3)
}, },
"pop": func(that *require.Assertions) { "pop": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
t, v := v.Pop() t, v := v.Pop()
that.Equal(3, t) that.Equal(3, t)
that.Equal(2, v.Len()) that.EqualValues([]int{1, 2}, v)
that.Equal([]int{1, 2}, v.Slice())
}, },
"withcap": func(that *require.Assertions) { "withcap": func(that *require.Assertions) {
v := coll.WithCap[int](3) v := coll.WithCap[int](3)
that.Zero(v.Len()) that.Zero(len(v))
that.Len(v.Slice(), 0) that.Len(v, 0)
}, },
"remove": func(that *require.Assertions) { "remove": func(that *require.Assertions) {
v := coll.New[int]().Push(0).Push(1).Push(2) v := coll.New[int]().Push(0).Push(1).Push(2)
r1 := v.Remove(1) r1 := v.Remove(1)
that.Equal(2, r1.Len()) that.Equal(2, len(r1))
that.Equal([]int{0, 2}, r1.Slice()) that.EqualValues([]int{0, 2}, r1)
that.Panics(func() { that.Panics(func() {
v.Remove(-1) v.Remove(-1)
}) })
@ -53,8 +49,8 @@ func TestVector(t *testing.T) {
"remove unordered": func(that *require.Assertions) { "remove unordered": func(that *require.Assertions) {
v := coll.New[int]().Push(0).Push(1).Push(2) v := coll.New[int]().Push(0).Push(1).Push(2)
v = v.RemoveUnordered(1) v = v.RemoveUnordered(1)
that.Equal(2, v.Len()) that.Equal(2, len(v))
vSlice := v.Slice() vSlice := v
if vSlice[0] == 0 { if vSlice[0] == 0 {
that.Equal(2, vSlice[1]) that.Equal(2, vSlice[1])
} else { } else {
@ -64,8 +60,8 @@ func TestVector(t *testing.T) {
}, },
"append": func(that *require.Assertions) { "append": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}).Append(4, 5, 6) v := coll.From([]int{1, 2, 3}).Append(4, 5, 6)
that.Equal(6, v.Len()) that.Equal(6, len(v))
that.Equal([]int{1, 2, 3, 4, 5, 6}, v.Slice()) that.EqualValues([]int{1, 2, 3, 4, 5, 6}, v)
}, },
"getsoft": func(that *require.Assertions) { "getsoft": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
@ -87,24 +83,24 @@ func TestVector(t *testing.T) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
v1 := v.Clone().Set(1, 1) v1 := v.Clone().Set(1, 1)
that.Equal(3, v1.Len()) that.Equal(3, len(v1))
that.Equal([]int{1, 1, 3}, v1.Slice()) that.EqualValues([]int{1, 1, 3}, v1)
that.Equal([]int{1, 2, 3}, v.Slice()) that.EqualValues([]int{1, 2, 3}, v)
}, },
"set": func(that *require.Assertions) { "set": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3}) v := coll.From([]int{1, 2, 3})
v1 := v.Clone().Set(1, 1) v1 := v.Clone().Set(1, 1)
that.Equal(3, v1.Len()) that.Equal(3, len(v1))
that.Equal([]int{1, 1, 3}, v1.Slice()) that.EqualValues([]int{1, 1, 3}, v1)
v2 := v.Clone().Set(2, 1) v2 := v.Clone().Set(2, 1)
that.Equal(3, v2.Len()) that.Equal(3, len(v2))
that.Equal([]int{1, 2, 1}, v2.Slice()) that.EqualValues([]int{1, 2, 1}, v2)
v3 := v.Clone().Set(0, 16) v3 := v.Clone().Set(0, 16)
that.Equal(3, v3.Len()) that.Equal(3, len(v3))
that.Equal([]int{16, 2, 3}, v3.Slice()) that.EqualValues([]int{16, 2, 3}, v3)
that.Panics(func() { that.Panics(func() {
v.Set(-1000, 1) v.Set(-1000, 1)
@ -117,20 +113,20 @@ func TestVector(t *testing.T) {
v := coll.From([]int{0, 1, 2, 3, 4, 5, 6}) v := coll.From([]int{0, 1, 2, 3, 4, 5, 6})
v1 := v.Clone().Sub(2, 4) v1 := v.Clone().Sub(2, 4)
that.Equal(2, v1.Len()) that.Equal(2, len(v1))
that.Equal([]int{2, 3}, v1.Slice()) that.EqualValues([]int{2, 3}, v1)
v2 := v.Clone().Sub(2, 5) v2 := v.Clone().Sub(2, 5)
that.Equal(3, v2.Len()) that.Equal(3, len(v2))
that.Equal([]int{2, 3, 4}, v2.Slice()) that.EqualValues([]int{2, 3, 4}, v2)
v3 := v.Clone().Sub(5, -1) v3 := v.Clone().Sub(5, -1)
that.Equal(2, v3.Len()) that.Equal(2, len(v3))
that.Equal([]int{5, 6}, v3.Slice()) that.EqualValues([]int{5, 6}, v3)
v4 := v.Clone().Sub(-1, 2) v4 := v.Clone().Sub(-1, 2)
that.Equal(2, v4.Len()) that.Equal(2, len(v4))
that.Equal([]int{0, 1}, v4.Slice()) that.EqualValues([]int{0, 1}, v4)
that.Panics(func() { that.Panics(func() {
v.Sub(0, 1000) v.Sub(0, 1000)
@ -142,6 +138,11 @@ func TestVector(t *testing.T) {
v.Sub(2, 1) v.Sub(2, 1)
}) })
}, },
"filter": func(that *require.Assertions) {
v := coll.From([]int{1, 2, 3, 4, 5, 6})
v = v.Filter(func(i int) bool { return i%2 == 0 })
that.Len(v, 3)
},
} }
for name, test := range tests { for name, test := range tests {