• 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 {
operator <<(std::ostream & o,StringPiece piece)42 std::ostream& operator<<(std::ostream& o, StringPiece piece) {
43   o.write(piece.data(), piece.size());
44   return o;
45 }
46 
47 // Out-of-line error path.
LogFatalSizeTooBig(size_t size,const char * details)48 void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
49   GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
50 }
51 
StringPiece(StringPiece x,stringpiece_ssize_type pos)52 StringPiece::StringPiece(StringPiece x, stringpiece_ssize_type pos)
53     : ptr_(x.ptr_ + pos), length_(x.length_ - pos) {
54   GOOGLE_DCHECK_LE(0, pos);
55   GOOGLE_DCHECK_LE(pos, x.length_);
56 }
57 
StringPiece(StringPiece x,stringpiece_ssize_type pos,stringpiece_ssize_type len)58 StringPiece::StringPiece(StringPiece x,
59                          stringpiece_ssize_type pos,
60                          stringpiece_ssize_type len)
61     : ptr_(x.ptr_ + pos), length_(std::min(len, x.length_ - pos)) {
62   GOOGLE_DCHECK_LE(0, pos);
63   GOOGLE_DCHECK_LE(pos, x.length_);
64   GOOGLE_DCHECK_GE(len, 0);
65 }
66 
CopyToString(string * target) const67 void StringPiece::CopyToString(string* target) const {
68   target->assign(ptr_, length_);
69 }
70 
AppendToString(string * target) const71 void StringPiece::AppendToString(string* target) const {
72   target->append(ptr_, length_);
73 }
74 
Consume(StringPiece x)75 bool StringPiece::Consume(StringPiece x) {
76   if (starts_with(x)) {
77     ptr_ += x.length_;
78     length_ -= x.length_;
79     return true;
80   }
81   return false;
82 }
83 
ConsumeFromEnd(StringPiece x)84 bool StringPiece::ConsumeFromEnd(StringPiece x) {
85   if (ends_with(x)) {
86     length_ -= x.length_;
87     return true;
88   }
89   return false;
90 }
91 
copy(char * buf,size_type n,size_type pos) const92 stringpiece_ssize_type StringPiece::copy(char* buf,
93                                          size_type n,
94                                          size_type pos) const {
95   stringpiece_ssize_type ret = std::min(length_ - pos, n);
96   memcpy(buf, ptr_ + pos, ret);
97   return ret;
98 }
99 
contains(StringPiece s) const100 bool StringPiece::contains(StringPiece s) const {
101   return find(s, 0) != npos;
102 }
103 
find(StringPiece s,size_type pos) const104 stringpiece_ssize_type StringPiece::find(StringPiece s, size_type pos) const {
105   if (length_ <= 0 || pos > static_cast<size_type>(length_)) {
106     if (length_ == 0 && pos == 0 && s.length_ == 0) return 0;
107     return npos;
108   }
109   const char *result = std::search(ptr_ + pos, ptr_ + length_,
110                                    s.ptr_, s.ptr_ + s.length_);
111   return result == ptr_ + length_ ? npos : result - ptr_;
112 }
113 
find(char c,size_type pos) const114 stringpiece_ssize_type StringPiece::find(char c, size_type pos) const {
115   if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
116     return npos;
117   }
118   const char* result = static_cast<const char*>(
119       memchr(ptr_ + pos, c, length_ - pos));
120   return result != nullptr ? result - ptr_ : npos;
121 }
122 
rfind(StringPiece s,size_type pos) const123 stringpiece_ssize_type StringPiece::rfind(StringPiece s, size_type pos) const {
124   if (length_ < s.length_) return npos;
125   const size_t ulen = length_;
126   if (s.length_ == 0) return std::min(ulen, pos);
127 
128   const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
129   const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
130   return result != last ? result - ptr_ : npos;
131 }
132 
133 // Search range is [0..pos] inclusive.  If pos == npos, search everything.
rfind(char c,size_type pos) const134 stringpiece_ssize_type StringPiece::rfind(char c, size_type pos) const {
135   // Note: memrchr() is not available on Windows.
136   if (length_ <= 0) return npos;
137   for (stringpiece_ssize_type i =
138       std::min(pos, static_cast<size_type>(length_ - 1));
139        i >= 0; --i) {
140     if (ptr_[i] == c) {
141       return i;
142     }
143   }
144   return npos;
145 }
146 
147 // For each character in characters_wanted, sets the index corresponding
148 // to the ASCII code of that character to 1 in table.  This is used by
149 // the find_.*_of methods below to tell whether or not a character is in
150 // the lookup table in constant time.
151 // The argument `table' must be an array that is large enough to hold all
152 // the possible values of an unsigned char.  Thus it should be be declared
153 // as follows:
154 //   bool table[UCHAR_MAX + 1]
BuildLookupTable(StringPiece characters_wanted,bool * table)155 static inline void BuildLookupTable(StringPiece characters_wanted,
156                                     bool* table) {
157   const stringpiece_ssize_type length = characters_wanted.length();
158   const char* const data = characters_wanted.data();
159   for (stringpiece_ssize_type i = 0; i < length; ++i) {
160     table[static_cast<unsigned char>(data[i])] = true;
161   }
162 }
163 
find_first_of(StringPiece s,size_type pos) const164 stringpiece_ssize_type StringPiece::find_first_of(StringPiece s,
165                                                   size_type pos) const {
166   if (length_ <= 0 || s.length_ <= 0) {
167     return npos;
168   }
169   // Avoid the cost of BuildLookupTable() for a single-character search.
170   if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
171 
172   bool lookup[UCHAR_MAX + 1] = { false };
173   BuildLookupTable(s, lookup);
174   for (stringpiece_ssize_type i = pos; i < length_; ++i) {
175     if (lookup[static_cast<unsigned char>(ptr_[i])]) {
176       return i;
177     }
178   }
179   return npos;
180 }
181 
find_first_not_of(StringPiece s,size_type pos) const182 stringpiece_ssize_type StringPiece::find_first_not_of(StringPiece s,
183                                                       size_type pos) const {
184   if (length_ <= 0) return npos;
185   if (s.length_ <= 0) return 0;
186   // Avoid the cost of BuildLookupTable() for a single-character search.
187   if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
188 
189   bool lookup[UCHAR_MAX + 1] = { false };
190   BuildLookupTable(s, lookup);
191   for (stringpiece_ssize_type i = pos; i < length_; ++i) {
192     if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
193       return i;
194     }
195   }
196   return npos;
197 }
198 
find_first_not_of(char c,size_type pos) const199 stringpiece_ssize_type StringPiece::find_first_not_of(char c,
200                                                       size_type pos) const {
201   if (length_ <= 0) return npos;
202 
203   for (; pos < static_cast<size_type>(length_); ++pos) {
204     if (ptr_[pos] != c) {
205       return pos;
206     }
207   }
208   return npos;
209 }
210 
find_last_of(StringPiece s,size_type pos) const211 stringpiece_ssize_type StringPiece::find_last_of(StringPiece s,
212                                                  size_type pos) const {
213   if (length_ <= 0 || s.length_ <= 0) return npos;
214   // Avoid the cost of BuildLookupTable() for a single-character search.
215   if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
216 
217   bool lookup[UCHAR_MAX + 1] = { false };
218   BuildLookupTable(s, lookup);
219   for (stringpiece_ssize_type i =
220        std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
221     if (lookup[static_cast<unsigned char>(ptr_[i])]) {
222       return i;
223     }
224   }
225   return npos;
226 }
227 
find_last_not_of(StringPiece s,size_type pos) const228 stringpiece_ssize_type StringPiece::find_last_not_of(StringPiece s,
229                                                      size_type pos) const {
230   if (length_ <= 0) return npos;
231 
232   stringpiece_ssize_type i = std::min(pos, static_cast<size_type>(length_ - 1));
233   if (s.length_ <= 0) return i;
234 
235   // Avoid the cost of BuildLookupTable() for a single-character search.
236   if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
237 
238   bool lookup[UCHAR_MAX + 1] = { false };
239   BuildLookupTable(s, lookup);
240   for (; i >= 0; --i) {
241     if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
242       return i;
243     }
244   }
245   return npos;
246 }
247 
find_last_not_of(char c,size_type pos) const248 stringpiece_ssize_type StringPiece::find_last_not_of(char c,
249                                                      size_type pos) const {
250   if (length_ <= 0) return npos;
251 
252   for (stringpiece_ssize_type i =
253        std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
254     if (ptr_[i] != c) {
255       return i;
256     }
257   }
258   return npos;
259 }
260 
substr(size_type pos,size_type n) const261 StringPiece StringPiece::substr(size_type pos, size_type n) const {
262   if (pos > length_) pos = length_;
263   if (n > length_ - pos) n = length_ - pos;
264   return StringPiece(ptr_ + pos, n);
265 }
266 
267 const StringPiece::size_type StringPiece::npos = size_type(-1);
268 
269 }  // namespace protobuf
270 }  // namespace google
271