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) { 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 ToStdString()121 std::string ToStdString() const { 122 return data_ == nullptr ? "" : std::string(data_, size_); 123 } 124 Hash()125 uint64_t Hash() const { 126 base::Hash hasher; 127 hasher.Update(data_, size_); 128 return hasher.digest(); 129 } 130 131 private: 132 const char* data_ = nullptr; 133 size_t size_ = 0; 134 }; 135 136 inline bool operator==(const StringView& x, const StringView& y) { 137 if (x.size() != y.size()) 138 return false; 139 if (x.size() == 0) 140 return true; 141 return memcmp(x.data(), y.data(), x.size()) == 0; 142 } 143 144 inline bool operator!=(const StringView& x, const StringView& y) { 145 return !(x == y); 146 } 147 148 inline bool operator<(const StringView& x, const StringView& y) { 149 auto size = std::min(x.size(), y.size()); 150 if (size == 0) 151 return x.size() < y.size(); 152 int result = memcmp(x.data(), y.data(), size); 153 return result < 0 || (result == 0 && x.size() < y.size()); 154 } 155 156 inline bool operator>=(const StringView& x, const StringView& y) { 157 return !(x < y); 158 } 159 160 inline bool operator>(const StringView& x, const StringView& y) { 161 return y < x; 162 } 163 164 inline bool operator<=(const StringView& x, const StringView& y) { 165 return !(y < x); 166 } 167 168 } // namespace base 169 } // namespace perfetto 170 171 template <> 172 struct std::hash<::perfetto::base::StringView> { 173 size_t operator()(const ::perfetto::base::StringView& sv) const { 174 return static_cast<size_t>(sv.Hash()); 175 } 176 }; 177 178 #endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ 179