Search for needle in haystack. Returns the offset into str if the needle exists Returns -1 if the needle is not found str will be temporarily modified for the duration of the function
| 56 | /// Returns -1 if the needle is not found |
| 57 | /// str will be temporarily modified for the duration of the function |
| 58 | int Search(const StringValue& haystack) const { |
| 59 | // Edge cases |
| 60 | StringValue::SimpleString haystack_s = haystack.ToSimpleString(); |
| 61 | if (UNLIKELY(haystack_s.len == 0 && needle_len_ == 0)) return 0; |
| 62 | if (UNLIKELY(haystack_s.len == 0)) return -1; |
| 63 | if (UNLIKELY(needle_len_ == 0)) return 0; |
| 64 | if (UNLIKELY(haystack_s.len < needle_len_)) return -1; |
| 65 | |
| 66 | int result = -1; |
| 67 | |
| 68 | // temporarily null terminated input string |
| 69 | char last_char_haystack = haystack_s.ptr[haystack_s.len - 1]; |
| 70 | haystack_s.ptr[haystack_s.len - 1] = '\0'; |
| 71 | |
| 72 | // Use strchr if needle_len_ is 1 |
| 73 | if (needle_len_ == 1) { |
| 74 | char c = (needle_str_val_ == NULL) ? needle_cstr_[0] : needle_str_val_->Ptr()[0]; |
| 75 | char* s = strchr(haystack_s.ptr, c); |
| 76 | if (s != NULL) { |
| 77 | result = s - haystack_s.ptr; |
| 78 | } else if (last_char_haystack == c) { |
| 79 | result = haystack_s.len - 1; |
| 80 | } |
| 81 | // Undo change to haystack |
| 82 | haystack_s.ptr[haystack_s.len - 1] = last_char_haystack; |
| 83 | return result; |
| 84 | } |
| 85 | |
| 86 | // needle is null terminated. We just need to run strstr on the |
| 87 | // null terminated haystack, and if there is no match, try a match |
| 88 | // on the last needle_len chars. |
| 89 | if (LIKELY(needle_cstr_ != NULL)) { |
| 90 | char* s = strstr(haystack_s.ptr, needle_cstr_); |
| 91 | // Undo change to haystack |
| 92 | haystack_s.ptr[haystack_s.len - 1] = last_char_haystack; |
| 93 | |
| 94 | if (s != NULL) { |
| 95 | result = s - haystack_s.ptr; |
| 96 | } else { |
| 97 | // If we didn't find a match, try the last needle->len chars |
| 98 | char* end = haystack_s.ptr + haystack_s.len - needle_len_; |
| 99 | bool match = true; |
| 100 | for (int i = 0; i < needle_len_; ++i) { |
| 101 | if (LIKELY(end[i] != needle_cstr_[i])) { |
| 102 | match = false; |
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | if (UNLIKELY(match)) result = haystack_s.len - needle_len_; |
| 107 | } |
| 108 | return result; |
| 109 | } else { |
| 110 | // Needle is not null terminated. Terminate it on the fly. |
| 111 | const char last_char_needle = needle_str_val_->Ptr()[needle_len_ - 1]; |
| 112 | needle_str_val_->Ptr()[needle_len_ - 1] = '\0'; |
| 113 | |
| 114 | int offset = 0; |
| 115 | char* haystack_pos = haystack_s.ptr; |