• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <google/protobuf/stubs/stringpiece.h>
31 
32 #include <string.h>
33 #include <algorithm>
34 #include <climits>
35 #include <string>
36 #include <ostream>
37 
38 #include <google/protobuf/stubs/logging.h>
39 
40 namespace google {
41 namespace protobuf {
42 namespace stringpiece_internal {
43 
operator <<(std::ostream & o,StringPiece piece)44 std::ostream& operator<<(std::ostream& o, StringPiece piece) {
45   o.write(piece.data(), piece.size());
46   return o;
47 }
48 
LogFatalSizeTooBig(size_t size,const char * details)49 void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
50   GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
51 }
52 
CopyToString(std::string * target) const53 void StringPiece::CopyToString(std::string* target) const {
54   target->assign(ptr_, length_);
55 }
56 
AppendToString(std::string * target) const57 void StringPiece::AppendToString(std::string* target) const {
58   target->append(ptr_, length_);
59 }
60 
Consume(StringPiece x)61 bool StringPiece::Consume(StringPiece x) {
62   if (starts_with(x)) {
63     ptr_ += x.length_;
64     length_ -= x.length_;
65     return true;
66   }
67   return false;
68 }
69 
ConsumeFromEnd(StringPiece x)70 bool StringPiece::ConsumeFromEnd(StringPiece x) {
71   if (ends_with(x)) {
72     length_ -= x.length_;
73     return true;
74   }
75   return false;
76 }
77 
copy(char * buf,size_type n,size_type pos) const78 StringPiece::size_type StringPiece::copy(char* buf, size_type n,
79                                          size_type pos) const {
80   size_type ret = std::min(length_ - pos, n);
81   memcpy(buf, ptr_ + pos, ret);
82   return ret;
83 }
84 
contains(StringPiece s) const85 bool StringPiece::contains(StringPiece s) const {
86   return find(s, 0) != npos;
87 }
88 
find(StringPiece s,size_type pos) const89 StringPiece::size_type StringPiece::find(StringPiece s, size_type pos) const {
90   if (length_ <= 0 || pos > static_cast<size_type>(length_)) {
91     if (length_ == 0 && pos == 0 && s.length_ == 0) return 0;
92     return npos;
93   }
94   const char *result = std::search(ptr_ + pos, ptr_ + length_,
95                                    s.ptr_, s.ptr_ + s.length_);
96   return result == ptr_ + length_ ? npos : result - ptr_;
97 }
98 
find(char c,size_type pos) const99 StringPiece::size_type StringPiece::find(char c, size_type pos) const {
100   if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
101     return npos;
102   }
103   const char* result = static_cast<const char*>(
104       memchr(ptr_ + pos, c, length_ - pos));
105   return result != nullptr ? result - ptr_ : npos;
106 }
107 
rfind(StringPiece s,size_type pos) const108 StringPiece::size_type StringPiece::rfind(StringPiece s, size_type pos) const {
109   if (length_ < s.length_) return npos;
110   const size_t ulen = length_;
111   if (s.length_ == 0) return std::min(ulen, pos);
112 
113   const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
114   const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
115   return result != last ? result - ptr_ : npos;
116 }
117 
118 // Search range is [0..pos] inclusive.  If pos == npos, search everything.
rfind(char c,size_type pos) const119 StringPiece::size_type StringPiece::rfind(char c, size_type pos) const {
120   // Note: memrchr() is not available on Windows.
121   if (empty()) return npos;
122   for (size_type i = std::min(pos, length_ - 1);; --i) {
123     if (ptr_[i] == c) {
124       return i;
125     }
126     if (i == 0) break;
127   }
128   return npos;
129 }
130 
131 // For each character in characters_wanted, sets the index corresponding
132 // to the ASCII code of that character to 1 in table.  This is used by
133 // the find_.*_of methods below to tell whether or not a character is in
134 // the lookup table in constant time.
135 // The argument `table' must be an array that is large enough to hold all
136 // the possible values of an unsigned char.  Thus it should be be declared
137 // as follows:
138 //   bool table[UCHAR_MAX + 1]
BuildLookupTable(StringPiece characters_wanted,bool * table)139 static inline void BuildLookupTable(StringPiece characters_wanted,
140                                     bool* table) {
141   const StringPiece::size_type length = characters_wanted.length();
142   const char* const data = characters_wanted.data();
143   for (StringPiece::size_type i = 0; i < length; ++i) {
144     table[static_cast<unsigned char>(data[i])] = true;
145   }
146 }
147 
find_first_of(StringPiece s,size_type pos) const148 StringPiece::size_type StringPiece::find_first_of(StringPiece s,
149                                                   size_type pos) const {
150   if (empty() || s.empty()) {
151     return npos;
152   }
153   // Avoid the cost of BuildLookupTable() for a single-character search.
154   if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
155 
156   bool lookup[UCHAR_MAX + 1] = { false };
157   BuildLookupTable(s, lookup);
158   for (size_type i = pos; i < length_; ++i) {
159     if (lookup[static_cast<unsigned char>(ptr_[i])]) {
160       return i;
161     }
162   }
163   return npos;
164 }
165 
find_first_not_of(StringPiece s,size_type pos) const166 StringPiece::size_type StringPiece::find_first_not_of(StringPiece s,
167                                                       size_type pos) const {
168   if (empty()) return npos;
169   if (s.empty()) return 0;
170   // Avoid the cost of BuildLookupTable() for a single-character search.
171   if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
172 
173   bool lookup[UCHAR_MAX + 1] = { false };
174   BuildLookupTable(s, lookup);
175   for (size_type i = pos; i < length_; ++i) {
176     if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
177       return i;
178     }
179   }
180   return npos;
181 }
182 
find_first_not_of(char c,size_type pos) const183 StringPiece::size_type StringPiece::find_first_not_of(char c,
184                                                       size_type pos) const {
185   if (empty()) return npos;
186 
187   for (; pos < static_cast<size_type>(length_); ++pos) {
188     if (ptr_[pos] != c) {
189       return pos;
190     }
191   }
192   return npos;
193 }
194 
find_last_of(StringPiece s,size_type pos) const195 StringPiece::size_type StringPiece::find_last_of(StringPiece s,
196                                                  size_type pos) const {
197   if (empty() || s.empty()) return npos;
198   // Avoid the cost of BuildLookupTable() for a single-character search.
199   if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
200 
201   bool lookup[UCHAR_MAX + 1] = { false };
202   BuildLookupTable(s, lookup);
203   for (size_type i = std::min(pos, length_ - 1);; --i) {
204     if (lookup[static_cast<unsigned char>(ptr_[i])]) {
205       return i;
206     }
207     if (i == 0) break;
208   }
209   return npos;
210 }
211 
find_last_not_of(StringPiece s,size_type pos) const212 StringPiece::size_type StringPiece::find_last_not_of(StringPiece s,
213                                                      size_type pos) const {
214   if (empty()) return npos;
215 
216   size_type i = std::min(pos, length() - 1);
217   if (s.empty()) return i;
218 
219   // Avoid the cost of BuildLookupTable() for a single-character search.
220   if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
221 
222   bool lookup[UCHAR_MAX + 1] = { false };
223   BuildLookupTable(s, lookup);
224   for (;; --i) {
225     if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
226       return i;
227     }
228     if (i == 0) break;
229   }
230   return npos;
231 }
232 
find_last_not_of(char c,size_type pos) const233 StringPiece::size_type StringPiece::find_last_not_of(char c,
234                                                      size_type pos) const {
235   if (empty()) return npos;
236   size_type i = std::min(pos, length_ - 1);
237   for (;; --i) {
238     if (ptr_[i] != c) {
239       return i;
240     }
241     if (i == 0) break;
242   }
243   return npos;
244 }
245 
substr(size_type pos,size_type n) const246 StringPiece StringPiece::substr(size_type pos, size_type n) const {
247   if (pos > length()) pos = length();
248   if (n > length_ - pos) n = length() - pos;
249   return StringPiece(ptr_ + pos, n);
250 }
251 
252 const StringPiece::size_type StringPiece::npos = size_type(-1);
253 
254 }  // namespace stringpiece_internal
255 }  // namespace protobuf
256 }  // namespace google
257