Skip to content

Commit

Permalink
feat: Add IfToLower and IfToUpper functions for converting ASCII stri…
Browse files Browse the repository at this point in the history
…ngs to lowercase and uppercase respectively
  • Loading branch information
sixcolors committed Mar 25, 2024
1 parent b1e3dbb commit 3717ffb
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
58 changes: 58 additions & 0 deletions strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,61 @@ func ToUpper(b string) string {

return UnsafeString(res)
}

// IfToUpper returns an lowercase version of the input ASCII string.
//
// It first checks if the string contains any uppercase characters before converting it.
//
// For strings that are already lowercase,this function will be faster than `ToLower`.
//
// In the case of mixed-case or uppercase strings, this function will be slightly slower than `ToLower`.
func IfToLower(s string) string {
hasUpper := false
for i := 0; i < len(s); i++ {
c := s[i]
if toLowerTable[c] != c {
hasUpper = true
break
}
}

if !hasUpper {
return s
}
res := make([]byte, len(s))
copy(res, s)
for i := 0; i < len(res); i++ {
res[i] = toLowerTable[res[i]]
}

return UnsafeString(res)
}

// IfToUpper returns an uppercase version of the input ASCII string.
//
// It first checks if the string contains any lowercase characters before converting it.
//
// For strings that are already uppercase,this function will be faster than `ToUpper`.
//
// In the case of mixed-case or lowercase strings, this function will be slightly slower than `ToUpper`.
func IfToUpper(s string) string {
hasLower := false
for i := 0; i < len(s); i++ {
c := s[i]
if toUpperTable[c] != c {
hasLower = true
break
}
}

if !hasLower {
return s
}
res := make([]byte, len(s))
copy(res, s)
for i := 0; i < len(res); i++ {
res[i] = toUpperTable[res[i]]
}

return UnsafeString(res)
}
63 changes: 63 additions & 0 deletions strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ func Benchmark_ToUpper(b *testing.B) {
}
require.Equal(b, upperStr, res)
})
b.Run("IfToUpper-Upper", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = IfToUpper(upperStr)
}
require.Equal(b, upperStr, res)
})
b.Run("IfToUpper-Mixed", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = IfToUpper(largeStr)
}
require.Equal(b, upperStr, res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.ToUpper(largeStr)
Expand All @@ -55,10 +67,61 @@ func Benchmark_ToLower(b *testing.B) {
}
require.Equal(b, lowerStr, res)
})
b.Run("IfToLower-Lower", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = IfToLower(lowerStr)
}
require.Equal(b, lowerStr, res)
})
b.Run("IfToLower-Mixed", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = IfToLower(largeStr)
}
require.Equal(b, lowerStr, res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.ToLower(largeStr)
}
require.Equal(b, lowerStr, res)
})
}

func Test_IfToUpper(t *testing.T) {
t.Parallel()
require.Equal(t, "MYNAMEISPARAM", IfToUpper("MYNAMEISPARAM")) // already uppercase
require.Equal(t, "MYNAMEISPARAM", IfToUpper("mynameisparam")) // lowercase to uppercase
require.Equal(t, "MYNAMEISPARAM", IfToUpper("MyNameIsParam")) // mixed case
}

func Test_IfToLower(t *testing.T) {
t.Parallel()
require.Equal(t, "mynameisparam", IfToLower("mynameisparam")) // already lowercase
require.Equal(t, "mynameisparam", IfToLower("myNameIsParam")) // mixed case
require.Equal(t, "https://gofiber.io", IfToLower("https://gofiber.io")) // Origin Header Type URL
require.Equal(t, "mynameisparam", IfToLower("MYNAMEISPARAM")) // uppercase to lowercase
}

// Benchmark_IfToLower_HeadersOrigin benchmarks the IfToLower function with an origin header type URL.
// These headers are typically lowercase, so the function should return the input string without modification.
func Benchmark_IfToToLower_HeadersOrigin(b *testing.B) {
var res string
b.Run("fiber", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = ToLower("https://gofiber.io")
}
require.Equal(b, "https://gofiber.io", res)
})
b.Run("IfToLower-Lower", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = IfToLower("https://gofiber.io")
}
require.Equal(b, "https://gofiber.io", res)
})
b.Run("default", func(b *testing.B) {
for n := 0; n < b.N; n++ {
res = strings.ToLower("https://gofiber.io")
}
require.Equal(b, "https://gofiber.io", res)
})
}

0 comments on commit 3717ffb

Please # to comment.