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