Skip to content

Commit

Permalink
🐛 utils: fix EqualFold and docs (#1833)
Browse files Browse the repository at this point in the history
* 🔍 utils: add/improve tests for ToLower/ToUpper/EqualFold

* 🐛 utils: fix EqualFold and docs
  • Loading branch information
jfcg committed Mar 23, 2022
1 parent 2f0d745 commit 2b5b6b2
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 51 deletions.
23 changes: 11 additions & 12 deletions utils/bytes.go
Expand Up @@ -4,15 +4,15 @@

package utils

// ToLowerBytes is the equivalent of bytes.ToLower
// ToLowerBytes converts ascii slice to lower-case
func ToLowerBytes(b []byte) []byte {
for i := 0; i < len(b); i++ {
b[i] = toLowerTable[b[i]]
}
return b
}

// ToUpperBytes is the equivalent of bytes.ToUpper
// ToUpperBytes converts ascii slice to upper-case
func ToUpperBytes(b []byte) []byte {
for i := 0; i < len(b); i++ {
b[i] = toUpperTable[b[i]]
Expand Down Expand Up @@ -55,16 +55,15 @@ func TrimBytes(b []byte, cutset byte) []byte {
return b[i : j+1]
}

// EqualFold the equivalent of bytes.EqualFold
func EqualFoldBytes(b, s []byte) (equals bool) {
n := len(b)
equals = n == len(s)
if equals {
for i := 0; i < n; i++ {
if equals = b[i]|0x20 == s[i]|0x20; !equals {
break
}
// EqualFoldBytes tests ascii slices for equality case-insensitively
func EqualFoldBytes(b, s []byte) bool {
if len(b) != len(s) {
return false
}
for i := len(b) - 1; i >= 0; i-- {
if toUpperTable[b[i]] != toUpperTable[s[i]] {
return false
}
}
return
return true
}
23 changes: 12 additions & 11 deletions utils/bytes_test.go
Expand Up @@ -24,20 +24,20 @@ func Test_ToLowerBytes(t *testing.T) {
}

func Benchmark_ToLowerBytes(b *testing.B) {
path := []byte("/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts")
path := []byte(largeStr)
want := []byte(lowerStr)
var res []byte

b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = ToLowerBytes(path)
}
AssertEqual(b, bytes.Equal(UnsafeBytes("/repos/gofiber/fiber/issues/187643/comments"), res), true)
AssertEqual(b, bytes.Equal(want, res), true)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = bytes.ToLower(path)
}
AssertEqual(b, bytes.Equal(UnsafeBytes("/repos/gofiber/fiber/issues/187643/comments"), res), true)
AssertEqual(b, bytes.Equal(want, res), true)
})
}

Expand All @@ -56,20 +56,20 @@ func Test_ToUpperBytes(t *testing.T) {
}

func Benchmark_ToUpperBytes(b *testing.B) {
path := []byte("/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts")
path := []byte(largeStr)
want := []byte(upperStr)
var res []byte

b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = ToUpperBytes(path)
}
AssertEqual(b, bytes.Equal(UnsafeBytes("/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS"), res), true)
AssertEqual(b, bytes.Equal(want, res), true)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = bytes.ToUpper(path)
}
AssertEqual(b, bytes.Equal(UnsafeBytes("/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS"), res), true)
AssertEqual(b, bytes.Equal(want, res), true)
})
}

Expand Down Expand Up @@ -182,10 +182,9 @@ func Benchmark_TrimBytes(b *testing.B) {
}

