mirror of
https://github.com/samber/lo.git
synced 2026-04-22 15:37:14 +08:00
refactor(benchmarks): reorganize benchark/ directory (#840)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Benchmark Guidelines
|
||||
|
||||
## File Organization
|
||||
|
||||
Benchmark files follow the naming convention:
|
||||
|
||||
```
|
||||
benchmark/{package}_{category}_bench_test.go
|
||||
```
|
||||
|
||||
- **package**: `core`, `it`, `mutable`, `parallel`
|
||||
- **category**: `slice`, `map`, `find`, `intersect`, `math`, `string`, `type_manipulation`, `condition`, `tuples`
|
||||
|
||||
Shared data generators live in `helpers_test.go` (and `it_helpers_test.go` for `go1.23` iter helpers).
|
||||
|
||||
## Performance PRs
|
||||
|
||||
Every performance improvement PR **must** include a `benchstat` comparison in the PR description. Without before/after numbers, the PR will not be merged.
|
||||
|
||||
### How to produce a benchstat report
|
||||
|
||||
1. Check out `master` and run the "before" benchmarks:
|
||||
```bash
|
||||
git stash && git switch master
|
||||
go test ./benchmark/... -bench=BenchmarkXxx -benchmem -count=6 -cpu=1 | tee /tmp/before.txt
|
||||
```
|
||||
|
||||
2. Switch to your branch and run the "after" benchmarks:
|
||||
```bash
|
||||
git switch my-branch && git stash pop
|
||||
go test ./benchmark/... -bench=BenchmarkXxx -benchmem -count=6 -cpu=1 | tee /tmp/after.txt
|
||||
```
|
||||
|
||||
3. Compare with `benchstat`:
|
||||
```bash
|
||||
benchstat /tmp/before.txt /tmp/after.txt
|
||||
```
|
||||
|
||||
4. Paste the full `benchstat` output in the PR description.
|
||||
|
||||
### What to include in the PR description
|
||||
|
||||
- The optimization technique (pre-allocation, direct indexing, value receivers, etc.)
|
||||
- The `benchstat` table showing time/op, allocs/op, and bytes/op deltas
|
||||
- An explanation of **why** the change is faster, not just **what** changed
|
||||
|
||||
### When NOT to submit a performance PR
|
||||
|
||||
- If `benchstat` shows no statistically significant improvement (p >= 0.05)
|
||||
- If the improvement is < 5% and adds code complexity
|
||||
- If the change regresses other benchmarks — always run the full suite, not just the targeted benchmark
|
||||
|
||||
## Adding New Benchmarks
|
||||
|
||||
When adding a new helper function to the library, add a corresponding benchmark in the appropriate `{package}_{category}_bench_test.go` file. Use the standard parametric pattern:
|
||||
|
||||
```go
|
||||
func BenchmarkMyFunc(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
data := genSliceInt(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MyFunc(data, ...)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use shared generators from `helpers_test.go` — do not create local generator functions.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,310 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func BenchmarkIndexOf(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[n-1] // worst case: last element
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.IndexOf(ints, target)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLastIndexOf(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[0]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.LastIndexOf(ints, target)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHasPrefix(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
prefix := ints[:n/10+1]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.HasPrefix(ints, prefix)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHasSuffix(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
suffix := ints[n-n/10-1:]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.HasSuffix(ints, suffix)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFind(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[n-1]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.Find(ints, func(v int) bool { return v == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindIndexOf(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[n-1]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = lo.FindIndexOf(ints, func(v int) bool { return v == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindLastIndexOf(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[0]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _ = lo.FindLastIndexOf(ints, func(v int) bool { return v == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindOrElse(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FindOrElse(ints, -1, func(v int) bool { return v == -999 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindKey(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.FindKey(m, n/2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindKeyBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.FindKeyBy(m, func(_ string, v int) bool { return v == n/2 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindUniques(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FindUniques(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindUniquesBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FindUniquesBy(ints, func(v int) int { return v % 50 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindDuplicates(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FindDuplicates(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFindDuplicatesBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FindDuplicatesBy(ints, func(v int) int { return v % 50 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMin(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Min(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMinIndex(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.MinIndex(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMinBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MinBy(ints, func(a, b int) bool { return a < b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMinIndexBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.MinIndexBy(ints, func(a, b int) bool { return a < b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMax(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Max(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMaxIndex(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.MaxIndex(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMaxBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MaxBy(ints, func(a, b int) bool { return a > b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMaxIndexBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.MaxIndexBy(ints, func(a, b int) bool { return a > b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFirst(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.First(ints)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFirstOrEmpty(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FirstOrEmpty(ints)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLast(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.Last(ints)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLastOrEmpty(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.LastOrEmpty(ints)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNth(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.Nth(ints, 50)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSample(b *testing.B) {
|
||||
ints := genSliceInt(100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Sample(ints)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSamples(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Samples(ints, n/4)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func BenchmarkContains(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[n-1]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Contains(ints, target)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkContainsBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
target := ints[n-1]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ContainsBy(ints, func(v int) bool { return v == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEvery(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
subset := ints[:n/2]
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Every(ints, subset)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEveryBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.EveryBy(ints, func(v int) bool { return v >= 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSome(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
subset := []int{ints[n-1]}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Some(ints, subset)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSomeBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.SomeBy(ints, func(v int) bool { return v < 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNone(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
subset := []int{-1, -2, -3}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.None(ints, subset)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNoneBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.NoneBy(ints, func(v int) bool { return v < 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIntersect(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
a := genSliceInt(n)
|
||||
c := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Intersect(a, c)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIntersectBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
a := genSliceInt(n)
|
||||
c := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.IntersectBy(func(v int) int { return v }, a, c)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnion(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
a := genSliceInt(n)
|
||||
c := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Union(a, c)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithout(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Without(ints, 1, 2, 3, 4, 5)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithoutBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.WithoutBy(ints, func(v int) int { return v % 100 }, 1, 2, 3, 4, 5)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithoutEmpty(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
// sprinkle some zeroes
|
||||
for j := 0; j < n/10; j++ {
|
||||
ints[j*10] = 0
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.WithoutEmpty(ints) //nolint:staticcheck
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithoutNth(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.WithoutNth(ints, 0, n/2, n-1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkElementsMatch(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
a := genSliceInt(n)
|
||||
c := make([]int, n)
|
||||
copy(c, a)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ElementsMatch(a, c)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
lop "github.com/samber/lo/parallel"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
func BenchmarkKeys(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Keys(m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUniqKeys(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m1 := genMap(n)
|
||||
m2 := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.UniqKeys(m1, m2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHasKey(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
key := strconv.Itoa(n / 2)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.HasKey(m, key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValues(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Values(m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUniqValues(b *testing.B) {
|
||||
m := []map[int64]int64{
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
}
|
||||
b.Run("lo.UniqValues", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.UniqValues(m...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkValueOr(b *testing.B) {
|
||||
m := genMap(100)
|
||||
b.Run("hit", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ValueOr(m, "50", -1)
|
||||
}
|
||||
})
|
||||
b.Run("miss", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ValueOr(m, "missing", -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkPickBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.PickBy(m, func(_ string, v int) bool { return v%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPickByKeys(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
keys := make([]string, n/2)
|
||||
for i := range keys {
|
||||
keys[i] = strconv.Itoa(i * 2)
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.PickByKeys(m, keys)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPickByValues(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
vals := make([]int, n/2)
|
||||
for i := range vals {
|
||||
vals[i] = i * 2
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.PickByValues(m, vals)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOmitBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.OmitBy(m, func(_ string, v int) bool { return v%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOmitByKeys(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
keys := make([]string, n/4)
|
||||
for i := range keys {
|
||||
keys[i] = strconv.Itoa(i)
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.OmitByKeys(m, keys)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOmitByValues(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
vals := make([]int, n/4)
|
||||
for i := range vals {
|
||||
vals[i] = i
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.OmitByValues(m, vals)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEntries(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Entries(m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromEntries(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
entries := make([]lo.Entry[string, int], n)
|
||||
for i := 0; i < n; i++ {
|
||||
entries[i] = lo.Entry[string, int]{Key: strconv.Itoa(i), Value: i}
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromEntries(entries)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInvert(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Invert(m)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAssign(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m1 := genMap(n)
|
||||
m2 := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Assign(m1, m2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChunkEntries(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ChunkEntries(m, 5)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapKeys(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MapKeys(m, func(_ int, k string) string { return k + "_x" })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapValues(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MapValues(m, func(v int, _ string) int { return v * 2 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapEntries(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MapEntries(m, func(k string, v int) (string, int) { return k, v * 2 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapToSlice(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MapToSlice(m, func(k string, v int) string { return k + "=" + strconv.Itoa(v) })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFilterMapToSlice(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
m := genMap(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FilterMapToSlice(m, func(k string, v int) (string, bool) { return k, v%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFilterKeys(b *testing.B) {
|
||||
m := mapGenerator(1000)
|
||||
b.Run("lo.FilterKeys", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.FilterKeys(m, func(k, v int64) bool { return k%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFilterValues(b *testing.B) {
|
||||
m := mapGenerator(1000)
|
||||
b.Run("lo.FilterValues", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.FilterValues(m, func(k, v int64) bool { return v%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Comparison benchmarks (lo vs lop vs go-funk vs manual loop)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func BenchmarkMapComparison(b *testing.B) {
|
||||
arr := sliceGenerator(1000000)
|
||||
|
||||
b.Run("lo.Map", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.Map(arr, func(x int64, i int) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("lop.Map", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lop.Map(arr, func(x int64, i int) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("reflect", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = funk.Map(arr, func(x int64) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("for", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
results := make([]string, len(arr))
|
||||
|
||||
for i, item := range arr {
|
||||
result := strconv.FormatInt(item, 10)
|
||||
results[i] = result
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func BenchmarkRange(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Range(n)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRangeFrom(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.RangeFrom(0, n)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRangeWithSteps(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.RangeWithSteps(0, n, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkClamp(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Clamp(15, 0, 10)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Sum(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSumBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.SumBy(ints, func(v int) int { return v })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProduct(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
floats := make([]float64, n)
|
||||
for j := range floats {
|
||||
floats[j] = 1.0001
|
||||
}
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Product(floats)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProductBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ProductBy(ints, func(v int) float64 { return float64(v) * 0.001 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMean(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Mean(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMeanBy(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.MeanBy(ints, func(v int) int { return v })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMode(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Mode(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,13 @@ package benchmark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
var lengths = []int{10, 100, 1000}
|
||||
|
||||
func BenchmarkChunk(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
strs := genSliceString(n)
|
||||
@@ -31,34 +29,6 @@ func BenchmarkChunk(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func genSliceString(n int) []string {
|
||||
res := make([]string, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
res = append(res, strconv.Itoa(rand.Intn(100_000)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func genSliceInt(n int) []int {
|
||||
res := make([]int, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
res = append(res, rand.Intn(100_000))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type heavy = [100]int
|
||||
|
||||
func genSliceHeavy(n int) []heavy {
|
||||
result := make([]heavy, n)
|
||||
for i := range result {
|
||||
for j := range result[i] {
|
||||
result[i][j] = i + j
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func BenchmarkFlatten(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := make([][]int, 0, n)
|
||||
@@ -219,53 +189,6 @@ func BenchmarkReplace(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToSlicePtr(b *testing.B) {
|
||||
preallocated := make([]int, 100000)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ToSlicePtr(preallocated)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromSlicePtr(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceInt(n))
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtr(ptrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceString(n))
|
||||
b.Run(fmt.Sprintf("strings_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtr(ptrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromSlicePtrOr(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceInt(n))
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtrOr(ptrs, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceString(n))
|
||||
b.Run(fmt.Sprintf("strings_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtrOr(ptrs, "default")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReject(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
strs := genSliceString(n)
|
||||
@@ -364,14 +287,6 @@ func BenchmarkRepeatBy(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
type clonableString struct {
|
||||
val string
|
||||
}
|
||||
|
||||
func (c clonableString) Clone() clonableString {
|
||||
return clonableString{c.val}
|
||||
}
|
||||
|
||||
func BenchmarkFill(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
collection := make([]clonableString, n)
|
||||
@@ -869,6 +784,18 @@ func BenchmarkIsSortedBy(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsSortedBySorted(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
data := genSliceInt(n)
|
||||
sort.Ints(data)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
lo.IsSortedBy(data, func(v int) int { return v })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplice(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
@@ -1046,3 +973,43 @@ func BenchmarkDifference(b *testing.B) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromSlicePtr(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceInt(n))
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtr(ptrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceString(n))
|
||||
b.Run(fmt.Sprintf("strings_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtr(ptrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromSlicePtrOr(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceInt(n))
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtrOr(ptrs, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for _, n := range lengths {
|
||||
ptrs := lo.ToSlicePtr(genSliceString(n))
|
||||
b.Run(fmt.Sprintf("strings_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromSlicePtrOr(ptrs, "default")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func BenchmarkRandomString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.RandomString(64, lo.AlphanumericCharset)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSubstring(b *testing.B) {
|
||||
s := lo.RandomString(1000, lo.LettersCharset)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Substring(s, 100, 200)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChunkString(b *testing.B) {
|
||||
s := lo.RandomString(1000, lo.LettersCharset)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ChunkString(s, 10)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRuneLength(b *testing.B) {
|
||||
s := lo.RandomString(1000, lo.LettersCharset)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.RuneLength(s)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPascalCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.PascalCase("some_long_variable_name")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCamelCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.CamelCase("some_long_variable_name")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKebabCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.KebabCase("someLongVariableName")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSnakeCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.SnakeCase("someLongVariableName")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWords(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Words("someLongVariableName")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCapitalize(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Capitalize("hello world")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEllipsis(b *testing.B) {
|
||||
s := lo.RandomString(200, lo.LettersCharset)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.Ellipsis(s, 50)
|
||||
}
|
||||
}
|
||||
@@ -30,3 +30,17 @@ func BenchmarkZip2_Unequal(b *testing.B) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnzip2(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
tuples := make([]lo.Tuple2[int, string], n)
|
||||
for i := range tuples {
|
||||
tuples[i] = lo.Tuple2[int, string]{A: i, B: "x"}
|
||||
}
|
||||
b.Run(fmt.Sprintf("n_%d", n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
lo.Unzip2(tuples)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func BenchmarkToPtr(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ToPtr(42)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromPtr(b *testing.B) {
|
||||
p := lo.ToPtr(42)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromPtr(p)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromPtrOr(b *testing.B) {
|
||||
var p *int
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.FromPtrOr(p, 99)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToSlicePtr(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ToSlicePtr(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToAnySlice(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
ints := genSliceInt(n)
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.ToAnySlice(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromAnySlice(b *testing.B) {
|
||||
for _, n := range lengths {
|
||||
anys := lo.ToAnySlice(genSliceInt(n))
|
||||
b.Run(strconv.Itoa(n), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.FromAnySlice[int](anys)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsEmpty(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.IsEmpty(0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsNotEmpty(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lo.IsNotEmpty(42)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCoalesce(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = lo.Coalesce(0, 0, 0, 42, 99)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var lengths = []int{10, 100, 1000}
|
||||
|
||||
func genSliceString(n int) []string {
|
||||
res := make([]string, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
res = append(res, strconv.Itoa(rand.Intn(100_000)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func genSliceInt(n int) []int {
|
||||
res := make([]int, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
res = append(res, rand.Intn(100_000))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type heavy = [100]int
|
||||
|
||||
func genSliceHeavy(n int) []heavy {
|
||||
result := make([]heavy, n)
|
||||
for i := range result {
|
||||
for j := range result[i] {
|
||||
result[i][j] = i + j
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func genMap(n int) map[string]int {
|
||||
m := make(map[string]int, n)
|
||||
for i := 0; i < n; i++ {
|
||||
m[strconv.Itoa(i)] = i
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type clonableString struct {
|
||||
val string
|
||||
}
|
||||
|
||||
func (c clonableString) Clone() clonableString {
|
||||
return clonableString{c.val}
|
||||
}
|
||||
|
||||
// sliceGenerator creates a random int64 slice (used by comparison benchmarks).
|
||||
func sliceGenerator(size uint) []int64 {
|
||||
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
|
||||
result := make([]int64, size)
|
||||
|
||||
for i := uint(0); i < size; i++ {
|
||||
result[i] = r.Int63()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// mapGenerator creates a random int64 map (used by comparison benchmarks).
|
||||
func mapGenerator(size uint) map[int64]int64 {
|
||||
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
|
||||
result := make(map[int64]int64, size)
|
||||
|
||||
for i := uint(0); i < size; i++ {
|
||||
result[int64(i)] = r.Int63()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
//go:build go1.23
|
||||
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
)
|
||||
|
||||
func BenchmarkItFind(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Find(ints, func(x int) bool { return x == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItContains(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Contains(ints, 42)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItContainsBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.ContainsBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEvery(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Every(ints, 1, 2, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEveryBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.EveryBy(ints, func(x int) bool { return x >= 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSome(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Some(ints, 1, 2, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSomeBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.SomeBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNone(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.None(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNoneBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.NoneBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItIntersect(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
a := genInts(n)
|
||||
c := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Intersect(a, c) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUnion(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
a := genInts(n)
|
||||
c := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Union(a, c) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItWithout(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Without(ints, 1, 2, 3, 4, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItWithoutNth(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.WithoutNth(ints, 0, n/2, n-1) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.IndexOf(ints, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLastIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.LastIndexOf(ints, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItHasPrefix(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.HasPrefix(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItHasSuffix(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.HasSuffix(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _, _ = it.FindIndexOf(ints, func(x int) bool { return x == -1 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindOrElse(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.FindOrElse(ints, -1, func(x int) bool { return x == -1 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindUniques(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FindUniques(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindDuplicates(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FindDuplicates(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMin(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Min(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMax(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Max(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMinBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.MinBy(ints, func(a, b int) bool { return a < b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMaxBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.MaxBy(ints, func(a, b int) bool { return a > b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFirst(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.First(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLast(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Last(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNth(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Nth(ints, n/2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSample(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Sample(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSamples(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Samples(ints, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//go:build go1.23
|
||||
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"math/rand/v2"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var itLengths = []int{10, 100, 1000}
|
||||
|
||||
func genStrings(n int) iter.Seq[string] {
|
||||
return func(yield func(string) bool) {
|
||||
for range n {
|
||||
if !yield(strconv.Itoa(rand.IntN(100_000))) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genInts(n int) iter.Seq[int] {
|
||||
return func(yield func(int) bool) {
|
||||
for range n {
|
||||
if !yield(rand.IntN(100_000)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genIntPtrSeq(n int) iter.Seq[*int] {
|
||||
return func(yield func(*int) bool) {
|
||||
for range n {
|
||||
v := rand.IntN(100_000)
|
||||
if !yield(&v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genMapStringInt(n int) map[string]int {
|
||||
m := make(map[string]int, n)
|
||||
for i := range n {
|
||||
m[strconv.Itoa(i)] = rand.IntN(100_000)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func genMapSeq(n int) iter.Seq[map[string]int] {
|
||||
return func(yield func(map[string]int) bool) {
|
||||
for range n {
|
||||
m := map[string]int{strconv.Itoa(rand.IntN(100_000)): rand.IntN(100_000)}
|
||||
if !yield(m) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
//go:build go1.23
|
||||
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
)
|
||||
|
||||
func BenchmarkItKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Keys(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUniqKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.UniqKeys(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Values(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUniqValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.UniqValues(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEntries(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Entries(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFromEntries(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
entries := it.Entries(m)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.FromEntries(entries)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItInvert(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
entries := it.Entries(m)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Invert(entries) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItAssign(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
seq := genMapSeq(n)
|
||||
b.Run(fmt.Sprintf("maps_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Assign(seq)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFilterKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FilterKeys(m, func(_ string, v int) bool { return v%2 == 0 }) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFilterValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FilterValues(m, func(_ string, v int) bool { return v%2 == 0 }) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItChunkString(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
var sb strings.Builder
|
||||
for range n {
|
||||
sb.WriteString("a")
|
||||
}
|
||||
s := sb.String()
|
||||
b.Run(fmt.Sprintf("len_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ChunkString(s, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//go:build go1.23
|
||||
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
)
|
||||
|
||||
func BenchmarkItSum(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Sum(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSumBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.SumBy(ints, func(x int) int { return x })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItProduct(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Product(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMean(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Mean(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMode(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Mode(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItRange(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Range(n) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLength(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Length(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,11 @@ package benchmark
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"math/rand/v2"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
)
|
||||
|
||||
var itLengths = []int{10, 100, 1000}
|
||||
|
||||
func BenchmarkItChunk(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
strs := genStrings(n)
|
||||
@@ -37,26 +32,6 @@ func BenchmarkItChunk(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func genStrings(n int) iter.Seq[string] {
|
||||
return func(yield func(string) bool) {
|
||||
for range n {
|
||||
if !yield(strconv.Itoa(rand.IntN(100_000))) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genInts(n int) iter.Seq[int] {
|
||||
return func(yield func(int) bool) {
|
||||
for range n {
|
||||
if !yield(rand.IntN(100_000)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFlatten(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := make([]iter.Seq[int], 0, n)
|
||||
@@ -241,105 +216,6 @@ func BenchmarkItTrimSuffix(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItCountBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.CountBy(ints, func(x int) bool { return x%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFind(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Find(ints, func(x int) bool { return x == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItContainsBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.ContainsBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEveryBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.EveryBy(ints, func(x int) bool { return x >= 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSomeBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.SomeBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNoneBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
target := rand.IntN(100_000)
|
||||
for range b.N {
|
||||
_ = it.NoneBy(ints, func(x int) bool { return x == target })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func genIntPtrSeq(n int) iter.Seq[*int] {
|
||||
return func(yield func(*int) bool) {
|
||||
for range n {
|
||||
v := rand.IntN(100_000)
|
||||
if !yield(&v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genMapStringInt(n int) map[string]int {
|
||||
m := make(map[string]int, n)
|
||||
for i := range n {
|
||||
m[strconv.Itoa(i)] = rand.IntN(100_000)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func genMapSeq(n int) iter.Seq[map[string]int] {
|
||||
return func(yield func(map[string]int) bool) {
|
||||
for range n {
|
||||
m := map[string]int{strconv.Itoa(rand.IntN(100_000)): rand.IntN(100_000)}
|
||||
if !yield(m) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFilter(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
@@ -648,6 +524,17 @@ func BenchmarkItCount(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItCountBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.CountBy(ints, func(x int) bool { return x%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItCountValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
@@ -765,537 +652,3 @@ func BenchmarkItBuffer(b *testing.B) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItContains(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Contains(ints, 42)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEvery(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Every(ints, 1, 2, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSome(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Some(ints, 1, 2, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNone(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.None(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItIntersect(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
a := genInts(n)
|
||||
c := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Intersect(a, c) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUnion(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
a := genInts(n)
|
||||
c := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Union(a, c) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItWithout(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Without(ints, 1, 2, 3, 4, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItWithoutNth(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.WithoutNth(ints, 0, n/2, n-1) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.IndexOf(ints, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLastIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.LastIndexOf(ints, -1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItHasPrefix(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.HasPrefix(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItHasSuffix(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.HasSuffix(ints, -1, -2, -3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindIndexOf(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _, _ = it.FindIndexOf(ints, func(x int) bool { return x == -1 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindOrElse(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.FindOrElse(ints, -1, func(x int) bool { return x == -1 })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindUniques(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FindUniques(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFindDuplicates(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FindDuplicates(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMin(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Min(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMax(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Max(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMinBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.MinBy(ints, func(a, b int) bool { return a < b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMaxBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.MaxBy(ints, func(a, b int) bool { return a > b })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFirst(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.First(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLast(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Last(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItNth(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_, _ = it.Nth(ints, n/2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSample(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Sample(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSamples(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Samples(ints, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSum(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Sum(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItSumBy(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.SumBy(ints, func(x int) int { return x })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItProduct(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Product(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMean(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Mean(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItMode(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Mode(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItRange(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Range(n) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItLength(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Length(ints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Keys(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUniqKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.UniqKeys(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Values(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItUniqValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.UniqValues(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItEntries(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Entries(m) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFromEntries(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
entries := it.Entries(m)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.FromEntries(entries)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItInvert(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
entries := it.Entries(m)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.Invert(entries) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItAssign(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
seq := genMapSeq(n)
|
||||
b.Run(fmt.Sprintf("maps_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
_ = it.Assign(seq)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFilterKeys(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FilterKeys(m, func(_ string, v int) bool { return v%2 == 0 }) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFilterValues(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
m := genMapStringInt(n)
|
||||
b.Run(fmt.Sprintf("map_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FilterValues(m, func(_ string, v int) bool { return v%2 == 0 }) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItToSeqPtr(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ToSeqPtr(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFromSeqPtr(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ptrs := genIntPtrSeq(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FromSeqPtr(ptrs) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItToAnySeq(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ToAnySeq(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItChunkString(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
s := ""
|
||||
var sSb1288 strings.Builder
|
||||
for range n {
|
||||
sSb1288.WriteString("a")
|
||||
}
|
||||
s += sSb1288.String()
|
||||
b.Run(fmt.Sprintf("len_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ChunkString(s, 5) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//go:build go1.23
|
||||
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo/it"
|
||||
)
|
||||
|
||||
func BenchmarkItToSeqPtr(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ToSeqPtr(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItFromSeqPtr(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ptrs := genIntPtrSeq(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.FromSeqPtr(ptrs) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItToAnySeq(b *testing.B) {
|
||||
for _, n := range itLengths {
|
||||
ints := genInts(n)
|
||||
b.Run(fmt.Sprintf("ints_%d", n), func(b *testing.B) {
|
||||
for range b.N {
|
||||
for range it.ToAnySeq(ints) { //nolint:revive
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
package benchmark
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
lop "github.com/samber/lo/parallel"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
func sliceGenerator(size uint) []int64 {
|
||||
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
|
||||
result := make([]int64, size)
|
||||
|
||||
for i := uint(0); i < size; i++ {
|
||||
result[i] = r.Int63()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mapGenerator(size uint) map[int64]int64 {
|
||||
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
|
||||
result := make(map[int64]int64, size)
|
||||
|
||||
for i := uint(0); i < size; i++ {
|
||||
result[int64(i)] = r.Int63()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func BenchmarkMap(b *testing.B) {
|
||||
arr := sliceGenerator(1000000)
|
||||
|
||||
b.Run("lo.Map", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.Map(arr, func(x int64, i int) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("lop.Map", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lop.Map(arr, func(x int64, i int) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("reflect", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = funk.Map(arr, func(x int64) string {
|
||||
return strconv.FormatInt(x, 10)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("for", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
results := make([]string, len(arr))
|
||||
|
||||
for i, item := range arr {
|
||||
result := strconv.FormatInt(item, 10)
|
||||
results[i] = result
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkUniqKeys(b *testing.B) {
|
||||
m := []map[int64]int64{
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
}
|
||||
b.Run("lo.UniqKeys", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.UniqKeys(m...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkUniqValues(b *testing.B) {
|
||||
m := []map[int64]int64{
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
mapGenerator(1000),
|
||||
}
|
||||
b.Run("lo.UniqValues", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.UniqValues(m...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFilterKeys(b *testing.B) {
|
||||
m := mapGenerator(1000)
|
||||
b.Run("lo.FilterKeys", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.FilterKeys(m, func(k, v int64) bool { return k%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFilterValues(b *testing.B) {
|
||||
m := mapGenerator(1000)
|
||||
b.Run("lo.FilterValues", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = lo.FilterValues(m, func(k, v int64) bool { return v%2 == 0 })
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -21,6 +21,8 @@ func TernaryF[T any](condition bool, ifFunc, elseFunc func() T) T {
|
||||
return elseFunc()
|
||||
}
|
||||
|
||||
// Perf: value receivers (not pointer) allow the compiler to fully inline the entire
|
||||
// If().ElseIf().Else() chain, eliminating all function call overhead.
|
||||
type ifElse[T any] struct {
|
||||
result T
|
||||
done bool
|
||||
@@ -90,6 +92,8 @@ func (i ifElse[T]) ElseF(resultF func() T) T {
|
||||
return resultF()
|
||||
}
|
||||
|
||||
// Perf: value receivers (not pointer) allow the compiler to fully inline the entire
|
||||
// Switch().Case().Default() chain, eliminating all function call overhead.
|
||||
type switchCase[T comparable, R any] struct {
|
||||
predicate T
|
||||
result R
|
||||
|
||||
@@ -105,6 +105,8 @@ func Zip2[A, B any](a []A, b []B) []Tuple2[A, B] {
|
||||
|
||||
result := make([]Tuple2[A, B], size)
|
||||
|
||||
// Perf: separate loops per input slice improve CPU cache locality (each loop reads
|
||||
// one contiguous memory region) and enable bounds-check elimination by the compiler.
|
||||
for i := range a {
|
||||
result[i].A = a[i]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user