From 2a166c93a3d2a7ba73e129649b7b41b6c696e74a Mon Sep 17 00:00:00 2001
From: Russ Cox <rsc@golang.org>
Date: Mon, 13 Nov 2017 21:30:22 -0500
Subject: [PATCH] bytes, strings: restore O(1) behavior of IndexAny(s, "") and
 LastIndexAny(s, "")
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

CL 65851 (bytes) and CL 65910 (strings) “improve[d] readability”
by removing the special case that bypassed the whole function body
when chars == "". In doing so, yes, the function was unindented a
level, which is nice, but the runtime of that case went from O(1) to O(n)
where n = len(s).

I don't know if anyone's code depends on the O(1) behavior in this case,
but quite possibly someone's does.

This CL adds the special case back, with a comment to prevent future
deletions, and without reindenting each function body in full.

Change-Id: I5aba33922b304dd1b8657e6d51d6c937a7f95c81
Reviewed-on: https://go-review.googlesource.com/78112
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
---
 src/bytes/bytes.go        | 8 ++++++++
 src/bytes/example_test.go | 2 +-
 src/strings/strings.go    | 8 ++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 260f32500a0..9af177fa882 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -144,6 +144,10 @@ func IndexRune(s []byte, r rune) int {
 // code points in chars. It returns -1 if chars is empty or if there is no code
 // point in common.
 func IndexAny(s []byte, chars string) int {
+	if chars == "" {
+		// Avoid scanning all of s.
+		return -1
+	}
 	if len(s) > 8 {
 		if as, isASCII := makeASCIISet(chars); isASCII {
 			for i, c := range s {
@@ -176,6 +180,10 @@ func IndexAny(s []byte, chars string) int {
 // the Unicode code points in chars. It returns -1 if chars is empty or if
 // there is no code point in common.
 func LastIndexAny(s []byte, chars string) int {
+	if chars == "" {
+		// Avoid scanning all of s.
+		return -1
+	}
 	if len(s) > 8 {
 		if as, isASCII := makeASCIISet(chars); isASCII {
 			for i := len(s) - 1; i >= 0; i-- {
diff --git a/src/bytes/example_test.go b/src/bytes/example_test.go
index 00e39cadcbe..5b7a46058f5 100644
--- a/src/bytes/example_test.go
+++ b/src/bytes/example_test.go
@@ -155,7 +155,7 @@ func ExampleCount() {
 
 func ExampleEqual() {
 	fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
-	fmt.Println(bytes.Equal([]byte("Go"), []byte("go")))
+	fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))
 	// Output:
 	// true
 	// false
diff --git a/src/strings/strings.go b/src/strings/strings.go
index c66c248c023..02c032046b7 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -166,6 +166,10 @@ func IndexRune(s string, r rune) int {
 // IndexAny returns the index of the first instance of any Unicode code point
 // from chars in s, or -1 if no Unicode code point from chars is present in s.
 func IndexAny(s, chars string) int {
+	if chars == "" {
+		// Avoid scanning all of s.
+		return -1
+	}
 	if len(s) > 8 {
 		if as, isASCII := makeASCIISet(chars); isASCII {
 			for i := 0; i < len(s); i++ {
@@ -190,6 +194,10 @@ func IndexAny(s, chars string) int {
 // point from chars in s, or -1 if no Unicode code point from chars is
 // present in s.
 func LastIndexAny(s, chars string) int {
+	if chars == "" {
+		// Avoid scanning all of s.
+		return -1
+	}
 	if len(s) > 8 {
 		if as, isASCII := makeASCIISet(chars); isASCII {
 			for i := len(s) - 1; i >= 0; i-- {
-- 
GitLab