1 // Copyright 2001-2010 The RE2 Authors.  All Rights Reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 
5 #ifndef RE2_STRINGPIECE_H_
6 #define RE2_STRINGPIECE_H_
7 
8 // A string-like object that points to a sized piece of memory.
9 //
10 // Functions or methods may use const StringPiece& parameters to accept either
11 // a "const char*" or a "string" value that will be implicitly converted to
12 // a StringPiece.  The implicit conversion means that it is often appropriate
13 // to include this .h file in other files rather than forward-declaring
14 // StringPiece as would be appropriate for most other Google classes.
15 //
16 // Systematic usage of StringPiece is encouraged as it will reduce unnecessary
17 // conversions from "const char*" to "string" and back again.
18 //
19 //
20 // Arghh!  I wish C++ literals were "string".
21 
22 // Doing this simplifies the logic below.
23 #ifndef __has_include
24 #define __has_include(x) 0
25 #endif
26 
27 #include <stddef.h>
28 #include <string.h>
29 #include <algorithm>
30 #include <iosfwd>
31 #include <iterator>
32 #include <string>
33 #if __has_include(<string_view>) && __cplusplus >= 201703L
34 #include <string_view>
35 #endif
36 
37 namespace re2 {
38 
39 class StringPiece {
40  public:
41   typedef std::char_traits<char> traits_type;
42   typedef char value_type;
43   typedef char* pointer;
44   typedef const char* const_pointer;
45   typedef char& reference;
46   typedef const char& const_reference;
47   typedef const char* const_iterator;
48   typedef const_iterator iterator;
49   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
50   typedef const_reverse_iterator reverse_iterator;
51   typedef size_t size_type;
52   typedef ptrdiff_t difference_type;
53   static const size_type npos = static_cast<size_type>(-1);
54 
55   // We provide non-explicit singleton constructors so users can pass
56   // in a "const char*" or a "string" wherever a "StringPiece" is
57   // expected.
StringPiece()58   StringPiece()
59       : data_(NULL), size_(0) {}
60 #if __has_include(<string_view>) && __cplusplus >= 201703L
StringPiece(const std::string_view & str)61   StringPiece(const std::string_view& str)
62       : data_(str.data()), size_(str.size()) {}
63 #endif
StringPiece(const std::string & str)64   StringPiece(const std::string& str)
65       : data_(str.data()), size_(str.size()) {}
StringPiece(const char * str)66   StringPiece(const char* str)
67       : data_(str), size_(str == NULL ? 0 : strlen(str)) {}
StringPiece(const char * str,size_type len)68   StringPiece(const char* str, size_type len)
69       : data_(str), size_(len) {}
70 
begin()71   const_iterator begin() const { return data_; }
end()72   const_iterator end() const { return data_ + size_; }
rbegin()73   const_reverse_iterator rbegin() const {
74     return const_reverse_iterator(data_ + size_);
75   }
rend()76   const_reverse_iterator rend() const {
77     return const_reverse_iterator(data_);
78   }
79 
size()80   size_type size() const { return size_; }
length()81   size_type length() const { return size_; }
empty()82   bool empty() const { return size_ == 0; }
83 
84   const_reference operator[](size_type i) const { return data_[i]; }
data()85   const_pointer data() const { return data_; }
86 
remove_prefix(size_type n)87   void remove_prefix(size_type n) {
88     data_ += n;
89     size_ -= n;
90   }
91 
remove_suffix(size_type n)92   void remove_suffix(size_type n) {
93     size_ -= n;
94   }
95 
set(const char * str)96   void set(const char* str) {
97     data_ = str;
98     size_ = str == NULL ? 0 : strlen(str);
99   }
100 
set(const char * str,size_type len)101   void set(const char* str, size_type len) {
102     data_ = str;
103     size_ = len;
104   }
105 
106   // Converts to `std::basic_string`.
107   template <typename A>
108   explicit operator std::basic_string<char, traits_type, A>() const {
109     if (!data_) return {};
110     return std::basic_string<char, traits_type, A>(data_, size_);
111   }
112 
as_string()113   std::string as_string() const {
114     return std::string(data_, size_);
115   }
116 
117   // We also define ToString() here, since many other string-like
118   // interfaces name the routine that converts to a C++ string
119   // "ToString", and it's confusing to have the method that does that
120   // for a StringPiece be called "as_string()".  We also leave the
121   // "as_string()" method defined here for existing code.
ToString()122   std::string ToString() const {
123     return std::string(data_, size_);
124   }
125 
CopyToString(std::string * target)126   void CopyToString(std::string* target) const {
127     target->assign(data_, size_);
128   }
129 
AppendToString(std::string * target)130   void AppendToString(std::string* target) const {
131     target->append(data_, size_);
132   }
133 
134   size_type copy(char* buf, size_type n, size_type pos = 0) const;
135   StringPiece substr(size_type pos = 0, size_type n = npos) const;
136 
compare(const StringPiece & x)137   int compare(const StringPiece& x) const {
138     size_type min_size = std::min(size(), x.size());
139     if (min_size > 0) {
140       int r = memcmp(data(), x.data(), min_size);
141       if (r < 0) return -1;
142       if (r > 0) return 1;
143     }
144     if (size() < x.size()) return -1;
145     if (size() > x.size()) return 1;
146     return 0;
147   }
148 
149   // Does "this" start with "x"?
starts_with(const StringPiece & x)150   bool starts_with(const StringPiece& x) const {
151     return x.empty() ||
152            (size() >= x.size() && memcmp(data(), x.data(), x.size()) == 0);
153   }
154 
155   // Does "this" end with "x"?
ends_with(const StringPiece & x)156   bool ends_with(const StringPiece& x) const {
157     return x.empty() ||
158            (size() >= x.size() &&
159             memcmp(data() + (size() - x.size()), x.data(), x.size()) == 0);
160   }
161 
contains(const StringPiece & s)162   bool contains(const StringPiece& s) const {
163     return find(s) != npos;
164   }
165 
166   size_type find(const StringPiece& s, size_type pos = 0) const;
167   size_type find(char c, size_type pos = 0) const;
168   size_type rfind(const StringPiece& s, size_type pos = npos) const;
169   size_type rfind(char c, size_type pos = npos) const;
170 
171  private:
172   const_pointer data_;
173   size_type size_;
174 };
175 
176 inline bool operator==(const StringPiece& x, const StringPiece& y) {
177   StringPiece::size_type len = x.size();
178   if (len != y.size()) return false;
179   return x.data() == y.data() || len == 0 ||
180          memcmp(x.data(), y.data(), len) == 0;
181 }
182 
183 inline bool operator!=(const StringPiece& x, const StringPiece& y) {
184   return !(x == y);
185 }
186 
187 inline bool operator<(const StringPiece& x, const StringPiece& y) {
188   StringPiece::size_type min_size = std::min(x.size(), y.size());
189   int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
190   return (r < 0) || (r == 0 && x.size() < y.size());
191 }
192 
193 inline bool operator>(const StringPiece& x, const StringPiece& y) {
194   return y < x;
195 }
196 
197 inline bool operator<=(const StringPiece& x, const StringPiece& y) {
198   return !(x > y);
199 }
200 
201 inline bool operator>=(const StringPiece& x, const StringPiece& y) {
202   return !(x < y);
203 }
204 
205 // Allow StringPiece to be logged.
206 std::ostream& operator<<(std::ostream& o, const StringPiece& p);
207 
208 }  // namespace re2
209 
210 #endif  // RE2_STRINGPIECE_H_
211