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