Skip to content

Commit

Permalink
Add natsort
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg committed Apr 11, 2023
1 parent b35a487 commit d2e9f90
Show file tree
Hide file tree
Showing 7 changed files with 1,910 additions and 0 deletions.
14 changes: 14 additions & 0 deletions natsort/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
run: build bench stat

build:
go test -c -o natsort-bench.exec

bench:
time ./natsort-bench.exec \
-test.v -test.benchmem \
-test.bench ^Benchmark \
-test.count 3 \
-test.run ^$ | tee bench.txt

stat:
benchstat bench.txt
85 changes: 85 additions & 0 deletions natsort/bench.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
goos: darwin
goarch: arm64
pkg: github.com/cristaloleg/benches/natsort
BenchmarkStdlib_Strings
BenchmarkStdlib_Strings/small
BenchmarkStdlib_Strings/small-10 561956 2117 ns/op 24 B/op 1 allocs/op
BenchmarkStdlib_Strings/small-10 547368 2121 ns/op 24 B/op 1 allocs/op
BenchmarkStdlib_Strings/small-10 545804 2125 ns/op 24 B/op 1 allocs/op
BenchmarkStdlib_Strings/huge
BenchmarkStdlib_Strings/huge-10 6225 188029 ns/op 24 B/op 1 allocs/op
BenchmarkStdlib_Strings/huge-10 6210 188691 ns/op 24 B/op 1 allocs/op
BenchmarkStdlib_Strings/huge-10 5698 187595 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Sort
BenchmarkCristalhq_Sort/small
BenchmarkCristalhq_Sort/small-10 316620 3794 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Sort/small-10 314504 3780 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Sort/small-10 310911 3792 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Sort/huge
BenchmarkCristalhq_Sort/huge-10 2227 522022 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Sort/huge-10 2328 525377 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Sort/huge-10 2269 519937 ns/op 0 B/op 0 allocs/op
BenchmarkCristalhq_Slice
BenchmarkCristalhq_Slice/small
BenchmarkCristalhq_Slice/small-10 295246 4081 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Slice/small-10 294901 4051 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Slice/small-10 295615 4119 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Slice/huge
BenchmarkCristalhq_Slice/huge-10 2246 537975 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Slice/huge-10 2256 537370 ns/op 24 B/op 1 allocs/op
BenchmarkCristalhq_Slice/huge-10 2218 532765 ns/op 24 B/op 1 allocs/op
BenchmarkFacette_Sort
BenchmarkFacette_Sort/small
BenchmarkFacette_Sort/small-10 6409 184176 ns/op 101048 B/op 1810 allocs/op
BenchmarkFacette_Sort/small-10 6489 180198 ns/op 101429 B/op 1815 allocs/op
BenchmarkFacette_Sort/small-10 6244 182682 ns/op 101242 B/op 1812 allocs/op
BenchmarkFacette_Sort/huge
BenchmarkFacette_Sort/huge-10 45 25645570 ns/op 16170764 B/op 323866 allocs/op
BenchmarkFacette_Sort/huge-10 43 25996568 ns/op 16258429 B/op 325554 allocs/op
BenchmarkFacette_Sort/huge-10 44 25354756 ns/op 16208050 B/op 324899 allocs/op
BenchmarkMaruel_Sort
BenchmarkMaruel_Sort/small
BenchmarkMaruel_Sort/small-10 247838 4673 ns/op 24 B/op 1 allocs/op
BenchmarkMaruel_Sort/small-10 250066 4685 ns/op 24 B/op 1 allocs/op
BenchmarkMaruel_Sort/small-10 250335 4690 ns/op 24 B/op 1 allocs/op
BenchmarkMaruel_Sort/huge
BenchmarkMaruel_Sort/huge-10 1462 808731 ns/op 24 B/op 1 allocs/op
BenchmarkMaruel_Sort/huge-10 1460 816428 ns/op 24 B/op 1 allocs/op
BenchmarkMaruel_Sort/huge-10 1400 827159 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice
BenchmarkDangogh_Slice/small
BenchmarkDangogh_Slice/small-10 91945 13080 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice/small-10 89635 13014 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice/small-10 92401 13013 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice/huge
BenchmarkDangogh_Slice/huge-10 738 1639175 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice/huge-10 728 1658934 ns/op 24 B/op 1 allocs/op
BenchmarkDangogh_Slice/huge-10 724 1647764 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice
BenchmarkEvie404_Slice/small
BenchmarkEvie404_Slice/small-10 95402 12068 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice/small-10 98350 12067 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice/small-10 96961 12054 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice/huge
BenchmarkEvie404_Slice/huge-10 1470 817867 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice/huge-10 1480 806769 ns/op 24 B/op 1 allocs/op
BenchmarkEvie404_Slice/huge-10 1456 805209 ns/op 24 B/op 1 allocs/op
BenchmarkMiraclesu_Slice
BenchmarkMiraclesu_Slice/small
BenchmarkMiraclesu_Slice/small-10 105171 11270 ns/op 57 B/op 5 allocs/op
BenchmarkMiraclesu_Slice/small-10 106788 11159 ns/op 57 B/op 5 allocs/op
BenchmarkMiraclesu_Slice/small-10 107000 11291 ns/op 57 B/op 5 allocs/op
BenchmarkMiraclesu_Slice/huge
BenchmarkMiraclesu_Slice/huge-10 862 1387731 ns/op 24 B/op 1 allocs/op
BenchmarkMiraclesu_Slice/huge-10 861 1378709 ns/op 24 B/op 1 allocs/op
BenchmarkMiraclesu_Slice/huge-10 865 1392451 ns/op 24 B/op 1 allocs/op
BenchmarkImmortal_Slice
BenchmarkImmortal_Slice/small
BenchmarkImmortal_Slice/small-10 55617 20679 ns/op 12499 B/op 385 allocs/op
BenchmarkImmortal_Slice/small-10 58698 20083 ns/op 12494 B/op 384 allocs/op
BenchmarkImmortal_Slice/small-10 58990 20010 ns/op 12495 B/op 384 allocs/op
BenchmarkImmortal_Slice/huge
BenchmarkImmortal_Slice/huge-10 782 1515601 ns/op 950145 B/op 33556 allocs/op
BenchmarkImmortal_Slice/huge-10 780 1525203 ns/op 951441 B/op 33601 allocs/op
BenchmarkImmortal_Slice/huge-10 789 1498044 ns/op 950063 B/op 33555 allocs/op
PASS
15 changes: 15 additions & 0 deletions natsort/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module github.com/cristaloleg/benches/natsort

