1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4// Copied from strings/stringpiece.cc with modifications
5
6#include <algorithm>
7#include <ostream>
8
9#include "phonenumbers/base/strings/string_piece.h"
10
11namespace i18n {
12namespace phonenumbers {
13
14typedef StringPiece::size_type size_type;
15
16std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
17  o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
18  return o;
19}
20
21bool operator==(const StringPiece& x, const StringPiece& y) {
22  if (x.size() != y.size())
23    return false;
24
25  return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
26}
27
28void StringPiece::CopyToString(std::string* target) const {
29  target->assign(!empty() ? data() : "", size());
30}
31
32void StringPiece::AppendToString(std::string* target) const {
33  if (!empty())
34    target->append(data(), size());
35}
36
37size_type StringPiece::copy(char* buf, size_type n, size_type pos) const {
38  if (pos > length_) {
39    return 0;
40  }
41
42  size_type ret = std::min(length_ - pos, n);
43  memcpy(buf, ptr_ + pos, ret);
44  return ret;
45}
46
47size_type StringPiece::find(const StringPiece& s, size_type pos) const {
48  if (pos > length_)
49    return npos;
50
51  const char* result = std::search(ptr_ + pos, ptr_ + length_,
52                                   s.ptr_, s.ptr_ + s.length_);
53  const size_type xpos = result - ptr_;
54  return xpos + s.length_ <= length_ ? xpos : npos;
55}
56
57size_type StringPiece::find(char c, size_type pos) const {
58  if (pos >= length_)
59    return npos;
60
61  const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
62  return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos;
63}
64
65size_type StringPiece::rfind(const StringPiece& s, size_type pos) const {
66  if (length_ < s.length_)
67    return npos;
68
69  if (s.empty())
70    return std::min(length_, pos);
71
72  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
73  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
74  return result != last ? static_cast<size_t>(result - ptr_) : npos;
75}
76
77size_type StringPiece::rfind(char c, size_type pos) const {
78  if (length_ == 0)
79    return npos;
80
81  for (size_type i = std::min(pos, length_ - 1); ; --i) {
82    if (ptr_[i] == c)
83      return i;
84    if (i == 0)
85      break;
86  }
87  return npos;
88}
89
90// For each character in characters_wanted, sets the index corresponding
91// to the ASCII code of that character to 1 in table.  This is used by
92// the find_.*_of methods below to tell whether or not a character is in
93// the lookup table in constant time.
94// The argument `table' must be an array that is large enough to hold all
95// the possible values of an unsigned char.  Thus it should be be declared
96// as follows:
97//   bool table[UCHAR_MAX + 1]
98static inline void BuildLookupTable(const StringPiece& characters_wanted,
99                                    bool* table) {
100  const size_type length = characters_wanted.length();
101  const char* const data = characters_wanted.data();
102  for (size_type i = 0; i < length; ++i) {
103    table[static_cast<unsigned char>(data[i])] = true;
104  }
105}
106
107size_type StringPiece::find_first_of(const StringPiece& s,
108                                     size_type pos) const {
109  if (length_ == 0 || s.length_ == 0)
110    return npos;
111
112  // Avoid the cost of BuildLookupTable() for a single-character search.
113  if (s.length_ == 1)
114    return find_first_of(s.ptr_[0], pos);
115
116  bool lookup[UCHAR_MAX + 1] = { false };
117  BuildLookupTable(s, lookup);
118  for (size_type i = pos; i < length_; ++i) {
119    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
120      return i;
121    }
122  }
123  return npos;
124}
125
126size_type StringPiece::find_first_not_of(const StringPiece& s,
127                                         size_type pos) const {
128  if (length_ == 0)
129    return npos;
130
131  if (s.length_ == 0)
132    return 0;
133
134  // Avoid the cost of BuildLookupTable() for a single-character search.
135  if (s.length_ == 1)
136    return find_first_not_of(s.ptr_[0], pos);
137
138  bool lookup[UCHAR_MAX + 1] = { false };
139  BuildLookupTable(s, lookup);
140  for (size_type i = pos; i < length_; ++i) {
141    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
142      return i;
143    }
144  }
145  return npos;
146}
147
148size_type StringPiece::find_first_not_of(char c, size_type pos) const {
149  if (length_ == 0)
150    return npos;
151
152  for (; pos < length_; ++pos) {
153    if (ptr_[pos] != c) {
154      return pos;
155    }
156  }
157  return npos;
158}
159
160size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const {
161  if (length_ == 0 || s.length_ == 0)
162    return npos;
163
164  // Avoid the cost of BuildLookupTable() for a single-character search.
165  if (s.length_ == 1)
166    return find_last_of(s.ptr_[0], pos);
167
168  bool lookup[UCHAR_MAX + 1] = { false };
169  BuildLookupTable(s, lookup);
170  for (size_type i = std::min(pos, length_ - 1); ; --i) {
171    if (lookup[static_cast<unsigned char>(ptr_[i])])
172      return i;
173    if (i == 0)
174      break;
175  }
176  return npos;
177}
178
179size_type StringPiece::find_last_not_of(const StringPiece& s,
180                                        size_type pos) const {
181  if (length_ == 0)
182    return npos;
183
184  size_type i = std::min(pos, length_ - 1);
185  if (s.length_ == 0)
186    return i;
187
188  // Avoid the cost of BuildLookupTable() for a single-character search.
189  if (s.length_ == 1)
190    return find_last_not_of(s.ptr_[0], pos);
191
192  bool lookup[UCHAR_MAX + 1] = { false };
193  BuildLookupTable(s, lookup);
194  for (; ; --i) {
195    if (!lookup[static_cast<unsigned char>(ptr_[i])])
196      return i;
197    if (i == 0)
198      break;
199  }
200  return npos;
201}
202
203size_type StringPiece::find_last_not_of(char c, size_type pos) const {
204  if (length_ == 0)
205    return npos;
206
207  for (size_type i = std::min(pos, length_ - 1); ; --i) {
208    if (ptr_[i] != c)
209      return i;
210    if (i == 0)
211      break;
212  }
213  return npos;
214}
215
216StringPiece StringPiece::substr(size_type pos, size_type n) const {
217  if (pos > length_) pos = length_;
218  if (n > length_ - pos) n = length_ - pos;
219  return StringPiece(ptr_ + pos, n);
220}
221
222const StringPiece::size_type StringPiece::npos = size_type(-1);
223
224}  // namespace phonenumbers
225}  // namespace i18n
226