]> Cypherpunks repositories - gostls13.git/commitdiff
strings: add Compare(x, y string) int, for symmetry with bytes.Compare
authorAlan Donovan <adonovan@google.com>
Wed, 14 Jan 2015 23:09:36 +0000 (18:09 -0500)
committerAlan Donovan <adonovan@google.com>
Thu, 15 Jan 2015 17:17:05 +0000 (17:17 +0000)
The implementation is the same assembly (or Go) routine.

Change-Id: Ib937c461c24ad2d5be9b692b4eed40d9eb031412
Reviewed-on: https://go-review.googlesource.com/2828
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_amd64p32.s
src/runtime/noasm.go
src/strings/compare_test.go [new file with mode: 0644]
src/strings/strings_decl.go

index 0a58faf19b23fe405c5661fb9e0f05c070849f74..625bf7bf4e2434b22948e0a4ebffac26aa98e207 100644 (file)
@@ -1431,6 +1431,9 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
        MOVL    AX, ret+16(FP)
        RET
 
+TEXT strings·Compare(SB),NOSPLIT,$0
+        JMP    runtime·cmpstring(SB)
+
 TEXT bytes·Compare(SB),NOSPLIT,$0-28
        MOVL    s1+0(FP), SI
        MOVL    s1+4(FP), BX
index 8547228ee37804e50ce02bf079661d5b2bce1e83..2f9d520d448a363fa658bc2065990af123b2abf5 100644 (file)
@@ -1364,6 +1364,9 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
        MOVQ    AX, ret+32(FP)
        RET
 
+TEXT strings·Compare(SB),NOSPLIT,$0
+        JMP    runtime·cmpstring(SB)
+
 TEXT bytes·Compare(SB),NOSPLIT,$0-56
        MOVQ    s1+0(FP), SI
        MOVQ    s1+8(FP), BX
index 77355bb99870590caa1b5512e7cd0c7237b42341..807bb56f2a80d07036b63eb20eb15991d301740f 100644 (file)
@@ -832,6 +832,9 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
        MOVL    AX, ret+16(FP)
        RET
 
+TEXT strings·Compare(SB),NOSPLIT,$0
+        JMP    runtime·cmpstring(SB)
+
 TEXT bytes·Compare(SB),NOSPLIT,$0-28
        MOVL    s1+0(FP), SI
        MOVL    s1+4(FP), BX
index 7ffde379921ab044915b9a6b5c4305c37453873a..c6e63257cbd6842244f89d316080ec639a01daa9 100644 (file)
@@ -10,6 +10,11 @@ package runtime
 
 import _ "unsafe" // for go:linkname
 
+//go:linkname strings_Compare strings.Compare
+func strings_Compare(s1, s2 string) int {
+       return cmpstring(s1, s2)
+}
+
 func cmpstring(s1, s2 string) int {
        l := len(s1)
        if len(s2) < l {
diff --git a/src/strings/compare_test.go b/src/strings/compare_test.go
new file mode 100644 (file)
index 0000000..68fc88e
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+// Derived from bytes/compare_test.go.
+// Benchmarks omitted since the underlying implementation is identical.
+
+import (
+       . "strings"
+       "testing"
+)
+
+var compareTests = []struct {
+       a, b string
+       i    int
+}{
+       {"", "", 0},
+       {"a", "", 1},
+       {"", "a", -1},
+       {"abc", "abc", 0},
+       {"ab", "abc", -1},
+       {"abc", "ab", 1},
+       {"x", "ab", 1},
+       {"ab", "x", -1},
+       {"x", "a", 1},
+       {"b", "x", -1},
+       // test runtime·memeq's chunked implementation
+       {"abcdefgh", "abcdefgh", 0},
+       {"abcdefghi", "abcdefghi", 0},
+       {"abcdefghi", "abcdefghj", -1},
+}
+
+func TestCompare(t *testing.T) {
+       for _, tt := range compareTests {
+               cmp := Compare(tt.a, tt.b)
+               if cmp != tt.i {
+                       t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+               }
+       }
+}
+
+func TestCompareIdenticalString(t *testing.T) {
+       var s = "Hello Gophers!"
+       if Compare(s, s) != 0 {
+               t.Error("s != s")
+       }
+       if Compare(s, s[:1]) != 1 {
+               t.Error("s > s[:1] failed")
+       }
+}
+
+func TestCompareStrings(t *testing.T) {
+       n := 128
+       a := make([]byte, n+1)
+       b := make([]byte, n+1)
+       for len := 0; len < 128; len++ {
+               // randomish but deterministic data.  No 0 or 255.
+               for i := 0; i < len; i++ {
+                       a[i] = byte(1 + 31*i%254)
+                       b[i] = byte(1 + 31*i%254)
+               }
+               // data past the end is different
+               for i := len; i <= n; i++ {
+                       a[i] = 8
+                       b[i] = 9
+               }
+
+               cmp := Compare(string(a[:len]), string(b[:len]))
+               if cmp != 0 {
+                       t.Errorf(`CompareIdentical(%d) = %d`, len, cmp)
+               }
+               if len > 0 {
+                       cmp = Compare(string(a[:len-1]), string(b[:len]))
+                       if cmp != -1 {
+                               t.Errorf(`CompareAshorter(%d) = %d`, len, cmp)
+                       }
+                       cmp = Compare(string(a[:len]), string(b[:len-1]))
+                       if cmp != 1 {
+                               t.Errorf(`CompareBshorter(%d) = %d`, len, cmp)
+                       }
+               }
+               for k := 0; k < len; k++ {
+                       b[k] = a[k] - 1
+                       cmp = Compare(string(a[:len]), string(b[:len]))
+                       if cmp != 1 {
+                               t.Errorf(`CompareAbigger(%d,%d) = %d`, len, k, cmp)
+                       }
+                       b[k] = a[k] + 1
+                       cmp = Compare(string(a[:len]), string(b[:len]))
+                       if cmp != -1 {
+                               t.Errorf(`CompareBbigger(%d,%d) = %d`, len, k, cmp)
+                       }
+                       b[k] = a[k]
+               }
+       }
+}
index 810a696af2767f7f877e1ca57c71a2412adb3090..9dc2a9a6c67e8d9f3acc962f853e8313f4e2e873 100644 (file)
@@ -6,3 +6,10 @@ package strings
 
 // IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
 func IndexByte(s string, c byte) int // ../runtime/asm_$GOARCH.s
+
+// Compare returns an integer comparing two strings lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+//
+// In most cases it is simpler to use the built-in comparison operators
+// ==, <, >, and so on.
+func Compare(a, b string) int // ../runtime/noasm.go or ../runtime/asm_*.s