Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions benchmark/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ func BenchmarkNew(b *testing.B) {
}
}

func BenchmarkNew2(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
gollection.New2([]int{})
}
}

func BenchmarkNewAndResult(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
Expand All @@ -32,15 +39,15 @@ func BenchmarkNewAndResultAs(b *testing.B) {
func BenchmarkNewStream(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
gollection.NewStream([]int{}).Result()
gollection.NewStream([]int{})
}
}

func BenchmarkDistinct(b *testing.B) {
arr := []int{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}
b.ResetTimer()
for i := 0; i < b.N; i++ {
gollection.New(arr).Distinct().Result()
gollection.New2(arr).Distinct()
}
}

Expand Down
19 changes: 10 additions & 9 deletions distinct.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,24 @@ func (g *gollection) DistinctBy(f /*func(v <T1>) <T2>*/ interface{}) *gollection
}

func (g *gollection) distinct() *gollection {
sv, err := g.validateSlice("Distinct")
if err != nil {
return &gollection{err: err}
defer g.slice2.free()
if g.err != nil {
return &gollection{err: g.err}
}

ret := reflect.MakeSlice(sv.Type(), 0, sv.Len())
m := make(map[interface{}]bool)
ret := newInterfaceSlice()

for i := 0; i < sv.Len(); i++ {
v := sv.Index(i)
if processDistinct(v.Interface(), m) {
ret = reflect.Append(ret, v)
for i := 0; i < len(g.slice2.slice); i++ {
v := g.slice2.slice[i]
if processDistinct(v, m) {
ret.slice = append(ret.slice, v)
}
}

return &gollection{
slice: ret.Interface(),
slice2: ret,
meta: g.meta,
}
}

Expand Down
24 changes: 12 additions & 12 deletions distinct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@ func TestDistinct(t *testing.T) {
arr := []int{1, 2, 3, 1, 2, 3}
expect := []int{1, 2, 3}

res, err := gollection.New(arr).Distinct().Result()
res, err := gollection.New2(arr).Distinct().Result()
assert.NoError(err)
assert.Equal(expect, res)
}

func TestDistinct_NotSlice(t *testing.T) {
assert := assert.New(t)
_, err := gollection.New("not slice value").Distinct().Result()
_, err := gollection.New2("not slice value").Distinct().Result()
assert.Error(err)
}

func TestDistinct_HavingError(t *testing.T) {
assert := assert.New(t)
_, err := gollection.New("not slice value").Distinct().Distinct().Result()
_, err := gollection.New2("not slice value").Distinct().Distinct().Result()
assert.Error(err)

res := []int{}
err = gollection.New("not slice value").Distinct().Distinct().ResultAs(&res)
err = gollection.New2("not slice value").Distinct().Distinct().ResultAs(&res)
assert.Error(err)
}

Expand Down Expand Up @@ -61,11 +61,11 @@ func TestDistinctBy_HavingError(t *testing.T) {
assert := assert.New(t)
_, err := gollection.New("not slice value").
DistinctBy(func(v interface{}) interface{} {
return v
}).
return v
}).
DistinctBy(func(v interface{}) interface{} {
return v
}).
return v
}).
Result()
assert.Error(err)
}
Expand Down Expand Up @@ -120,11 +120,11 @@ func TestDistinctBy_Stream_HavingError(t *testing.T) {
assert := assert.New(t)
_, err := gollection.NewStream("not slice value").
DistinctBy(func(v interface{}) interface{} {
return v
}).
return v
}).
DistinctBy(func(v interface{}) interface{} {
return v
}).
return v
}).
Result()
assert.Error(err)
}
2 changes: 1 addition & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
func Example_distinct() {
arr := []int{1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10}

res, err := gollection.New(arr).Distinct().Result()
res, err := gollection.New2(arr).Distinct().Result()
fmt.Println(res, err)
// Output: [1 2 3 4 5 6 7 8 9 10] <nil>
}
Expand Down
2 changes: 1 addition & 1 deletion examples/distinct/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
func main() {
arr := []int{1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10}

res, _ := gollection.New(arr).Distinct().Result()
res, _ := gollection.New2(arr).Distinct().Result()
fmt.Println("origin : ", arr)
fmt.Println("ret : ", res) // {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

Expand Down
69 changes: 65 additions & 4 deletions gollection.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,44 @@ import (
"sync"
)

type interfaceSlice struct {
slice []interface{}
}

func (s *interfaceSlice) truncate() {
s.slice = s.slice[:0]
}

func (s *interfaceSlice) free() {
slicePool.Put(s)
}

func newInterfaceSlice() *interfaceSlice {
s := slicePool.Get().(*interfaceSlice)
s.truncate()
return s
}

var slicePool = sync.Pool{
New: func() interface{} {
return &interfaceSlice{
slice: make([]interface{}, 0, 10),
}
},
}

type gollection struct {
slice interface{}
val interface{}
ch chan interface{}
err error
slice interface{}
val interface{}
ch chan interface{}
err error
slice2 *interfaceSlice
meta meta
}

type meta struct {
Len int
Type reflect.Type
}

// New returns a gollection instance which can method chain *sequentially* specified by some type of slice.
Expand All @@ -23,11 +56,39 @@ func New(slice interface{}) *gollection {
}
}

func New2(slice interface{}) *gollection {
sv := reflect.ValueOf(slice)
if sv.Kind() != reflect.Slice {
return &gollection{err: fmt.Errorf("gollection.%s called with non-slice value of type %T", slice)}
}
s := newInterfaceSlice()

for i := 0; i < sv.Len(); i++ {
v := sv.Index(i).Interface()
s.slice = append(s.slice, v)
}
return &gollection{
slice: slice,
slice2: s,
meta: meta{
Len: sv.Len(),
Type: sv.Type(),
},
}
}

// Result return a collection processed value and error.
func (g *gollection) Result() (interface{}, error) {
if g.ch != nil {
return g.resultStream()
}
if g.slice2 != nil {
ret := reflect.MakeSlice(g.meta.Type, 0, g.meta.Len)
for _, v := range g.slice2.slice {
ret = reflect.Append(ret, reflect.ValueOf(v))
}
return ret.Interface(), g.err
}
return g.result()
}

Expand Down