diff --git a/strings.go b/strings.go index 0436f03..bf59f9a 100644 --- a/strings.go +++ b/strings.go @@ -68,3 +68,49 @@ func DefaultString(value string, defaultValue string) string { } return value } + +// 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 + } + return ToLower(s) +} + +// 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 + } + return ToUpper(s) +} diff --git a/strings_test.go b/strings_test.go index c65142b..5b0fece 100644 --- a/strings_test.go +++ b/strings_test.go @@ -25,6 +25,18 @@ func Benchmark_ToUpper(b *testing.B) { } AssertEqual(b, "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS", res) }) + b.Run("IfToUpper-Upper", func(b *testing.B) { + for n := 0; n < b.N; n++ { + res = IfToUpper("/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS") + } + AssertEqual(b, "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS", res) + }) + b.Run("IfToUpper-Mixed", func(b *testing.B) { + for n := 0; n < b.N; n++ { + res = IfToUpper(path) + } + AssertEqual(b, "/REPOS/GOFIBER/FIBER/ISSUES/187643/COMMENTS", res) + }) b.Run("default", func(b *testing.B) { for n := 0; n < b.N; n++ { res = strings.ToUpper(path) @@ -56,6 +68,18 @@ func Benchmark_ToLower(b *testing.B) { } AssertEqual(b, "/repos/gofiber/fiber/issues/187643/comments", res) }) + b.Run("IfToLower-Lower", func(b *testing.B) { + for n := 0; n < b.N; n++ { + res = IfToLower("/repos/gofiber/fiber/issues/187643/comments") + } + AssertEqual(b, "/repos/gofiber/fiber/issues/187643/comments", res) + }) + b.Run("IfToLower-Mixed", func(b *testing.B) { + for n := 0; n < b.N; n++ { + res = IfToLower(path) + } + AssertEqual(b, "/repos/gofiber/fiber/issues/187643/comments", res) + }) b.Run("default", func(b *testing.B) { for n := 0; n < b.N; n++ { res = strings.ToLower(path) @@ -147,3 +171,42 @@ func Benchmark_Trim(b *testing.B) { AssertEqual(b, "foobar", res) }) } + +func Test_IfToUpper(t *testing.T) { + t.Parallel() + AssertEqual(t, "MYNAMEISPARAM", IfToUpper("MYNAMEISPARAM")) // already uppercase + AssertEqual(t, "MYNAMEISPARAM", IfToUpper("mynameisparam")) // lowercase to uppercase + AssertEqual(t, "MYNAMEISPARAM", IfToUpper("MyNameIsParam")) // mixed case +} + +func Test_IfToLower(t *testing.T) { + t.Parallel() + AssertEqual(t, "mynameisparam", IfToLower("mynameisparam")) // already lowercase + AssertEqual(t, "mynameisparam", IfToLower("myNameIsParam")) // mixed case + AssertEqual(t, "https://gofiber.io", IfToLower("https://gofiber.io")) // Origin Header Type URL + AssertEqual(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") + } + AssertEqual(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") + } + AssertEqual(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") + } + AssertEqual(b, "https://gofiber.io", res) + }) +}