"unicode/utf8"
)
-// Equal returns a boolean reporting whether a and b
+// Equal reports whether a and b
// are the same length and contain the same bytes.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool {
- return bytealg.Equal(a, b)
-}
-
-func equalPortable(a, b []byte) bool {
- if len(a) != len(b) {
- return false
- }
- for i, c := range a {
- if c != b[i] {
- return false
- }
- }
- return true
+ // Neither cmd/compile nor gccgo allocates for these string conversions.
+ return string(a) == string(b)
}
// Compare returns an integer comparing two byte slices lexicographically.
}
func TestEqual(t *testing.T) {
- for _, tt := range compareTests {
- eql := Equal(tt.a, tt.b)
- if eql != (tt.i == 0) {
- t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
- }
- eql = EqualPortable(tt.a, tt.b)
- if eql != (tt.i == 0) {
- t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql)
+ // Run the tests and check for allocation at the same time.
+ allocs := testing.AllocsPerRun(10, func() {
+ for _, tt := range compareTests {
+ eql := Equal(tt.a, tt.b)
+ if eql != (tt.i == 0) {
+ t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
+ }
}
+ })
+ if allocs > 0 {
+ t.Errorf("Equal allocated %v times", allocs)
}
}
benchBytes(b, sizes, bmEqual(Equal))
}
-func BenchmarkEqualPort(b *testing.B) {
- sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20}
- benchBytes(b, sizes, bmEqual(EqualPortable))
-}
-
func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
return func(b *testing.B, n int) {
if len(bmbuf) < 2*n {
// Export func for testing
var IndexBytePortable = indexBytePortable
-var EqualPortable = equalPortable
runtime/tls_arm.s: [arm] _initcgo: function _initcgo missing Go declaration
runtime/internal/atomic/asm_arm.s: [arm] cas: function cas missing Go declaration
-internal/bytealg/equal_arm.s: [arm] Equal: invalid MOVW of ret+24(FP); bool is 1-byte value
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT,$0-25
- MOVL a_len+4(FP), BX
- MOVL b_len+16(FP), CX
- CMPL BX, CX
- JNE neq
- MOVL a_base+0(FP), SI
- MOVL b_base+12(FP), DI
- CMPL SI, DI
- JEQ eq
- LEAL ret+24(FP), AX
- JMP memeqbody<>(SB)
-neq:
- MOVB $0, ret+24(FP)
- RET
-eq:
- MOVB $1, ret+24(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT,$0-13
MOVL a+0(FP), SI
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT,$0-49
- MOVQ a_len+8(FP), BX
- MOVQ b_len+32(FP), CX
- CMPQ BX, CX
- JNE neq
- MOVQ a_base+0(FP), SI
- MOVQ b_base+24(FP), DI
- CMPQ SI, DI
- JEQ eq
- LEAQ ret+48(FP), AX
- JMP memeqbody<>(SB)
-neq:
- MOVB $0, ret+48(FP)
- RET
-eq:
- MOVB $1, ret+48(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT,$0-25
MOVQ a+0(FP), SI
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT,$0-25
- MOVL a_len+4(FP), BX
- MOVL b_len+16(FP), CX
- CMPL BX, CX
- JNE neq
- MOVL a_base+0(FP), SI
- MOVL b_base+12(FP), DI
- CMPL SI, DI
- JEQ eq
- CALL memeqbody<>(SB)
- MOVB AX, ret+24(FP)
- RET
-neq:
- MOVB $0, ret+24(FP)
- RET
-eq:
- MOVB $1, ret+24(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT,$0-17
MOVL a+0(FP), SI
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT,$0-25
- MOVW a_len+4(FP), R1
- MOVW b_len+16(FP), R3
- CMP R1, R3 // unequal lengths are not equal
- B.NE notequal
- CMP $0, R1 // short path to handle 0-byte case
- B.EQ equal
-
- MOVW a_base+0(FP), R0
- MOVW b_base+12(FP), R2
- MOVW $ret+24(FP), R7
- B memeqbody<>(SB)
-equal:
- MOVW $1, R0
- MOVB R0, ret+24(FP)
- RET
-notequal:
- MOVW $0, R0
- MOVBU R0, ret+24(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-13
MOVW a+0(FP), R0
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT,$0-49
- MOVD a_len+8(FP), R1
- MOVD b_len+32(FP), R3
- CMP R1, R3
- // unequal lengths are not equal
- BNE not_equal
- // short path to handle 0-byte case
- CBZ R1, equal
- MOVD a_base+0(FP), R0
- MOVD b_base+24(FP), R2
- MOVD $ret+48(FP), R8
- B memeqbody<>(SB)
-equal:
- MOVD $1, R0
- MOVB R0, ret+48(FP)
- RET
-not_equal:
- MOVB ZR, ret+48(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVD size+16(FP), R1
--- /dev/null
+// Copyright 2019 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 bytealg
+
+// Equal reports whether a and b
+// are the same length and contain the same bytes.
+// A nil argument is equivalent to an empty slice.
+//
+// Equal is equivalent to bytes.Equal.
+// It is provided here for convenience,
+// because some packages cannot depend on bytes.
+func Equal(a, b []byte) bool {
+ // Neither cmd/compile nor gccgo allocates for these string conversions.
+ // There is a test for this in package bytes.
+ return string(a) == string(b)
+}
#define REGCTXT R22
-TEXT ·Equal(SB),NOSPLIT,$0-49
- MOVV a_len+8(FP), R3
- MOVV b_len+32(FP), R4
- BNE R3, R4, noteq // unequal lengths are not equal
-
- MOVV a_base+0(FP), R1
- MOVV b_base+24(FP), R2
- ADDV R1, R3 // end
-
-loop:
- BEQ R1, R3, equal // reached the end
- MOVBU (R1), R6
- ADDV $1, R1
- MOVBU (R2), R7
- ADDV $1, R2
- BEQ R6, R7, loop
-
-noteq:
- MOVB R0, ret+48(FP)
- RET
-
-equal:
- MOVV $1, R1
- MOVB R1, ret+48(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVV a+0(FP), R1
#define REGCTXT R22
-TEXT ·Equal(SB),NOSPLIT,$0-25
- MOVW a_len+4(FP), R3
- MOVW b_len+16(FP), R4
- BNE R3, R4, noteq // unequal lengths are not equal
-
- MOVW a_base+0(FP), R1
- MOVW b_base+12(FP), R2
- ADDU R1, R3 // end
-
-loop:
- BEQ R1, R3, equal // reached the end
- MOVBU (R1), R6
- ADDU $1, R1
- MOVBU (R2), R7
- ADDU $1, R2
- BEQ R6, R7, loop
-
-noteq:
- MOVB R0, ret+24(FP)
- RET
-
-equal:
- MOVW $1, R1
- MOVB R1, ret+24(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT,$0-13
MOVW a+0(FP), R1
import "unsafe"
-// Note: there's no equal_generic.go because every platform must implement at least memequal_varlen in assembly.
-
-//go:noescape
-func Equal(a, b []byte) bool
-
// The declarations below generate ABI wrappers for functions
// implemented in assembly in this package but declared in another
// package.
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT|NOFRAME,$0-49
- MOVD a_len+8(FP), R4
- MOVD b_len+32(FP), R5
- CMP R5, R4 // unequal lengths are not equal
- BNE noteq
- MOVD a_base+0(FP), R3
- MOVD b_base+24(FP), R4
- MOVD $ret+48(FP), R10
- BR memeqbody<>(SB)
-
-noteq:
- MOVBZ $0,ret+48(FP)
- RET
-
-equal:
- MOVD $1,R3
- MOVBZ R3,ret+48(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVD a+0(FP), R3
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB),NOSPLIT|NOFRAME,$0-49
- MOVD a_len+8(FP), R2
- MOVD b_len+32(FP), R6
- MOVD a_base+0(FP), R3
- MOVD b_base+24(FP), R5
- LA ret+48(FP), R7
- CMPBNE R2, R6, notequal
- BR memeqbody<>(SB)
-notequal:
- MOVB $0, ret+48(FP)
- RET
-
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVD a+0(FP), R3
#include "go_asm.h"
#include "textflag.h"
-TEXT ·Equal(SB), NOSPLIT, $0-49
- MOVD a_len+8(FP), R0
- MOVD b_len+32(FP), R1
- Get R0
- Get R1
- I64Eq
- If
- Get SP
- I64Load a+0(FP)
- I64Load b+24(FP)
- Get R0
- Call memeqbody<>(SB)
- I64Store8 ret+48(FP)
- Else
- Get SP
- I64Const $0
- I64Store8 ret+48(FP)
- End
- RET
-
// memequal(p, q unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB), NOSPLIT, $0-25
Get SP