1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <memory> 20 #include <string> 21 #include <type_traits> 22 23 namespace unwindstack { 24 25 // Ref-counted read-only string. Used to avoid string allocations/copies. 26 // It is intended to be transparent std::string replacement in most cases. 27 class SharedString { 28 public: SharedString()29 SharedString() : data_() {} SharedString(std::string && s)30 SharedString(std::string&& s) : data_(std::make_shared<const std::string>(std::move(s))) {} SharedString(const std::string & s)31 SharedString(const std::string& s) : SharedString(std::string(s)) {} SharedString(const char * s)32 SharedString(const char* s) : SharedString(std::string(s)) {} 33 clear()34 void clear() { data_.reset(); } is_null()35 bool is_null() const { return data_.get() == nullptr; } empty()36 bool empty() const { return is_null() ? true : data_->empty(); } c_str()37 const char* c_str() const { return is_null() ? "" : data_->c_str(); } 38 39 operator const std::string&() const { 40 [[clang::no_destroy]] static const EmptyString empty; 41 return data_ ? *data_.get() : empty.str; 42 } 43 string_view()44 operator std::string_view() const { return static_cast<const std::string&>(*this); } 45 46 private: 47 std::shared_ptr<const std::string> data_; 48 49 // Wrap the std::string in a struct with a non-constexpr user-declared 50 // constructor, ensuring that the static variable consistently uses dynamic 51 // initialization regardless of whether string() is a constexpr constructor 52 // (i.e. regardless of whether the code is compiled with C++17 or C++20). If 53 // this code were always compiled with C++20, then this struct could be 54 // removed, and the std::string variable could be declared 55 // `[[clang::no_destroy]] static constinit const` See b/330974273. 56 struct EmptyString { EmptyStringEmptyString57 EmptyString() {} 58 std::string str; 59 }; 60 }; 61 62 template <typename T, typename = std::enable_if_t<std::is_same_v<T, SharedString>>> 63 static inline bool operator==(const T& a, const T& b) { 64 return static_cast<std::string_view>(a) == static_cast<std::string_view>(b); 65 } 66 static inline bool operator==(const SharedString& a, std::string_view b) { 67 return static_cast<std::string_view>(a) == b; 68 } 69 static inline bool operator==(std::string_view a, const SharedString& b) { 70 return a == static_cast<std::string_view>(b); 71 } 72 template <typename T, typename = std::enable_if_t<std::is_same_v<T, SharedString>>> 73 static inline bool operator!=(const T& a, const T& b) { 74 return !(a == b); 75 } 76 static inline bool operator!=(const SharedString& a, std::string_view b) { 77 return !(a == b); 78 } 79 static inline bool operator!=(std::string_view a, const SharedString& b) { 80 return !(a == b); 81 } 82 static inline std::string operator+(const SharedString& a, const char* b) { 83 return static_cast<const std::string&>(a) + b; 84 } 85 static inline std::string operator+(const char* a, const SharedString& b) { 86 return a + static_cast<const std::string&>(b); 87 } 88 89 } // namespace unwindstack 90