• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
19 
20 #include <string.h>
21 
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25 
26 #include "perfetto/base/build_config.h"
27 #include "perfetto/base/logging.h"
28 #include "perfetto/ext/base/hash.h"
29 
30 namespace perfetto {
31 namespace base {
32 
33 // A string-like object that refers to a non-owned piece of memory.
34 // Strings are internally NOT null terminated.
35 class StringView {
36  public:
37   // Allow hashing with base::Hash.
38   static constexpr bool kHashable = true;
39   static constexpr size_t npos = static_cast<size_t>(-1);
40 
StringView()41   StringView() : data_(nullptr), size_(0) {}
42   StringView(const StringView&) = default;
43   StringView& operator=(const StringView&) = default;
StringView(const char * data,size_t size)44   StringView(const char* data, size_t size) : data_(data), size_(size) {
45     PERFETTO_DCHECK(size == 0 || data != nullptr);
46   }
47 
48   // Allow implicit conversion from any class that has a |data| and |size| field
49   // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars).
50   template <typename T, typename = std::enable_if<T::kConvertibleToStringView>>
StringView(const T & x)51   StringView(const T& x) : StringView(x.data, x.size) {
52     PERFETTO_DCHECK(x.size == 0 || x.data != nullptr);
53   }
54 
55   // Creates a StringView from a null-terminated C string.
56   // Deliberately not "explicit".
StringView(const char * cstr)57   StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) {
58     PERFETTO_DCHECK(cstr != nullptr);
59   }
60 
61   // This instead has to be explicit, as creating a StringView out of a
62   // std::string can be subtle.
StringView(const std::string & str)63   explicit StringView(const std::string& str)
64       : data_(str.data()), size_(str.size()) {}
65 
empty()66   bool empty() const { return size_ == 0; }
size()67   size_t size() const { return size_; }
data()68   const char* data() const { return data_; }
begin()69   const char* begin() const { return data_; }
end()70   const char* end() const { return data_ + size_; }
71 
at(size_t pos)72   char at(size_t pos) const {
73     PERFETTO_DCHECK(pos < size_);
74     return data_[pos];
75   }
76 
77   size_t find(char c, size_t start_pos = 0) const {
78     for (size_t i = start_pos; i < size_; ++i) {
79       if (data_[i] == c)
80         return i;
81     }
82     return npos;
83   }
84 
85   size_t find(const StringView& str, size_t start_pos = 0) const {
86     if (start_pos > size())
87       return npos;
88     auto it = std::search(begin() + start_pos, end(), str.begin(), str.end());
89     size_t pos = static_cast<size_t>(it - begin());
90     return pos + str.size() <= size() ? pos : npos;
91   }
92 
93   size_t find(const char* str, size_t start_pos = 0) const {
94     return find(StringView(str), start_pos);
95   }
96 
rfind(char c)97   size_t rfind(char c) const {
98     for (size_t i = size_; i > 0; --i) {
99       if (data_[i - 1] == c)
100         return i - 1;
101     }
102     return npos;
103   }
104 
105   StringView substr(size_t pos, size_t count = npos) const {
106     if (pos >= size_)
107       return StringView("", 0);
108     size_t rcount = std::min(count, size_ - pos);
109     return StringView(data_ + pos, rcount);
110   }
111 
CaseInsensitiveEq(const StringView & other)112   bool CaseInsensitiveEq(const StringView& other) const {
113     if (size() != other.size())
114       return false;
115     if (size() == 0)
116       return true;
117 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
118     return _strnicmp(data(), other.data(), size()) == 0;
119 #else
120     return strncasecmp(data(), other.data(), size()) == 0;
121 #endif
122   }
123 
CaseInsensitiveOneOf(const std::vector<StringView> & others)124   bool CaseInsensitiveOneOf(const std::vector<StringView>& others) const {
125     for (const StringView& other : others) {
126       if (CaseInsensitiveEq(other)) {
127         return true;
128       }
129     }
130     return false;
131   }
132 
StartsWith(const StringView & other)133   bool StartsWith(const StringView& other) const {
134     if (other.size() == 0)
135       return true;
136     if (size() == 0)
137       return false;
138     if (other.size() > size())
139       return false;
140     return memcmp(data(), other.data(), other.size()) == 0;
141   }
142 
EndsWith(const StringView & other)143   bool EndsWith(const StringView& other) const {
144     if (other.size() == 0)
145       return true;
146     if (size() == 0)
147       return false;
148     if (other.size() > size())
149       return false;
150     size_t off = size() - other.size();
151     return memcmp(data() + off, other.data(), other.size()) == 0;
152   }
153 
ToStdString()154   std::string ToStdString() const {
155     return size_ == 0 ? "" : std::string(data_, size_);
156   }
157 
Hash()158   uint64_t Hash() const {
159     base::Hasher hasher;
160     hasher.Update(data_, size_);
161     return hasher.digest();
162   }
163 
164  private:
165   const char* data_ = nullptr;
166   size_t size_ = 0;
167 };
168 
169 inline bool operator==(const StringView& x, const StringView& y) {
170   if (x.size() != y.size())
171     return false;
172   if (x.size() == 0)
173     return true;
174   return memcmp(x.data(), y.data(), x.size()) == 0;
175 }
176 
177 inline bool operator!=(const StringView& x, const StringView& y) {
178   return !(x == y);
179 }
180 
181 inline bool operator<(const StringView& x, const StringView& y) {
182   auto size = std::min(x.size(), y.size());
183   if (size == 0)
184     return x.size() < y.size();
185   int result = memcmp(x.data(), y.data(), size);
186   return result < 0 || (result == 0 && x.size() < y.size());
187 }
188 
189 inline bool operator>=(const StringView& x, const StringView& y) {
190   return !(x < y);
191 }
192 
193 inline bool operator>(const StringView& x, const StringView& y) {
194   return y < x;
195 }
196 
197 inline bool operator<=(const StringView& x, const StringView& y) {
198   return !(y < x);
199 }
200 
201 }  // namespace base
202 }  // namespace perfetto
203 
204 template <>
205 struct std::hash<::perfetto::base::StringView> {
206   size_t operator()(const ::perfetto::base::StringView& sv) const {
207     return static_cast<size_t>(sv.Hash());
208   }
209 };
210 
211 #endif  // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
212