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