mirror of
https://github.com/samber/lo.git
synced 2026-04-22 23:47:11 +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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lengths = []int{10, 100, 1000}
|
|
||||||
|
|
||||||
func BenchmarkChunk(b *testing.B) {
|
func BenchmarkChunk(b *testing.B) {
|
||||||
for _, n := range lengths {
|
for _, n := range lengths {
|
||||||
strs := genSliceString(n)
|
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) {
|
func BenchmarkFlatten(b *testing.B) {
|
||||||
for _, n := range lengths {
|
for _, n := range lengths {
|
||||||
ints := make([][]int, 0, n)
|
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) {
|
func BenchmarkReject(b *testing.B) {
|
||||||
for _, n := range lengths {
|
for _, n := range lengths {
|
||||||
strs := genSliceString(n)
|
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) {
|
func BenchmarkFill(b *testing.B) {
|
||||||
for _, n := range lengths {
|
for _, n := range lengths {
|
||||||
collection := make([]clonableString, n)
|
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) {
|
func BenchmarkSplice(b *testing.B) {
|
||||||
for _, n := range lengths {
|
for _, n := range lengths {
|
||||||
ints := genSliceInt(n)
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
"iter"
|
||||||
"math/rand/v2"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/samber/lo/it"
|
"github.com/samber/lo/it"
|
||||||
)
|
)
|
||||||
|
|
||||||
var itLengths = []int{10, 100, 1000}
|
|
||||||
|
|
||||||
func BenchmarkItChunk(b *testing.B) {
|
func BenchmarkItChunk(b *testing.B) {
|
||||||
for _, n := range itLengths {
|
for _, n := range itLengths {
|
||||||
strs := genStrings(n)
|
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) {
|
func BenchmarkItFlatten(b *testing.B) {
|
||||||
for _, n := range itLengths {
|
for _, n := range itLengths {
|
||||||
ints := make([]iter.Seq[int], 0, n)
|
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) {
|
func BenchmarkItFilter(b *testing.B) {
|
||||||
for _, n := range itLengths {
|
for _, n := range itLengths {
|
||||||
ints := genInts(n)
|
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) {
|
func BenchmarkItCountValues(b *testing.B) {
|
||||||
for _, n := range itLengths {
|
for _, n := range itLengths {
|
||||||
ints := genInts(n)
|
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()
|
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 {
|
type ifElse[T any] struct {
|
||||||
result T
|
result T
|
||||||
done bool
|
done bool
|
||||||
@@ -90,6 +92,8 @@ func (i ifElse[T]) ElseF(resultF func() T) T {
|
|||||||
return resultF()
|
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 {
|
type switchCase[T comparable, R any] struct {
|
||||||
predicate T
|
predicate T
|
||||||
result R
|
result R
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ func Zip2[A, B any](a []A, b []B) []Tuple2[A, B] {
|
|||||||
|
|
||||||
result := make([]Tuple2[A, B], size)
|
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 {
|
for i := range a {
|
||||||
result[i].A = a[i]
|
result[i].A = a[i]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user