• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/string_view.h"
16 
17 #ifndef ABSL_USES_STD_STRING_VIEW
18 
19 #include <algorithm>
20 #include <climits>
21 #include <cstring>
22 #include <ostream>
23 
24 namespace absl {
25 ABSL_NAMESPACE_BEGIN
26 
27 namespace {
28 
29 // This is significantly faster for case-sensitive matches with very
30 // few possible matches.
memmatch(const char * phaystack,size_t haylen,const char * pneedle,size_t neelen)31 const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
32                      size_t neelen) {
33   if (0 == neelen) {
34     return phaystack;  // even if haylen is 0
35   }
36   if (haylen < neelen) return nullptr;
37 
38   const char* match;
39   const char* hayend = phaystack + haylen - neelen + 1;
40   // A static cast is used here to work around the fact that memchr returns
41   // a void* on Posix-compliant systems and const void* on Windows.
42   while (
43       (match = static_cast<const char*>(memchr(
44            phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) {
45     if (memcmp(match, pneedle, neelen) == 0)
46       return match;
47     else
48       phaystack = match + 1;
49   }
50   return nullptr;
51 }
52 
WritePadding(std::ostream & o,size_t pad)53 void WritePadding(std::ostream& o, size_t pad) {
54   char fill_buf[32];
55   memset(fill_buf, o.fill(), sizeof(fill_buf));
56   while (pad) {
57     size_t n = std::min(pad, sizeof(fill_buf));
58     o.write(fill_buf, static_cast<std::streamsize>(n));
59     pad -= n;
60   }
61 }
62 
63 class LookupTable {
64  public:
65   // For each character in wanted, sets the index corresponding
66   // to the ASCII code of that character. This is used by
67   // the find_.*_of methods below to tell whether or not a character is in
68   // the lookup table in constant time.
LookupTable(string_view wanted)69   explicit LookupTable(string_view wanted) {
70     for (char c : wanted) {
71       table_[Index(c)] = true;
72     }
73   }
operator [](char c) const74   bool operator[](char c) const { return table_[Index(c)]; }
75 
76  private:
Index(char c)77   static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
78   bool table_[UCHAR_MAX + 1] = {};
79 };
80 
81 }  // namespace
82 
operator <<(std::ostream & o,string_view piece)83 std::ostream& operator<<(std::ostream& o, string_view piece) {
84   std::ostream::sentry sentry(o);
85   if (sentry) {
86     size_t lpad = 0;
87     size_t rpad = 0;
88     if (static_cast<size_t>(o.width()) > piece.size()) {
89       size_t pad = static_cast<size_t>(o.width()) - piece.size();
90       if ((o.flags() & o.adjustfield) == o.left) {
91         rpad = pad;
92       } else {
93         lpad = pad;
94       }
95     }
96     if (lpad) WritePadding(o, lpad);
97     o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
98     if (rpad) WritePadding(o, rpad);
99     o.width(0);
100   }
101   return o;
102 }
103 
find(string_view s,size_type pos) const104 string_view::size_type string_view::find(string_view s,
105                                          size_type pos) const noexcept {
106   if (empty() || pos > length_) {
107     if (empty() && pos == 0 && s.empty()) return 0;
108     return npos;
109   }
110   const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
111   return result ? static_cast<size_type>(result - ptr_) : npos;
112 }
113 
find(char c,size_type pos) const114 string_view::size_type string_view::find(char c, size_type pos) const noexcept {
115   if (empty() || pos >= length_) {
116     return npos;
117   }
118   const char* result =
119       static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
120   return result != nullptr ? static_cast<size_type>(result - ptr_) : npos;
121 }
122 
rfind(string_view s,size_type pos) const123 string_view::size_type string_view::rfind(string_view s,
124                                           size_type pos) const noexcept {
125   if (length_ < s.length_) return npos;
126   if (s.empty()) return std::min(length_, pos);
127   const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
128   const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
129   return result != last ? static_cast<size_type>(result - ptr_) : npos;
130 }
131 
132 // Search range is [0..pos] inclusive.  If pos == npos, search everything.
rfind(char c,size_type pos) const133 string_view::size_type string_view::rfind(char c,
134                                           size_type pos) const noexcept {
135   // Note: memrchr() is not available on Windows.
136   if (empty()) return npos;
137   for (size_type i = std::min(pos, length_ - 1);; --i) {
138     if (ptr_[i] == c) {
139       return i;
140     }
141     if (i == 0) break;
142   }
143   return npos;
144 }
145 
find_first_of(string_view s,size_type pos) const146 string_view::size_type string_view::find_first_of(
147     string_view s, size_type pos) const noexcept {
148   if (empty() || s.empty()) {
149     return npos;
150   }
151   // Avoid the cost of LookupTable() for a single-character search.
152   if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
153   LookupTable tbl(s);
154   for (size_type i = pos; i < length_; ++i) {
155     if (tbl[ptr_[i]]) {
156       return i;
157     }
158   }
159   return npos;
160 }
161 
find_first_not_of(string_view s,size_type pos) const162 string_view::size_type string_view::find_first_not_of(
163     string_view s, size_type pos) const noexcept {
164   if (empty()) return npos;
165   // Avoid the cost of LookupTable() for a single-character search.
166   if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
167   LookupTable tbl(s);
168   for (size_type i = pos; i < length_; ++i) {
169     if (!tbl[ptr_[i]]) {
170       return i;
171     }
172   }
173   return npos;
174 }
175 
find_first_not_of(char c,size_type pos) const176 string_view::size_type string_view::find_first_not_of(
177     char c, size_type pos) const noexcept {
178   if (empty()) return npos;
179   for (; pos < length_; ++pos) {
180     if (ptr_[pos] != c) {
181       return pos;
182     }
183   }
184   return npos;
185 }
186 
find_last_of(string_view s,size_type pos) const187 string_view::size_type string_view::find_last_of(string_view s,
188                                                  size_type pos) const noexcept {
189   if (empty() || s.empty()) return npos;
190   // Avoid the cost of LookupTable() for a single-character search.
191   if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
192   LookupTable tbl(s);
193   for (size_type i = std::min(pos, length_ - 1);; --i) {
194     if (tbl[ptr_[i]]) {
195       return i;
196     }
197     if (i == 0) break;
198   }
199   return npos;
200 }
201 
find_last_not_of(string_view s,size_type pos) const202 string_view::size_type string_view::find_last_not_of(
203     string_view s, size_type pos) const noexcept {
204   if (empty()) return npos;
205   size_type i = std::min(pos, length_ - 1);
206   if (s.empty()) return i;
207   // Avoid the cost of LookupTable() for a single-character search.
208   if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
209   LookupTable tbl(s);
210   for (;; --i) {
211     if (!tbl[ptr_[i]]) {
212       return i;
213     }
214     if (i == 0) break;
215   }
216   return npos;
217 }
218 
find_last_not_of(char c,size_type pos) const219 string_view::size_type string_view::find_last_not_of(
220     char c, size_type pos) const noexcept {
221   if (empty()) return npos;
222   size_type i = std::min(pos, length_ - 1);
223   for (;; --i) {
224     if (ptr_[i] != c) {
225       return i;
226     }
227     if (i == 0) break;
228   }
229   return npos;
230 }
231 
232 
233 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
234 constexpr string_view::size_type string_view::npos;
235 constexpr string_view::size_type string_view::kMaxSize;
236 #endif
237 
238 ABSL_NAMESPACE_END
239 }  // namespace absl
240 
241 #endif  // ABSL_USES_STD_STRING_VIEW
242