1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_BASE_STRINGPIECE_H_
18 #define ART_RUNTIME_BASE_STRINGPIECE_H_
19 
20 #include <string.h>
21 #include <string>
22 
23 namespace art {
24 
25 // A string-like object that points to a sized piece of memory.
26 //
27 // Functions or methods may use const StringPiece& parameters to accept either
28 // a "const char*" or a "string" value that will be implicitly converted to
29 // a StringPiece.  The implicit conversion means that it is often appropriate
30 // to include this .h file in other files rather than forward-declaring
31 // StringPiece as would be appropriate for most other Google classes.
32 class StringPiece {
33  public:
34   // standard STL container boilerplate
35   typedef char value_type;
36   typedef const char* pointer;
37   typedef const char& reference;
38   typedef const char& const_reference;
39   typedef size_t size_type;
40   typedef ptrdiff_t difference_type;
41   static constexpr size_type npos = size_type(-1);
42   typedef const char* const_iterator;
43   typedef const char* iterator;
44   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
45   typedef std::reverse_iterator<iterator> reverse_iterator;
46 
47   // We provide non-explicit singleton constructors so users can pass
48   // in a "const char*" or a "string" wherever a "StringPiece" is
49   // expected.
StringPiece()50   StringPiece() : ptr_(nullptr), length_(0) { }
StringPiece(const char * str)51   StringPiece(const char* str)  // NOLINT implicit constructor desired
52     : ptr_(str), length_((str == nullptr) ? 0 : strlen(str)) { }
StringPiece(const std::string & str)53   StringPiece(const std::string& str)  // NOLINT implicit constructor desired
54     : ptr_(str.data()), length_(str.size()) { }
StringPiece(const char * offset,size_t len)55   StringPiece(const char* offset, size_t len) : ptr_(offset), length_(len) { }
56 
57   // data() may return a pointer to a buffer with embedded NULs, and the
58   // returned buffer may or may not be null terminated.  Therefore it is
59   // typically a mistake to pass data() to a routine that expects a NUL
60   // terminated string.
data()61   const char* data() const { return ptr_; }
size()62   size_type size() const { return length_; }
length()63   size_type length() const { return length_; }
empty()64   bool empty() const { return length_ == 0; }
65 
clear()66   void clear() {
67     ptr_ = nullptr;
68     length_ = 0;
69   }
set(const char * data_in,size_type len)70   void set(const char* data_in, size_type len) {
71     ptr_ = data_in;
72     length_ = len;
73   }
set(const char * str)74   void set(const char* str) {
75     ptr_ = str;
76     if (str != nullptr) {
77       length_ = strlen(str);
78     } else {
79       length_ = 0;
80     }
81   }
set(const void * data_in,size_type len)82   void set(const void* data_in, size_type len) {
83     ptr_ = reinterpret_cast<const char*>(data_in);
84     length_ = len;
85   }
86 
87 #if defined(NDEBUG)
88   char operator[](size_type i) const {
89     return ptr_[i];
90   }
91 #else
92   char operator[](size_type i) const;
93 #endif
94 
remove_prefix(size_type n)95   void remove_prefix(size_type n) {
96     ptr_ += n;
97     length_ -= n;
98   }
99 
remove_suffix(size_type n)100   void remove_suffix(size_type n) {
101     length_ -= n;
102   }
103 
104   int compare(const StringPiece& x) const;
105 
as_string()106   std::string as_string() const {
107     return std::string(data(), size());
108   }
109   // We also define ToString() here, since many other string-like
110   // interfaces name the routine that converts to a C++ string
111   // "ToString", and it's confusing to have the method that does that
112   // for a StringPiece be called "as_string()".  We also leave the
113   // "as_string()" method defined here for existing code.
ToString()114   std::string ToString() const {
115     return std::string(data(), size());
116   }
117 
118   void CopyToString(std::string* target) const;
119   void AppendToString(std::string* target) const;
120 
121   // Does "this" start with "x"
starts_with(const StringPiece & x)122   bool starts_with(const StringPiece& x) const {
123     return ((length_ >= x.length_) &&
124             (memcmp(ptr_, x.ptr_, x.length_) == 0));
125   }
126 
127   // Does "this" end with "x"
ends_with(const StringPiece & x)128   bool ends_with(const StringPiece& x) const {
129     return ((length_ >= x.length_) &&
130             (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
131   }
132 
begin()133   iterator begin() const { return ptr_; }
end()134   iterator end() const { return ptr_ + length_; }
rbegin()135   const_reverse_iterator rbegin() const {
136     return const_reverse_iterator(ptr_ + length_);
137   }
rend()138   const_reverse_iterator rend() const {
139     return const_reverse_iterator(ptr_);
140   }
141 
142   size_type copy(char* buf, size_type n, size_type pos = 0) const;
143 
144   size_type find(const StringPiece& s, size_type pos = 0) const;
145   size_type find(char c, size_type pos = 0) const;
146   size_type rfind(const StringPiece& s, size_type pos = npos) const;
147   size_type rfind(char c, size_type pos = npos) const;
148 
149   StringPiece substr(size_type pos, size_type n = npos) const;
150 
Compare(const StringPiece & rhs)151   int Compare(const StringPiece& rhs) const {
152     const int r = memcmp(data(), rhs.data(), std::min(size(), rhs.size()));
153     if (r != 0) {
154       return r;
155     }
156     if (size() < rhs.size()) {
157       return -1;
158     } else if (size() > rhs.size()) {
159       return 1;
160     }
161     return 0;
162   }
163 
164  private:
165   // Pointer to char data, not necessarily zero terminated.
166   const char* ptr_;
167   // Length of data.
168   size_type length_;
169 };
170 
171 // This large function is defined inline so that in a fairly common case where
172 // one of the arguments is a literal, the compiler can elide a lot of the
173 // following comparisons.
174 inline bool operator==(const StringPiece& x, const StringPiece& y) {
175   StringPiece::size_type len = x.size();
176   if (len != y.size()) {
177     return false;
178   }
179 
180   const char* p1 = x.data();
181   const char* p2 = y.data();
182   if (p1 == p2) {
183     return true;
184   }
185   if (len == 0) {
186     return true;
187   }
188 
189   // Test last byte in case strings share large common prefix
190   if (p1[len-1] != p2[len-1]) return false;
191   if (len == 1) return true;
192 
193   // At this point we can, but don't have to, ignore the last byte.  We use
194   // this observation to fold the odd-length case into the even-length case.
195   len &= ~1;
196 
197   return memcmp(p1, p2, len) == 0;
198 }
199 
200 inline bool operator==(const StringPiece& x, const char* y) {
201   if (y == nullptr) {
202     return x.size() == 0;
203   } else {
204     return strncmp(x.data(), y, x.size()) == 0 && y[x.size()] == '\0';
205   }
206 }
207 
208 inline bool operator!=(const StringPiece& x, const StringPiece& y) {
209   return !(x == y);
210 }
211 
212 inline bool operator!=(const StringPiece& x, const char* y) {
213   return !(x == y);
214 }
215 
216 inline bool operator<(const StringPiece& x, const StringPiece& y) {
217   return x.Compare(y) < 0;
218 }
219 
220 inline bool operator>(const StringPiece& x, const StringPiece& y) {
221   return y < x;
222 }
223 
224 inline bool operator<=(const StringPiece& x, const StringPiece& y) {
225   return !(x > y);
226 }
227 
228 inline bool operator>=(const StringPiece& x, const StringPiece& y) {
229   return !(x < y);
230 }
231 
232 extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
233 
234 }  // namespace art
235 
236 #endif  // ART_RUNTIME_BASE_STRINGPIECE_H_
237