Skip to content

Commit dd9cf49

Browse files
authored
Merge pull request #94 from llir/natsort
all: replace rickypai/natsort with internal/natsort
2 parents c5c443d + 685a7e3 commit dd9cf49

File tree

9 files changed

+330
-10
lines changed

9 files changed

+330
-10
lines changed

.travis.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ install:
1616
- go get -t ./...
1717

1818
before_script:
19-
- go get -u golang.org/x/tools/cmd/cover
20-
- go get -u golang.org/x/tools/cmd/goimports
21-
- go get -u golang.org/x/lint/golint
22-
- go get -u github.com/mattn/goveralls
23-
- go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
19+
- go get golang.org/x/tools/cmd/cover
20+
- go get golang.org/x/tools/cmd/goimports
21+
- go get golang.org/x/lint/golint
22+
- go get github.com/mattn/goveralls
23+
- go get github.com/golangci/golangci-lint/cmd/golangci-lint
2424
- wget https://raw.githubusercontent.com/mewmew/ci/master/ci_checks.sh
2525
- chmod +x ci_checks.sh
2626

asm/translate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,12 @@ import (
8989

9090
"github.com/llir/ll/ast"
9191
"github.com/llir/llvm/internal/enc"
92+
"github.com/llir/llvm/internal/natsort"
9293
"github.com/llir/llvm/ir"
9394
"github.com/llir/llvm/ir/constant"
9495
"github.com/llir/llvm/ir/metadata"
9596
"github.com/llir/llvm/ir/types"
9697
"github.com/pkg/errors"
97-
"github.com/rickypai/natsort"
9898
)
9999

100100
// translate translates the given AST module into an equivalent IR module.

go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ require (
77
github.com/mewmew/float v0.0.0-20181121163145-c0f786d7da73
88
github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8
99
github.com/pkg/errors v0.8.1
10-
github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c
1110
golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c
1211
)

go.sum

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8 h1:DSZ+nV7JOU9CznT
1313
github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8/go.mod h1:UAdVbSksr+7Bg+z4mga16OaBg3qAcgdaF3x3AeqJHEs=
1414
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
1515
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
16-
github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c h1:wq5MmT1Whub72MXlR2I5jWTQ3Q5wkNXnVBY21Q3Qzis=
17-
github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c/go.mod h1:ECfieXu+EwvGnmpzRZvaAN0U/Jese1LX/BqX3HF1Kl0=
1816
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
1917
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
2018
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

internal/natsort/LICENSE

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
The MIT License (MIT)
2+
Copyright (c) 2015 Frits van Bommel
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
The above copyright notice and this permission notice shall be included in all
10+
copies or substantial portions of the Software.
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17+
SOFTWARE.

