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