func Benchmark_EqualFoldBytes(b *testing.B) {
left := []byte("/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts")
right := []byte("/RePos/goFiber/Fiber/issues/187643/COMMENTS")
left := []byte(upperStr)
right := []byte(lowerStr)
var res bool

b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = EqualFoldBytes(left, right)
Expand All @@ -210,6 +209,8 @@ func Test_EqualFoldBytes(t *testing.T) {
AssertEqual(t, false, res)
res = EqualFoldBytes([]byte("/dddddd"), []byte("eeeeee"))
AssertEqual(t, false, res)
res = EqualFoldBytes([]byte("\na"), []byte("*A"))
AssertEqual(t, false, res)
res = EqualFoldBytes([]byte("/MY3/NAME/IS/:PARAM/*"), []byte("/my3/name/is/:param/*"))
AssertEqual(t, true, res)
res = EqualFoldBytes([]byte("/MY4/NAME/IS/:PARAM/*"), []byte("/my4/nAME/IS/:param/*"))
Expand Down
23 changes: 11 additions & 12 deletions utils/strings.go
Expand Up @@ -4,7 +4,7 @@

package utils

// ToLower is the equivalent of strings.ToLower
// ToLower converts ascii string to lower-case
func ToLower(b string) string {
res := make([]byte, len(b))
copy(res, b)
Expand All @@ -15,7 +15,7 @@ func ToLower(b string) string {
return UnsafeString(res)
}

// ToUpper is the equivalent of strings.ToUpper
// ToUpper converts ascii string to upper-case
func ToUpper(b string) string {
res := make([]byte, len(b))
copy(res, b)
Expand Down Expand Up @@ -61,16 +61,15 @@ func TrimRight(s string, cutset byte) string {
return s[:lenStr]
}

// EqualFold the equivalent of strings.EqualFold
func EqualFold(b, s string) (equals bool) {
n := len(b)
equals = n == len(s)
if equals {
for i := 0; i < n; i++ {
if equals = b[i]|0x20 == s[i]|0x20; !equals {
break
}
// EqualFold tests ascii strings for equality case-insensitively
func EqualFold(b, s string) bool {
if len(b) != len(s) {
return false
}
for i := len(b) - 1; i >= 0; i-- {
if toUpperTable[b[i]] != toUpperTable[s[i]] {
return false
}
}
return
return true
}
34 changes: 18 additions & 16 deletions utils/strings_test.go
Expand Up @@ -15,21 +15,25 @@ func Test_ToUpper(t *testing.T) {
AssertEqual(t, "/MY/NAME/IS/:PARAM/*", res)
}

const (
largeStr = "/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts/RePos/GoFiBer/FibEr/iSsues/CoMmEnts"
upperStr = "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS/REPOS/GOFIBER/FIBER/ISSUES/COMMENTS"
lowerStr = "/repos/gofiber/fiber/issues/187643/comments/repos/gofiber/fiber/issues/comments"
)

func Benchmark_ToUpper(b *testing.B) {
path := "/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts"
var res string

b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = ToUpper(path)
res = ToUpper(largeStr)
}
AssertEqual(b, "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS", res)
AssertEqual(b, upperStr, res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.ToUpper(path)
res = strings.ToUpper(largeStr)
}
AssertEqual(b, "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS", res)
AssertEqual(b, upperStr, res)
})
}

Expand All @@ -48,19 +52,18 @@ func Test_ToLower(t *testing.T) {
}

func Benchmark_ToLower(b *testing.B) {
path := "/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts"
var res string
b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = ToLower(path)
res = ToLower(largeStr)
}
AssertEqual(b, "/repos/gofiber/fiber/issues/187643/comments", res)
AssertEqual(b, lowerStr, res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.ToLower(path)
res = strings.ToLower(largeStr)
}
AssertEqual(b, "/repos/gofiber/fiber/issues/187643/comments", res)
AssertEqual(b, lowerStr, res)
})
}

Expand Down Expand Up @@ -180,19 +183,16 @@ func Benchmark_Trim(b *testing.B) {

// go test -v -run=^$ -bench=Benchmark_EqualFold -benchmem -count=4
func Benchmark_EqualFold(b *testing.B) {
left := "/RePos/GoFiBer/FibEr/iSsues/187643/CoMmEnts"
right := "/RePos/goFiber/Fiber/issues/187643/COMMENTS"
var res bool

b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = EqualFold(left, right)
res = EqualFold(upperStr, lowerStr)
}
AssertEqual(b, true, res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.EqualFold(left, right)
res = strings.EqualFold(upperStr, lowerStr)
}
AssertEqual(b, true, res)
})
Expand All @@ -208,6 +208,8 @@ func Test_EqualFold(t *testing.T) {
AssertEqual(t, false, res)
res = EqualFold("/dddddd", "eeeeee")
AssertEqual(t, false, res)
res = EqualFold("\na", "*A")
AssertEqual(t, false, res)
res = EqualFold("/MY3/NAME/IS/:PARAM/*", "/my3/name/is/:param/*")
AssertEqual(t, true, res)
res = EqualFold("/MY4/NAME/IS/:PARAM/*", "/my4/nAME/IS/:param/*")
Expand Down

2 comments on commit 2b5b6b2

@Fenny
Copy link
Member

@Fenny Fenny commented on 2b5b6b2 Mar 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: 2b5b6b2 Previous: 2f0d745 Ratio
Benchmark_ToLowerBytes/fiber 49.21 ns/op 0 B/op 0 allocs/op 22.86 ns/op 0 B/op 0 allocs/op 2.15
Benchmark_ToUpperBytes/fiber 62.11 ns/op 0 B/op 0 allocs/op 30.81 ns/op 0 B/op 0 allocs/op 2.02
Benchmark_EqualFoldBytes/fiber 98.98 ns/op 0 B/op 0 allocs/op 39.02 ns/op 0 B/op 0 allocs/op 2.54
Benchmark_EqualFoldBytes/default 299.1 ns/op 0 B/op 0 allocs/op 123.7 ns/op 0 B/op 0 allocs/op 2.42
Benchmark_ToUpper/default 323 ns/op 80 B/op 1 allocs/op 157 ns/op 48 B/op 1 allocs/op 2.06
Benchmark_ToLower/default 319.1 ns/op 80 B/op 1 allocs/op 157.8 ns/op 48 B/op 1 allocs/op 2.02
Benchmark_EqualFold/fiber 98.46 ns/op 0 B/op 0 allocs/op 44.22 ns/op 0 B/op 0 allocs/op 2.23
Benchmark_EqualFold/default 302.8 ns/op 0 B/op 0 allocs/op 123.4 ns/op 0 B/op 0 allocs/op 2.45

This comment was automatically generated by workflow using github-action-benchmark.

@jfcg
Copy link
Contributor Author

@jfcg jfcg commented on 2b5b6b2 Mar 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

largeStr is about twice as long as previous inputs, hence the benchmark results are fine.

Please sign in to comment.