From 57deaa3670acfe3e1b063747e23a49a19932c00e Mon Sep 17 00:00:00 2001 From: emilis Date: Tue, 2 Aug 2022 15:49:10 +0100 Subject: [PATCH] Optimization for vector --- pkg/coll/Iterator.go | 19 -------- pkg/coll/coll.go | 45 +++++++++---------- pkg/coll/vector.go | 99 +++++++++++++++-------------------------- pkg/coll/vector_test.go | 76 +++++++++++++++++-------------- 4 files changed, 99 insertions(+), 140 deletions(-) delete mode 100644 pkg/coll/Iterator.go diff --git a/pkg/coll/Iterator.go b/pkg/coll/Iterator.go deleted file mode 100644 index e6a5c02..0000000 --- a/pkg/coll/Iterator.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/coll/coll.go b/pkg/coll/coll.go index 4cb1f5d..7b95c46 100644 --- a/pkg/coll/coll.go +++ b/pkg/coll/coll.go @@ -2,43 +2,41 @@ 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]) + out := make([]V, len(c)) + for index := 0; index < len(c); index++ { + out[index] = f(c[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) { + out := WithCap[T](len(v)) + for _, t := range v { if f(t) { - out.Push(t) + out = out.Push(t) } - }) + } return out } func Take[T any](v Vector[T], howMany int) Vector[T] { - if v.length == 0 { + if len(v) == 0 { return New[T]() } - if v.length < howMany { - howMany = v.length + if len(v) < howMany { + 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 { - var found bool - v.Iterate().ForBreak(func(_ int, t T, breaker func()) { + for _, t := range v { if f(t) { - found = true - breaker() + return true } - }) - return found + } + return false } type numeric interface { @@ -47,26 +45,25 @@ type numeric interface { func Min[T numeric](v Vector[T]) T { var min T - if v.length == 0 { + if len(v) == 0 { return min } - min = v.array[0] - v.Iterate().ForEach(func(_ int, t T) { + min = v[0] + for _, t := range v { 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) { + for _, t := range v { if max < t { max = t } - }) + } return max } diff --git a/pkg/coll/vector.go b/pkg/coll/vector.go index 4dcc8ff..74123df 100644 --- a/pkg/coll/vector.go +++ b/pkg/coll/vector.go @@ -6,143 +6,116 @@ const ( DefaultSize = 4 ) -type Vector[T any] struct { - array []T - length int - capacity int -} +type Vector[T any] []T 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, - } + return make(Vector[T], 0, capacity) } func From[T any](v []T) Vector[T] { - return Vector[T]{ - array: v, - length: len(v), - capacity: len(v), - } + return Vector[T](v) } func (v Vector[T]) Push(t T) Vector[T] { - if v.length == v.capacity { + if len(v) == cap(v) { v = v.upsize() } - v.array[v.length] = t - v.length++ + v = v[:len(v)+1] + v[len(v)-1] = t return v } 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)) } + startLen := len(v) + v = v[:len(v)+len(t)] var tIndex int - for ; v.length < v.capacity; v.length++ { - v.array[v.length] = t[tIndex] + for index := startLen; index < cap(v); index++ { + v[index] = 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]...)) + return From(append(v[:index], v[index+1:]...)) } // 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 + v[index] = v[len(v)-1] + return v[:len(v)-1] } 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] { - 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] + resized := make([]T, len(v), cap(v)+extraSize) + copy(resized, v) + return resized } func (v Vector[T]) panicIndex(index int) { min := -1 - if v.length != 0 { + if len(v) != 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 // it's out of range func (v Vector[T]) GetSoft(index int) T { var result T - if index < 0 || index >= v.length { + if index < 0 || index >= len(v) { return result } - return v.array[index] + return v[index] } func (v Vector[T]) Get(index int) T { - if index < 0 || index >= v.length { + if index < 0 || index >= len(v) { v.panicIndex(index) } - return v.array[index] + return v[index] } 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.array[index] = value + v[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 + t := v[len(v)-1] + return t, v[:len(v)-1] } func (v Vector[T]) Sub(start, end int) Vector[T] { - if start >= v.length { + if start >= len(v) { v.panicIndex(start) } - if end >= v.length { + if end >= len(v) { v.panicIndex(end) } if start < 0 { - return From(v.array[:end]) + return From(v[:end]) } 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] { @@ -158,8 +131,8 @@ func (v Vector[T]) Take(howMany int) Vector[T] { } func (v Vector[T]) Clone() Vector[T] { - clone := make([]T, len(v.array)) - copy(clone, v.array) - v.array = clone + clone := make([]T, len(v)) + copy(clone, v) + v = clone return v } diff --git a/pkg/coll/vector_test.go b/pkg/coll/vector_test.go index cbae3c0..b5c46f8 100644 --- a/pkg/coll/vector_test.go +++ b/pkg/coll/vector_test.go @@ -12,37 +12,33 @@ func TestVector(t *testing.T) { "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()) + that.Len(v, 6) + that.EqualValues([]int{0, 1, 2, 3, 4, 5}, v) }, "len": func(that *require.Assertions) { v := coll.From([]int{1, 2, 3}) - that.Equal(3, v.Len()) - that.Len(v.Slice(), v.Len()) + that.Len(v, len(v)) }, "from": func(that *require.Assertions) { v := coll.From([]int{1, 2, 3}) - that.Equal(3, v.Len()) - that.Len(v.Slice(), 3) + that.Len(v, 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()) + that.EqualValues([]int{1, 2}, v) }, "withcap": func(that *require.Assertions) { v := coll.WithCap[int](3) - that.Zero(v.Len()) - that.Len(v.Slice(), 0) + that.Zero(len(v)) + that.Len(v, 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.Equal(2, len(r1)) + that.EqualValues([]int{0, 2}, r1) that.Panics(func() { v.Remove(-1) }) @@ -53,8 +49,8 @@ func TestVector(t *testing.T) { "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() + that.Equal(2, len(v)) + vSlice := v if vSlice[0] == 0 { that.Equal(2, vSlice[1]) } else { @@ -64,8 +60,8 @@ func TestVector(t *testing.T) { }, "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()) + that.Equal(6, len(v)) + that.EqualValues([]int{1, 2, 3, 4, 5, 6}, v) }, "getsoft": func(that *require.Assertions) { v := coll.From([]int{1, 2, 3}) @@ -87,24 +83,24 @@ func TestVector(t *testing.T) { 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()) + that.Equal(3, len(v1)) + that.EqualValues([]int{1, 1, 3}, v1) + that.EqualValues([]int{1, 2, 3}, v) }, "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()) + that.Equal(3, len(v1)) + that.EqualValues([]int{1, 1, 3}, v1) v2 := v.Clone().Set(2, 1) - that.Equal(3, v2.Len()) - that.Equal([]int{1, 2, 1}, v2.Slice()) + that.Equal(3, len(v2)) + that.EqualValues([]int{1, 2, 1}, v2) v3 := v.Clone().Set(0, 16) - that.Equal(3, v3.Len()) - that.Equal([]int{16, 2, 3}, v3.Slice()) + that.Equal(3, len(v3)) + that.EqualValues([]int{16, 2, 3}, v3) that.Panics(func() { v.Set(-1000, 1) @@ -117,20 +113,20 @@ func TestVector(t *testing.T) { 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()) + that.Equal(2, len(v1)) + that.EqualValues([]int{2, 3}, v1) v2 := v.Clone().Sub(2, 5) - that.Equal(3, v2.Len()) - that.Equal([]int{2, 3, 4}, v2.Slice()) + that.Equal(3, len(v2)) + that.EqualValues([]int{2, 3, 4}, v2) v3 := v.Clone().Sub(5, -1) - that.Equal(2, v3.Len()) - that.Equal([]int{5, 6}, v3.Slice()) + that.Equal(2, len(v3)) + that.EqualValues([]int{5, 6}, v3) v4 := v.Clone().Sub(-1, 2) - that.Equal(2, v4.Len()) - that.Equal([]int{0, 1}, v4.Slice()) + that.Equal(2, len(v4)) + that.EqualValues([]int{0, 1}, v4) that.Panics(func() { v.Sub(0, 1000) @@ -142,6 +138,18 @@ func TestVector(t *testing.T) { 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) + }, + "any": func(that *require.Assertions) { + that.True(coll.From([]int{1, 2, 3, 4, 5, 6}).Any(func(i int) bool { return i == 3 })) + that.False(coll.From([]int{1, 2, 3, 4, 5, 6}).Any(func(i int) bool { return i == 666 })) + }, + "take": func(that *require.Assertions) { + that.EqualValues([]int{1, 2, 3}, coll.From([]int{1, 2, 3, 4, 5, 6}).Take(3)) + }, } for name, test := range tests {