internal/natsort/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# natsort
2+
3+
This is a fork of the `sortorder` package of [github.com/fvbommel/util](https://github.com/fvbommel/util).
4+
5+
## License
6+
7+
* [MIT](./LICENSE)
8+
- the original implementation of `sortorder` was released by [Frits van Bommel](https://github.com/fvbommel) under an MIT license.
9+
* [Public domain](../../UNLICENSE)
10+
- any changes made in this fork are released into the public domain.

internal/natsort/natsort.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Package natsort implements natural sort. In "Natural Sort Order" integers
2+
// embedded in strings are compared by value.
3+
//
4+
// References:
5+
// https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
6+
package natsort
7+
8+
import (
9+
"sort"
10+
)
11+
12+
// Strings sorts the given slice of strings in natural order.
13+
func Strings(a []string) {
14+
sort.Sort(Order(a))
15+
}
16+
17+
// Order implements sort.Interface to sort strings in natural order. This means
18+
// that e.g. "abc2" < "abc12".
19+
//
20+
// Non-digit sequences and numbers are compared separately. The former are
21+
// compared bytewise, while the latter are compared numerically (except that
22+
// the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02")
23+
//
24+
// Limitation: only ASCII digits (0-9) are considered.
25+
type Order []string
26+
27+
func (n Order) Len() int { return len(n) }
28+
func (n Order) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
29+
func (n Order) Less(i, j int) bool { return Less(n[i], n[j]) }
30+
31+
// isdigit reports whether the given byte is a decimal digit.
32+
func isdigit(b byte) bool {
33+
return '0' <= b && b <= '9'
34+
}
35+
36+
// Less compares two strings using natural ordering. This means that e.g. "abc2"
37+
// < "abc12".
38+
//
39+
// Non-digit sequences and numbers are compared separately. The former are
40+
// compared bytewise, while the latter are compared numerically (except that
41+
// the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02")
42+
//
43+
// Limitation: only ASCII digits (0-9) are considered.
44+
func Less(str1, str2 string) bool {
45+
idx1, idx2 := 0, 0
46+
for idx1 < len(str1) && idx2 < len(str2) {
47+
c1, c2 := str1[idx1], str2[idx2]
48+
dig1, dig2 := isdigit(c1), isdigit(c2)
49+
switch {
50+
case dig1 && dig2: // Digits
51+
// Eat zeros.
52+
for ; idx1 < len(str1) && str1[idx1] == '0'; idx1++ {
53+
}
54+
for ; idx2 < len(str2) && str2[idx2] == '0'; idx2++ {
55+
}
56+
// Eat all digits.
57+
nonZero1, nonZero2 := idx1, idx2
58+
for ; idx1 < len(str1) && isdigit(str1[idx1]); idx1++ {
59+
}
60+
for ; idx2 < len(str2) && isdigit(str2[idx2]); idx2++ {
61+
}
62+
// If lengths of numbers with non-zero prefix differ, the shorter
63+
// one is less.
64+
if len1, len2 := idx1-nonZero1, idx2-nonZero2; len1 != len2 {
65+
return len1 < len2
66+
}
67+
// If they're equal, string comparison is correct.
68+
if nr1, nr2 := str1[nonZero1:idx1], str2[nonZero2:idx2]; nr1 != nr2 {
69+
return nr1 < nr2
70+
}
71+
// Otherwise, the one with less zeros is less.
72+
// Because everything up to the number is equal, comparing the index
73+
// after the zeros is sufficient.
74+
if nonZero1 != nonZero2 {
75+
return nonZero1 < nonZero2
76+
}
77+
default: // non-digit characters
78+
// UTF-8 compares bytewise-lexicographically, no need to decode
79+
// codepoints.
80+
if c1 != c2 {
81+
return c1 < c2
82+
}
83+
idx1++
84+
idx2++
85+
}
86+
// They're identical so far, so continue comparing.
87+
}
88+
// So far they are identical. At least one is ended. If the other continues,
89+
// it sorts last.
90+
return len(str1) < len(str2)
91+
}

internal/natsort/natsort_test.go

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package natsort
2+
3+
import (
4+
"math/rand"
5+
"reflect"
6+
"sort"
7+
"strconv"
8+
"testing"
9+
)
10+
11+
func TestStrings(t *testing.T) {
12+
golden := []struct {
13+
in []string
14+
want []string
15+
}{
16+
{
17+
in: []string{"abc5", "abc1", "abc01", "ab", "abc10", "abc2"},
18+
want: []string{
19+
"ab",
20+
"abc1",
21+
"abc01",
22+
"abc2",
23+
"abc5",
24+
"abc10",
25+
},
26+
},
27+
{
28+
in: []string{"foo20", "foo.bar", "foo2", "foo.10", "foo.1", "foo.20", "foo.11", "foo1", "foobar", "foo21", "foo10", "foo11", "foo.21", "foo.2"},
29+
want: []string{
30+
"foo.1",
31+
"foo.2",
32+
"foo.10",
33+
"foo.11",
34+
"foo.20",
35+
"foo.21",
36+
"foo.bar",
37+
"foo1",
38+
"foo2",
39+
"foo10",
40+
"foo11",
41+
"foo20",
42+
"foo21",
43+
"foobar",
44+
},
45+
},
46+
}
47+
for _, g := range golden {
48+
Strings(g.in)
49+
if !reflect.DeepEqual(g.want, g.in) {
50+
t.Errorf("Error: sort failed, expected: %#q, got: %#q", g.want, g.in)
51+
}
52+
}
53+
}
54+
55+
func TestLess(t *testing.T) {
56+
testset := []struct {
57+
s1, s2 string
58+
less bool
59+
}{
60+
{"0", "00", true},
61+
{"00", "0", false},
62+
{"aa", "ab", true},
63+
{"ab", "abc", true},
64+
{"abc", "ad", true},
65+
{"ab1", "ab2", true},
66+
{"ab1c", "ab1c", false},
67+
{"ab12", "abc", true},
68+
{"ab2a", "ab10", true},
69+
{"a0001", "a0000001", true},
70+
{"a10", "abcdefgh2", true},
71+
{"аб2аб", "аб10аб", true},
72+
{"2аб", "3аб", true},
73+
//
74+
{"a1b", "a01b", true},
75+
{"a01b", "a1b", false},
76+
{"ab01b", "ab010b", true},
77+
{"ab010b", "ab01b", false},
78+
{"a01b001", "a001b01", true},
79+
{"a001b01", "a01b001", false},
80+
{"a1", "a1x", true},
81+
{"1ax", "1b", true},
82+
{"1b", "1ax", false},
83+
//
84+
{"082", "83", true},
85+
//
86+
{"083a", "9a", false},
87+
{"9a", "083a", true},
88+
//
89+
{"foo.bar", "foo123", true},
90+
{"foo123", "foo.bar", false},
91+
}
92+
for _, v := range testset {
93+
if res := Less(v.s1, v.s2); res != v.less {
94+
t.Errorf("Compared %#q to %#q: expected %v, got %v",
95+
v.s1, v.s2, v.less, res)
96+
}
97+
}
98+
}
99+
100+
func BenchmarkStdStrings(b *testing.B) {
101+
set := testSet(300)
102+
arr := make([]string, len(set[0]))
103+
b.ResetTimer()
104+
for i := 0; i < b.N; i++ {
105+
for _, list := range set {
106+
b.StopTimer()
107+
copy(arr, list)
108+
b.StartTimer()
109+
110+
sort.Strings(arr)
111+
}
112+
}
113+
}
114+
115+
func BenchmarkStrings(b *testing.B) {
116+
set := testSet(300)
117+
arr := make([]string, len(set[0]))
118+
b.ResetTimer()
119+
for i := 0; i < b.N; i++ {
120+
for _, list := range set {
121+
b.StopTimer()
122+
copy(arr, list)
123+
b.StartTimer()
124+
125+
Strings(arr)
126+
}
127+
}
128+
}
129+
130+
func BenchmarkStdLess(b *testing.B) {
131+
set := testSet(300)
132+
b.ResetTimer()
133+
for i := 0; i < b.N; i++ {
134+
for j := range set[0] {
135+
k := (j + 1) % len(set[0])
136+
_ = set[0][j] < set[0][k]
137+
}
138+
}
139+
}
140+
141+
func BenchmarkLess(b *testing.B) {
142+
set := testSet(300)
143+
b.ResetTimer()
144+
for i := 0; i < b.N; i++ {
145+
for j := range set[0] {
146+
k := (j + 1) % len(set[0])
147+
_ = Less(set[0][j], set[0][k])
148+
}
149+
}
150+
}
151+
152+
// Get 1000 arrays of 10000-string-arrays (less if -short is specified).
153+
func testSet(seed int) [][]string {
154+
gen := &generator{
155+
src: rand.New(rand.NewSource(
156+
int64(seed),
157+
)),
158+
}
159+
n := 1000
160+
if testing.Short() {
161+
n = 1
162+
}
163+
set := make([][]string, n)
164+
for i := range set {
165+
strings := make([]string, 10000)
166+
for idx := range strings {
167+
// Generate a random string
168+
strings[idx] = gen.NextString()
169+
}
170+
set[i] = strings
171+
}
172+
return set
173+
}
174+
175+
type generator struct {
176+
src *rand.Rand
177+
}
178+
179+
func (g *generator) NextInt(max int) int {
180+
return g.src.Intn(max)
181+
}
182+
183+
// Gets random random-length alphanumeric string.
184+
func (g *generator) NextString() (str string) {
185+
// Random-length 3-8 chars part
186+
strlen := g.src.Intn(6) + 3
187+
// Random-length 1-3 num
188+
numlen := g.src.Intn(3) + 1
189+
// Random position for num in string
190+
numpos := g.src.Intn(strlen + 1)
191+
// Generate the number
192+
var num string
193+
for i := 0; i < numlen; i++ {
194+
num += strconv.Itoa(g.src.Intn(10))
195+
}
196+
// Put it all together
197+
for i := 0; i < strlen+1; i++ {
198+
if i == numpos {
199+
str += num
200+
} else {
201+
str += string('a' + g.src.Intn(16))
202+
}
203+
}
204+
return str
205+
}

ir/module.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import (
55
"strings"
66

77
"github.com/llir/llvm/internal/enc"
8+
"github.com/llir/llvm/internal/natsort"
89
"github.com/llir/llvm/ir/enum"
910
"github.com/llir/llvm/ir/metadata"
1011
"github.com/llir/llvm/ir/types"
1112
"github.com/llir/llvm/ir/value"
1213
"github.com/pkg/errors"
13-
"github.com/rickypai/natsort"
1414
)
1515

1616
// === [ Modules ] =============================================================

0 commit comments

Comments
 (0)