go 1.20

require (
github.com/cristalhq/natsort v0.1.1
github.com/dangogh/naturally v0.1.1
github.com/evie404/natsort v0.0.0-20180124032556-f194e6bd5b0c
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
github.com/immortal/natcasesort v0.0.0-20180922190600-53ad4be8bc1a
github.com/maruel/natural v1.1.0
github.com/miraclesu/natsort v0.0.0-20160121124727-836e59d384de
)

require github.com/smartystreets/goconvey v1.8.0 // indirect
19 changes: 19 additions & 0 deletions natsort/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
github.com/cristalhq/natsort v0.1.1 h1:UlPHSkP+Tx2f0wgoZS3N3U29nO3NF7lHvhEKuQr8LpY=
github.com/cristalhq/natsort v0.1.1/go.mod h1:cGdtrXl4O1ycmnwdnSBWgmTzZ9WP4i8ca2LH/QupN0Y=
github.com/dangogh/naturally v0.1.1 h1:q9j9n4Ij/cjZv7MOUj+871HTrCJE3ZJeoJrw5CjPrC0=
github.com/dangogh/naturally v0.1.1/go.mod h1:pmGmUAFR+GoKRXHpf/K5Hs2JP0o8oatc3t0NeVjrf8U=
github.com/evie404/natsort v0.0.0-20180124032556-f194e6bd5b0c h1:DNvN+Lov05ao9/haEzCTzJDfIHL/F4E3DBsDUMnjpYs=
github.com/evie404/natsort v0.0.0-20180124032556-f194e6bd5b0c/go.mod h1:+D05cmtvIC2Mc7z7x+AM82AAbaaBlUI9fMHJomz77qI=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM=
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/immortal/natcasesort v0.0.0-20180922190600-53ad4be8bc1a h1:xGCNWvZqUk/9l1ytDVzZHLAadyrB6My8AoG6ksxWbDU=
github.com/immortal/natcasesort v0.0.0-20180922190600-53ad4be8bc1a/go.mod h1:wrlf+Cc7o4fqKniC+4ebBmr6sJ8eeOjx5588f/4RgIU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ=
github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ=
github.com/miraclesu/natsort v0.0.0-20160121124727-836e59d384de h1:ZTLp5p4MzSKh9Is0s+l/J7qQiY4c3yKA98J5z1qcyv0=
github.com/miraclesu/natsort v0.0.0-20160121124727-836e59d384de/go.mod h1:hYCDR4MVndk4vkatvVgNzw27cfxJH+fLFSMFdjdMXmQ=
github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU=
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg=
186 changes: 186 additions & 0 deletions natsort/natsort_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package natsort_test

