github.com/kazu/loncha@v0.6.3/loncha_test.go (about) 1 package loncha 2 3 import ( 4 "fmt" 5 "math" 6 "math/rand" 7 "sort" 8 "testing" 9 10 "github.com/thoas/go-funk" 11 12 "github.com/stretchr/testify/assert" 13 ) 14 15 type Element struct { 16 ID int 17 Name string 18 } 19 20 const ( 21 CREATE_SLICE_MAX int = 10000 22 ) 23 24 func MakeSliceSample() (slice []Element) { 25 slice = make([]Element, 0, CREATE_SLICE_MAX*2) 26 27 for i := 0; i < CREATE_SLICE_MAX; i++ { 28 slice = append(slice, 29 Element{ 30 ID: int(math.Abs(float64(rand.Intn(CREATE_SLICE_MAX)))), 31 Name: fmt.Sprintf("aaa%d", i), 32 }) 33 } 34 return 35 } 36 37 type Elements []Element 38 type PtrElements []*Element 39 40 type EqInt map[string]int 41 type EqString map[string]string 42 43 type Eq map[string]interface{} 44 45 func (eq EqInt) Func(slice Elements) (funcs []CondFunc) { 46 funcs = make([]CondFunc, 0, len(eq)) 47 for key, _ := range eq { 48 switch key { 49 case "ID": 50 fn := func(i int) bool { 51 return slice[i].ID == eq[key] 52 } 53 funcs = append(funcs, fn) 54 } 55 } 56 return 57 } 58 59 func (eq EqString) Func(slice Elements) (funcs []CondFunc) { 60 funcs = make([]CondFunc, 0, len(eq)) 61 for key, _ := range eq { 62 switch key { 63 case "Name": 64 fn := func(i int) bool { 65 return slice[i].Name == eq[key] 66 } 67 funcs = append(funcs, fn) 68 } 69 } 70 return 71 } 72 73 func (slice Elements) Where(q Eq) Elements { 74 eqInt := make(EqInt) 75 eqString := make(EqString) 76 funcs := make([]CondFunc, 0, len(q)) 77 for key, value := range q { 78 switch key { 79 case "ID": 80 eqInt[key] = value.(int) 81 funcs = append(funcs, eqInt.Func(slice)[0]) 82 case "Name": 83 eqString[key] = value.(string) 84 funcs = append(funcs, eqString.Func(slice)[0]) 85 } 86 } 87 oslice := &slice 88 OldFilter(oslice, funcs...) 89 return *oslice 90 } 91 92 func MakePtrSliceSample() (slice []*Element) { 93 slice = make([]*Element, 0, CREATE_SLICE_MAX*2) 94 95 for i := 0; i < CREATE_SLICE_MAX; i++ { 96 slice = append(slice, 97 &Element{ 98 ID: int(math.Abs(float64(rand.Intn(CREATE_SLICE_MAX)))), 99 Name: fmt.Sprintf("aaa%d", i), 100 }) 101 } 102 return 103 } 104 105 func TestWhere(t *testing.T) { 106 slice := Elements(MakeSliceSample()) 107 108 nSlice := slice.Where(Eq{"ID": 555}) 109 110 assert.True(t, nSlice[0].ID == 555, nSlice) 111 assert.True(t, len(nSlice) < 100, len(nSlice)) 112 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 113 } 114 115 func TestFind(t *testing.T) { 116 nSlice := Elements(MakeSliceSample()) 117 id := nSlice[50].ID 118 data, err := Find(&nSlice, func(i int) bool { 119 return nSlice[i].ID == id 120 }) 121 122 assert.NoError(t, err) 123 elm := data.(Element) 124 assert.True(t, elm.ID == id, elm) 125 126 nSlice = MakeSliceSample() 127 id = nSlice[50].ID 128 data, err = Find(nSlice, func(i int) bool { 129 return nSlice[i].ID == id 130 }) 131 132 assert.NoError(t, err) 133 elm = data.(Element) 134 assert.True(t, elm.ID == id, elm) 135 136 } 137 138 func TestLastIndexOf(t *testing.T) { 139 nSlice := Elements(MakeSliceSample()) 140 id := nSlice[50].ID 141 i, err := LastIndexOf(nSlice, func(i int) bool { 142 return nSlice[i].ID == id 143 }) 144 145 assert.NoError(t, err) 146 assert.True(t, nSlice[i].ID == id, nSlice[i]) 147 148 nSlice = MakeSliceSample() 149 id = nSlice[50].ID 150 i, err = LastIndexOf(nSlice, func(i int) bool { 151 return nSlice[i].ID == id 152 }) 153 154 assert.NoError(t, err) 155 assert.True(t, nSlice[i].ID == id, nSlice[i]) 156 157 } 158 159 func TestFilter(t *testing.T) { 160 nSlice := Elements(MakeSliceSample()) 161 id := nSlice[50].ID 162 OldFilter(&nSlice, func(i int) bool { 163 return nSlice[i].ID == id 164 }) 165 166 assert.True(t, nSlice[0].ID == id, nSlice) 167 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 168 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 169 } 170 171 func TestFilter2(t *testing.T) { 172 nSlice := Elements(MakeSliceSample()) 173 id := nSlice[50].ID 174 var err error 175 nSlice, err = Filter(nSlice, nil, 176 Cond2[FilterOpt[Element]](func(obj *Element) bool { 177 return obj.ID == id 178 })) 179 180 assert.NoError(t, err) 181 assert.True(t, nSlice[0].ID == id, nSlice) 182 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 183 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 184 185 nSlice = Elements(MakeSliceSample()) 186 id = nSlice[50].ID 187 nSlice, err = Filter(nSlice, nil, 188 FilterVersion[FilterOpt[Element]](4), 189 Cond2[FilterOpt[Element]](func(obj *Element) bool { 190 return obj.ID == id || obj.ID == id+100 191 })) 192 193 assert.NoError(t, err) 194 assert.True(t, nSlice[0].ID == id, nSlice) 195 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 196 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 197 198 nSlice = Elements(MakeSliceSample()) 199 id = nSlice[50].ID 200 expect := nSlice[50] 201 nSlice, err = Filter(nSlice, nil, 202 FilterVersion[FilterOpt[Element]](3), 203 Equal[FilterOpt[Element]](expect)) 204 205 assert.NoError(t, err) 206 assert.True(t, nSlice[0].ID == id, nSlice) 207 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 208 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 209 210 nSlice = Elements(MakeSliceSample()) 211 id = nSlice[50].ID 212 nSlice, err = Filter(nSlice, 213 func(obj *Element) bool { 214 return obj.ID == id || obj.ID == id+100 215 }) 216 217 assert.NoError(t, err) 218 assert.True(t, nSlice[0].ID == id, nSlice) 219 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 220 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 221 222 nSlice = Elements(MakeSliceSample()) 223 id = nSlice[50].ID 224 nSlice, err = Filter(nSlice, nil, 225 FilterVersion[FilterOpt[Element]](3), 226 Cond2[FilterOpt[Element]](func(obj *Element) bool { 227 return obj.ID == id || obj.ID == id+100 228 })) 229 230 assert.NoError(t, err) 231 assert.True(t, nSlice[0].ID == id, nSlice) 232 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 233 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 234 235 nSlice = Elements(MakeSliceSample()) 236 id = nSlice[50].ID 237 nSlice = Filterable( 238 func(obj *Element) bool { 239 return obj.ID == id || obj.ID == id+100 240 })(nSlice) 241 242 assert.NoError(t, err) 243 assert.True(t, nSlice[0].ID == id, nSlice) 244 assert.True(t, len(nSlice) < CREATE_SLICE_MAX, len(nSlice)) 245 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 246 247 } 248 249 func TestDelete(t *testing.T) { 250 251 nSlice := Elements(MakeSliceSample()) 252 253 beforeSlice := make(Elements, len(nSlice)) 254 copy(beforeSlice[:len(nSlice)], nSlice) 255 afterSlice := make(Elements, len(nSlice)) 256 257 size := len(nSlice) 258 id := nSlice[100].ID 259 Delete(&nSlice, func(i int) bool { 260 return nSlice[i].ID == id 261 }) 262 263 assert.True(t, nSlice[0].ID != 555, nSlice) 264 assert.True(t, len(nSlice) < size, len(nSlice)) 265 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 266 267 afterSlice = afterSlice[:len(nSlice)] 268 copy(afterSlice[:len(nSlice)], nSlice) 269 nSlice = nSlice[:len(beforeSlice)] 270 copy(nSlice[:len(beforeSlice)], beforeSlice) 271 272 size = len(nSlice) 273 deleteCond := func(e *Element) bool { 274 return e.ID == id 275 } 276 nSlice = Deletable(deleteCond)(nSlice) 277 278 assert.Equal(t, afterSlice, nSlice) 279 280 } 281 282 func TestUniq(t *testing.T) { 283 nSlice := Elements(MakeSliceSample()) 284 nSlice = append(nSlice, Element{ID: nSlice[0].ID}) 285 size := len(nSlice) 286 287 fn := func(i int) interface{} { return i } 288 assert.NotEqual(t, fn(1), fn(2)) 289 Uniq(&nSlice, func(i int) interface{} { 290 return nSlice[i].ID 291 }) 292 293 assert.True(t, len(nSlice) < size, len(nSlice)) 294 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 295 } 296 297 func TestUniq2(t *testing.T) { 298 nSlice := Elements(MakeSliceSample()) 299 nSlice = append(nSlice, Element{ID: nSlice[0].ID}) 300 size := len(nSlice) 301 nSlice2 := make([]Element, len(nSlice)) 302 copy(nSlice2, nSlice) 303 304 Uniq2(&nSlice, func(i, j int) bool { 305 return nSlice[i].ID == nSlice[j].ID 306 }) 307 Uniq(&nSlice2, func(i int) interface{} { 308 return nSlice2[i].ID 309 }) 310 311 assert.True(t, len(nSlice) < size, len(nSlice)) 312 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 313 assert.Equal(t, len(nSlice), len(nSlice2)) 314 315 } 316 317 func TestUniqWithSort(t *testing.T) { 318 nSlice := Elements(MakeSliceSample()) 319 nSlice = append(nSlice, Element{ID: nSlice[0].ID}) 320 //size := len(nSlice) 321 nSlice2 := make([]Element, len(nSlice)) 322 copy(nSlice2, nSlice) 323 324 UniqWithSort(&nSlice, func(i, j int) bool { 325 return nSlice[i].ID < nSlice[j].ID 326 }) 327 328 //assert.True(t, len(nSlice) < size, len(nSlice)) 329 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 330 assert.Equal(t, len(nSlice), len(nSlice2)) 331 332 } 333 334 func TestSelect(t *testing.T) { 335 slice := MakeSliceSample() 336 337 ret, err := Select(&slice, func(i int) bool { 338 return slice[i].ID < 50 339 }) 340 nSlice, ok := ret.([]Element) 341 342 assert.NoError(t, err) 343 assert.True(t, nSlice[0].ID < 50, nSlice) 344 assert.True(t, ok) 345 assert.True(t, len(nSlice) < 100, len(nSlice)) 346 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 347 348 slice = MakeSliceSample() 349 350 ret, err = Select(slice, func(i int) bool { 351 return slice[i].ID < 50 352 }) 353 nSlice, ok = ret.([]Element) 354 355 assert.NoError(t, err) 356 assert.True(t, nSlice[0].ID < 50, nSlice) 357 assert.True(t, ok) 358 assert.True(t, len(nSlice) < 100, len(nSlice)) 359 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 360 361 slice = MakeSliceSample() 362 363 islessID := func(id int) func(e *Element) bool { 364 return func(e *Element) bool { 365 return e.ID < id 366 } 367 } 368 369 nSlice = Selectable(islessID(50))(slice) 370 371 assert.NoError(t, err) 372 assert.True(t, nSlice[0].ID < 50, nSlice) 373 assert.True(t, ok) 374 assert.True(t, len(nSlice) < 100, len(nSlice)) 375 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 376 377 } 378 379 func TestPtrSelect(t *testing.T) { 380 slice := MakePtrSliceSample() 381 382 ret, err := Select(&slice, func(i int) bool { 383 return slice[i].ID < 50 384 }) 385 nSlice, ok := ret.([]*Element) 386 387 assert.NoError(t, err) 388 assert.True(t, nSlice[0].ID < 50, nSlice) 389 assert.True(t, ok) 390 assert.True(t, len(nSlice) < 100, len(nSlice)) 391 t.Logf("nSlice.len=%d cap=%d\n", len(nSlice), cap(nSlice)) 392 } 393 394 func TestShuffle(t *testing.T) { 395 slice := MakeSliceSample() 396 a := slice[0] 397 398 err := Shuffle(slice, 2) 399 400 assert.NoError(t, err) 401 assert.NotEqual(t, slice[0].ID, a.ID) 402 } 403 404 func TestReverse(t *testing.T) { 405 slice := []int{1, 4, 2, 6, 4, 6} 406 Reverse(slice) 407 408 assert.Equal(t, []int{6, 4, 6, 2, 4, 1}, slice) 409 } 410 411 func TestIntersect(t *testing.T) { 412 slice1 := []int{1, 4, 2, 6, 4, 6} 413 slice2 := []int{2, 5, 9, 6, 4} 414 415 result := Intersect(slice1, slice2) 416 417 assert.Equal(t, []int{2, 6, 4}, result) 418 } 419 420 func TestIntersectSSorted(t *testing.T) { 421 slice1 := []int{6, 4, 2, 1} 422 slice2 := []int{9, 6, 5, 3, 2} 423 Reverse(slice1) 424 Reverse(slice2) 425 426 result := IntersectSorted(slice1, slice2, func(s []int, i int) int { 427 return s[i] 428 }) 429 430 assert.Equal(t, []int{2, 6}, result) 431 } 432 433 func TestSub(t *testing.T) { 434 slice1 := []int{6, 4, 2, 1} 435 slice2 := []int{9, 6, 5, 3, 2} 436 Reverse(slice1) 437 Reverse(slice2) 438 439 result := Sub(slice1, slice2) 440 441 assert.Equal(t, []int{1, 4}, result) 442 } 443 444 func TestSubSorted(t *testing.T) { 445 slice1 := []int{10, 6, 4, 2} 446 slice2 := []int{9, 6, 5, 3, 2, 1} 447 Reverse(slice1) 448 Reverse(slice2) 449 450 result := SubSorted(slice1, slice2, func(s []int, i int) int { 451 return s[i] 452 }) 453 454 assert.Equal(t, []int{4, 10}, result) 455 } 456 457 type V4sum struct { 458 A int 459 } 460 461 func TestInject(t *testing.T) { 462 slice1 := []int{10, 6, 4, 2} 463 464 sum1 := Inject(slice1, func(sum int, t int) int { 465 return sum + t 466 }) 467 assert.Equal(t, 22, sum1) 468 469 sum := Reduce(slice1, func(sum *int, t int) *int { 470 if sum == nil { 471 sum = new(int) 472 *sum = 0 473 } 474 v := *sum + t 475 return &v 476 }) 477 assert.Equal(t, 22, *sum) 478 479 sum4 := Sum(slice1) 480 481 assert.Equal(t, 22, sum4) 482 483 sum2 := Reducable(func(sum *int, t int) *int { 484 if sum == nil { 485 sum = new(int) 486 *sum = 0 487 } 488 v := *sum + t 489 return &v 490 })(slice1) 491 assert.Equal(t, *sum, *sum2) 492 493 d := int(0) 494 _ = d 495 496 sum3 := Reducable(func(sum *int, t int) *int { 497 if sum == nil { 498 sum = new(int) 499 *sum = 0 500 } 501 v := *sum + t 502 return &v 503 }, Default(&d))(slice1) 504 assert.Equal(t, *sum, *sum3) 505 506 slice2 := []V4sum{ 507 {1}, {2}, 508 } 509 510 sumFns := SumWithFn(slice2, func(a V4sum) int { return a.A }) 511 assert.Equal(t, sumFns, 3) 512 513 } 514 515 func TestGettable(t *testing.T) { 516 517 slice1 := []int{10, 6, 4, 2} 518 519 r := Gettable(func(v *int) bool { return *v == 4 })(slice1) 520 521 assert.Equal(t, 4, r) 522 523 } 524 525 func TestConv(t *testing.T) { 526 slice1 := []int{10, 6, 4, 2} 527 528 int64s := Convertable( 529 func(i int) (int64, bool) { 530 return int64(100 + i), false 531 })(slice1) 532 533 assert.Equal(t, slice1[0]+100, int(int64s[0])) 534 535 } 536 537 func has[T comparable](a T) func(e *T) bool { 538 return func(e *T) bool { 539 return *e == a 540 } 541 542 } 543 544 func TestContain(t *testing.T) { 545 slice1 := []int{10, 6, 4, 2} 546 547 assert.True(t, Containable(has(6))(slice1)) 548 assert.False(t, Containable(has(11))(slice1)) 549 550 assert.True(t, 551 Contain(slice1, func(i int) bool { return slice1[i] == 6 })) 552 553 } 554 555 func TestEvery(t *testing.T) { 556 slice1 := []int{10, 6, 4, 2} 557 558 assert.True(t, 559 Every(func(v *int) bool { 560 *v = +1 561 return true 562 })(slice1...)) 563 564 assert.False(t, 565 Every(func(v *int) bool { 566 *v++ 567 if *v == 5 { 568 return false 569 } 570 return true 571 })(slice1...)) 572 assert.True(t, 573 EveryWithIndex(func(i int, v *int) bool { 574 *v = +1 575 return true 576 })(slice1...)) 577 578 } 579 580 func Sort[T Ordered](s []T) []T { 581 582 sort.Slice(s, func(i, j int) bool { 583 return s[i] <= s[j] 584 }) 585 586 return s 587 } 588 589 func TestMap(t *testing.T) { 590 591 m := map[int]int{ 592 1: 20, 593 4: 30, 594 } 595 assert.Equal(t, []int{1, 4}, Sort(Keys(m))) 596 assert.Nil(t, Keys[int, int](nil)) 597 assert.Equal(t, []int{20, 30}, Sort(Values(m))) 598 assert.Nil(t, Values[int, int](nil)) 599 600 nM := SelectMap(m, func(k, v int) (int, int, bool) { 601 if k+v == 34 { 602 return k, v, true 603 } 604 return k + 10, v + 100, false 605 }) 606 607 assert.Equal(t, 120, nM[11]) 608 609 } 610 611 func TestZipper(t *testing.T) { 612 613 a := []string{"bob", "hoge", "one", "home"} 614 b := []int{0, 1, 2} 615 616 m := Zipper(ToMap[string, int], map[string]int{})(a, b) 617 618 assert.Equal(t, 0, m["bob"]) 619 assert.Equal(t, 2, m["one"]) 620 assert.Equal(t, 0, m["home"]) 621 622 } 623 624 // BenchmarkFilter/loncha.Filter-16 100 89142 ns/op 82119 B/op 4 allocs/op 625 // BenchmarkFilter/loncha.Filter_pointer-16 100 201 ns/op 0 B/op 0 allocs/op 626 // BenchmarkFilter/hand_Filter_pointer-16 100 24432 ns/op 81921 B/op 1 allocs/op 627 // BenchmarkFilter/go-funk.Filter-16 100 2370492 ns/op 640135 B/op 20004 allocs/op 628 // BenchmarkFilter/go-funk.Filter_pointer-16 100 1048 ns/op 64 B/op 2 allocs/op 629 func BenchmarkFilter(b *testing.B) { 630 631 orig := MakeSliceSample() 632 633 b.ResetTimer() 634 b.Run("loncha.Filter ", func(b *testing.B) { 635 for i := 0; i < b.N; i++ { 636 b.StopTimer() 637 objs := make([]Element, len(orig)) 638 copy(objs, orig) 639 b.StartTimer() 640 OldFilter(&objs, func(i int) bool { 641 return objs[i].ID == 555 642 }) 643 } 644 }) 645 646 b.ResetTimer() 647 b.Run("loncha.oFilter2", func(b *testing.B) { 648 for i := 0; i < b.N; i++ { 649 b.StopTimer() 650 objs := make([]Element, len(orig)) 651 copy(objs, orig) 652 b.StartTimer() 653 Filter(objs, 654 nil, 655 Cond[FilterOpt[Element]](func(i int) bool { 656 return objs[i].ID == 555 657 })) 658 } 659 }) 660 661 b.ResetTimer() 662 b.Run("loncha.Filter2 ", func(b *testing.B) { 663 for i := 0; i < b.N; i++ { 664 b.StopTimer() 665 objs := make([]Element, len(orig)) 666 copy(objs, orig) 667 b.StartTimer() 668 objs, _ = Filter(objs, nil, 669 Cond2[FilterOpt[Element]](func(obj *Element) bool { 670 return obj.ID == 555 671 })) 672 } 673 }) 674 b.ResetTimer() 675 b.Run("loncha.Filter2.3 ", func(b *testing.B) { 676 for i := 0; i < b.N; i++ { 677 b.StopTimer() 678 objs := make([]Element, len(orig)) 679 copy(objs, orig) 680 b.StartTimer() 681 objs, _ = Filter(objs, nil, 682 FilterVersion[FilterOpt[Element]](3), 683 Cond2[FilterOpt[Element]](func(obj *Element) bool { 684 return obj.ID == 555 685 })) 686 } 687 }) 688 b.ResetTimer() 689 b.Run("loncha.Filter2.4 ", func(b *testing.B) { 690 for i := 0; i < b.N; i++ { 691 b.StopTimer() 692 objs := make([]Element, len(orig)) 693 copy(objs, orig) 694 b.StartTimer() 695 objs, _ = Filter(objs, nil, 696 FilterVersion[FilterOpt[Element]](4), 697 Cond2[FilterOpt[Element]](func(obj *Element) bool { 698 return obj.ID == 555 699 })) 700 } 701 }) 702 703 b.ResetTimer() 704 b.Run("loncha.Filterable ", func(b *testing.B) { 705 for i := 0; i < b.N; i++ { 706 b.StopTimer() 707 objs := make([]Element, len(orig)) 708 copy(objs, orig) 709 b.StartTimer() 710 objs = Filterable(func(obj *Element) bool { 711 return obj.ID == 555 712 })(objs) 713 714 } 715 }) 716 717 pObjs := MakePtrSliceSample() 718 b.ResetTimer() 719 b.Run("loncha.Filter pointer", func(b *testing.B) { 720 for i := 0; i < b.N; i++ { 721 b.StopTimer() 722 objs := make([]*Element, 0, len(pObjs)) 723 copy(objs, pObjs) 724 b.StartTimer() 725 OldFilter(&objs, func(i int) bool { 726 return objs[i].ID == 555 727 }) 728 } 729 }) 730 731 b.ResetTimer() 732 b.Run("hand Filter pointer", func(b *testing.B) { 733 for i := 0; i < b.N; i++ { 734 b.StopTimer() 735 objs := make([]*Element, len(orig)) 736 copy(objs, pObjs) 737 b.StartTimer() 738 result := make([]*Element, 0, len(orig)) 739 for idx, _ := range objs { 740 if objs[idx].ID == 555 { 741 result = append(result, objs[idx]) 742 } 743 } 744 } 745 }) 746 747 b.ResetTimer() 748 b.Run("go-funk.Filter", func(b *testing.B) { 749 for i := 0; i < b.N; i++ { 750 b.StopTimer() 751 objs := make([]Element, len(orig)) 752 copy(objs, orig) 753 b.StartTimer() 754 funk.Filter(objs, func(e Element) bool { 755 return e.ID == 555 756 }) 757 } 758 }) 759 760 b.ResetTimer() 761 b.Run("go-funk.Filter pointer", func(b *testing.B) { 762 for i := 0; i < b.N; i++ { 763 b.StopTimer() 764 objs := make([]*Element, 0, len(pObjs)) 765 copy(objs, pObjs) 766 b.StartTimer() 767 funk.Filter(objs, func(e *Element) bool { 768 return e.ID == 555 769 }) 770 } 771 }) 772 } 773 774 // BenchmarkUniq/loncha.Uniq-16 1000 997543 ns/op 548480 B/op 16324 allocs/op 775 // BenchmarkUniq/loncha.UniqWithSort-16 1000 2237924 ns/op 256 B/op 7 allocs/op 776 // BenchmarkUniq/loncha.UniqWithSort(sort)-16 1000 260283 ns/op 144 B/op 4 allocs/op 777 // BenchmarkUniq/hand_Uniq-16 1000 427765 ns/op 442642 B/op 8 allocs/op 778 // BenchmarkUniq/hand_Uniq_iface-16 1000 808895 ns/op 632225 B/op 6322 allocs/op 779 // BenchmarkUniq/go-funk.Uniq-16 1000 1708396 ns/op 655968 B/op 10004 allocs/op 780 func BenchmarkUniq(b *testing.B) { 781 782 orig := MakeSliceSample() 783 784 b.ResetTimer() 785 b.Run("loncha.UniqWithSort(before sort)", func(b *testing.B) { 786 for i := 0; i < b.N; i++ { 787 b.StopTimer() 788 objs := make([]Element, len(orig)) 789 copy(objs, orig) 790 sort.Slice(objs, func(i, j int) bool { 791 return objs[i].ID < objs[j].ID 792 }) 793 b.StartTimer() 794 UniqWithSort(&objs, func(i, j int) bool { 795 return objs[i].ID < objs[j].ID 796 }) 797 } 798 }) 799 800 b.ResetTimer() 801 b.Run("loncha.UniqWithSort", func(b *testing.B) { 802 for i := 0; i < b.N; i++ { 803 b.StopTimer() 804 objs := make([]Element, len(orig)) 805 copy(objs, orig) 806 b.StartTimer() 807 UniqWithSort(&objs, func(i, j int) bool { 808 return objs[i].ID < objs[j].ID 809 }) 810 } 811 }) 812 813 b.ResetTimer() 814 b.Run("loncha.Uniq", func(b *testing.B) { 815 for i := 0; i < b.N; i++ { 816 b.StopTimer() 817 objs := make([]Element, len(orig)) 818 copy(objs, orig) 819 b.StartTimer() 820 Uniq(&objs, func(i int) interface{} { 821 return objs[i].ID 822 }) 823 } 824 }) 825 826 b.Run("loncha.Uniq2", func(b *testing.B) { 827 for i := 0; i < b.N; i++ { 828 b.StopTimer() 829 objs := make([]Element, len(orig)) 830 copy(objs, orig) 831 b.StartTimer() 832 Uniq2(&objs, func(i, j int) bool { 833 return objs[i].ID == objs[j].ID 834 }) 835 } 836 }) 837 838 b.ResetTimer() 839 b.Run("hand Uniq", func(b *testing.B) { 840 for i := 0; i < b.N; i++ { 841 b.StopTimer() 842 objs := make([]Element, len(orig)) 843 copy(objs, orig) 844 b.StartTimer() 845 exists := make(map[int]bool, len(objs)) 846 result := make([]Element, 0, len(orig)) 847 for idx, _ := range objs { 848 if !exists[objs[idx].ID] { 849 exists[objs[idx].ID] = true 850 result = append(result, orig[idx]) 851 } 852 } 853 } 854 }) 855 856 b.ResetTimer() 857 b.Run("hand Uniq iface", func(b *testing.B) { 858 for i := 0; i < b.N; i++ { 859 b.StopTimer() 860 objs := make([]Element, len(orig)) 861 copy(objs, orig) 862 b.StartTimer() 863 exists := make(map[interface{}]bool, len(objs)) 864 result := make([]Element, 0, len(orig)) 865 for idx, _ := range objs { 866 if !exists[objs[idx].ID] { 867 exists[objs[idx].ID] = true 868 result = append(result, orig[idx]) 869 } 870 } 871 } 872 }) 873 874 b.ResetTimer() 875 b.Run("go-funk.Uniq", func(b *testing.B) { 876 for i := 0; i < b.N; i++ { 877 b.StopTimer() 878 objs := make([]Element, len(orig)) 879 copy(objs, orig) 880 b.StartTimer() 881 funk.Uniq(objs) 882 } 883 }) 884 } 885 886 func BenchmarkSelect(b *testing.B) { 887 orig := MakeSliceSample() 888 889 b.ResetTimer() 890 b.Run("loncha.Select", func(b *testing.B) { 891 for i := 0; i < b.N; i++ { 892 b.StopTimer() 893 objs := make([]Element, len(orig)) 894 copy(objs, orig) 895 b.StartTimer() 896 Select(&objs, func(i int) bool { 897 return objs[i].ID == 555 898 }) 899 } 900 }) 901 902 b.ResetTimer() 903 b.Run("loncha.FilterAndCopy", func(b *testing.B) { 904 for i := 0; i < b.N; i++ { 905 b.StopTimer() 906 objs := make([]Element, len(orig)) 907 copy(objs, orig) 908 b.StartTimer() 909 OldFilter(&objs, func(i int) bool { 910 return objs[i].ID == 555 911 }) 912 newObjs := make([]Element, len(orig)) 913 copy(newObjs, objs) 914 } 915 }) 916 917 b.ResetTimer() 918 b.Run("hand Select", func(b *testing.B) { 919 for i := 0; i < b.N; i++ { 920 b.StopTimer() 921 objs := make([]Element, len(orig)) 922 copy(objs, orig) 923 b.StartTimer() 924 result := make([]Element, len(orig)) 925 for idx, _ := range objs { 926 if objs[idx].ID == 555 { 927 result = append(result, objs[idx]) 928 } 929 } 930 } 931 }) 932 933 } 934 935 type TestInterface interface { 936 Inc() int 937 Name() string 938 } 939 940 type TestObject struct { 941 Cnt int 942 name string 943 } 944 945 func (o TestObject) Inc() int { 946 o.Cnt++ 947 return o.Cnt 948 } 949 950 func (o TestObject) Name() string { 951 return o.name 952 } 953 954 func BenchmarkCall(b *testing.B) { 955 956 b.ResetTimer() 957 b.Run("struct call", func(b *testing.B) { 958 for i := 0; i < b.N; i++ { 959 b.StopTimer() 960 object := TestObject{Cnt: 0, name: "Test"} 961 b.StartTimer() 962 for j := 0; j < 100000; j++ { 963 object.Inc() 964 } 965 } 966 }) 967 968 b.ResetTimer() 969 b.Run("interface call", func(b *testing.B) { 970 for i := 0; i < b.N; i++ { 971 b.StopTimer() 972 object := TestInterface(TestObject{Cnt: 0, name: "Test"}) 973 b.StartTimer() 974 for j := 0; j < 100000; j++ { 975 object.Inc() 976 } 977 } 978 }) 979 } 980 981 func (list PtrElements) Len() int { return len(list) } 982 func (list PtrElements) Swap(i, j int) { list[i], list[j] = list[j], list[i] } 983 func (list PtrElements) Less(i, j int) bool { return list[i].ID < list[j].ID } 984 985 // BenchmarkSortPtr/sort.Sort-16 1000 1712284 ns/op 32 B/op 1 allocs/op 986 // BenchmarkSortPtr/sort.Slice-16 2000 1170132 ns/op 64 B/op 2 allocs/op 987 988 func BenchmarkSortPtr(b *testing.B) { 989 orig := MakePtrSliceSample() 990 991 b.ResetTimer() 992 b.Run("sort.Sort", func(b *testing.B) { 993 for i := 0; i < b.N; i++ { 994 b.StopTimer() 995 data := make(PtrElements, len(orig)) 996 copy(data, orig) 997 b.StartTimer() 998 sort.Sort(data) 999 } 1000 }) 1001 1002 b.ResetTimer() 1003 b.Run("sort.Slice", func(b *testing.B) { 1004 for i := 0; i < b.N; i++ { 1005 b.StopTimer() 1006 data := make([]*Element, len(orig)) 1007 copy(data, orig) 1008 b.StartTimer() 1009 sort.Slice(data, func(i, j int) bool { return data[i].ID < data[j].ID }) 1010 } 1011 }) 1012 } 1013 1014 func (list Elements) Len() int { return len(list) } 1015 func (list Elements) Swap(i, j int) { list[i], list[j] = list[j], list[i] } 1016 func (list Elements) Less(i, j int) bool { return list[i].ID < list[j].ID } 1017 1018 // BenchmarkSort/sort.Sort-16 1000 1648947 ns/op 34 B/op 1 allocs/op 1019 // BenchmarkSort/sort.Slice-16 1000 1973036 ns/op 112 B/op 3 allocs/op 1020 1021 func BenchmarkSort(b *testing.B) { 1022 orig := MakeSliceSample() 1023 1024 b.ResetTimer() 1025 b.Run("sort.Sort", func(b *testing.B) { 1026 for i := 0; i < b.N; i++ { 1027 b.StopTimer() 1028 data := make(Elements, len(orig)) 1029 copy(data, orig) 1030 b.StartTimer() 1031 sort.Sort(data) 1032 } 1033 }) 1034 1035 b.ResetTimer() 1036 b.Run("sort.Slice", func(b *testing.B) { 1037 for i := 0; i < b.N; i++ { 1038 b.StopTimer() 1039 data := make([]Element, len(orig)) 1040 copy(data, orig) 1041 b.StartTimer() 1042 sort.Slice(data, func(i, j int) bool { return data[i].ID < data[j].ID }) 1043 } 1044 }) 1045 }