import (
"bytes"
_ "embed"
"math/rand"
"sort"
"testing"

cristalhq "github.com/cristalhq/natsort"
dangogh "github.com/dangogh/naturally"
evie404 "github.com/evie404/natsort"
facette "github.com/facette/natsort"
immortal "github.com/immortal/natcasesort"
maruel "github.com/maruel/natural"
miraclesu "github.com/miraclesu/natsort"
)

func BenchmarkStdlib_Strings(b *testing.B) {
bench(b, "small", smallList, func(list []string) {
sort.Strings(list)
})

bench(b, "huge", tagsList, func(list []string) {
sort.Strings(list)
})

// no need to checkResult(..) because stdlib sort is correct
// and result is sorted in lexicographical order, not natural
}

func BenchmarkCristalhq_Sort(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
cristalhq.Sort(list)
})
checkResult(b, data)

data = bench(b, "huge", tagsList, func(list []string) {
cristalhq.Sort(list)
})
checkResult(b, data)
}

func BenchmarkCristalhq_Slice(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
sort.Sort(cristalhq.Slice[string](list))
})
checkResult(b, data)

data = bench(b, "huge", tagsList, func(list []string) {
sort.Sort(cristalhq.Slice[string](list))
})
checkResult(b, data)
}

func BenchmarkFacette_Sort(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
facette.Sort(list)
})
checkResult(b, data)

data = bench(b, "huge", tagsList, func(list []string) {
facette.Sort(list)
})
// no check, small variance in the result
}

func BenchmarkMaruel_Sort(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
sort.Sort(maruel.StringSlice(list))
})
checkResult(b, data)

data = bench(b, "huge", tagsList, func(list []string) {
sort.Sort(maruel.StringSlice(list))
})
checkResult(b, data)
}

func BenchmarkDangogh_Slice(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
sort.Sort(dangogh.StringSlice(list))
})
// no check, incorrect result
_ = data

data = bench(b, "huge", tagsList, func(list []string) {
sort.Sort(dangogh.StringSlice(list))
})
// no check, incorrect result
}

func BenchmarkEvie404_Slice(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
evie404.Strings(list)
})
checkResult(b, data)

data = bench(b, "huge", tagsList, func(list []string) {
evie404.Strings(list)
})
checkResult(b, data)
}

func BenchmarkMiraclesu_Slice(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
miraclesu.Sort(list)
})
// no check, incorrect result
_ = data

data = bench(b, "huge", tagsList, func(list []string) {
miraclesu.Sort(list)
})
// no check, incorrect result
}

func BenchmarkImmortal_Slice(b *testing.B) {
data := bench(b, "small", smallList, func(list []string) {
sort.Sort(immortal.Sort(list))
})
// no check, incorrect result
_ = data

data = bench(b, "huge", tagsList, func(list []string) {
sort.Sort(immortal.Sort(list))
})
// no check, incorrect result
}

func bench(b *testing.B, name string, input []string, fn func(list []string)) []string {
b.Helper()

data := make([]string, len(input))
r := rand.New(rand.NewSource(69420))
copy(data, input)

b.Run(name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
r.Shuffle(len(data), func(i, j int) {
data[i], data[j] = data[j], data[i]
})
fn(data)
}
})
return data
}

func checkResult(b *testing.B, list []string) {
b.Helper()

ok := sort.SliceIsSorted(list, func(i, j int) bool {
return cristalhq.Less(list[i], list[j])
})
if !ok {
b.Errorf("not sorted %+v", list)
}
}

var (
//go:embed testdata/small.txt
smallFile []byte

//go:embed testdata/aws-sdk-go-tags.txt
tagsFile []byte
)

var (
smallList []string
tagsList []string
)

func init() {
smallList = readFile(smallFile)
tagsList = readFile(tagsFile)
}

func readFile(raw []byte) []string {
lines := bytes.Split(raw, []byte{'\n'})
res := make([]string, len(lines))

for i, line := range lines {
res[i] = string(line)
}
return res
}
Loading

0 comments on commit d2e9f90

Please sign in to comment.