1*eb293b8fSAndroid Build Coastguard Worker /* 2*eb293b8fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project 3*eb293b8fSAndroid Build Coastguard Worker * 4*eb293b8fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*eb293b8fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*eb293b8fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*eb293b8fSAndroid Build Coastguard Worker * 8*eb293b8fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*eb293b8fSAndroid Build Coastguard Worker * 10*eb293b8fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*eb293b8fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*eb293b8fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*eb293b8fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*eb293b8fSAndroid Build Coastguard Worker * limitations under the License. 15*eb293b8fSAndroid Build Coastguard Worker */ 16*eb293b8fSAndroid Build Coastguard Worker 17*eb293b8fSAndroid Build Coastguard Worker #pragma once 18*eb293b8fSAndroid Build Coastguard Worker 19*eb293b8fSAndroid Build Coastguard Worker #include <memory> 20*eb293b8fSAndroid Build Coastguard Worker #include <string> 21*eb293b8fSAndroid Build Coastguard Worker #include <type_traits> 22*eb293b8fSAndroid Build Coastguard Worker 23*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack { 24*eb293b8fSAndroid Build Coastguard Worker 25*eb293b8fSAndroid Build Coastguard Worker // Ref-counted read-only string. Used to avoid string allocations/copies. 26*eb293b8fSAndroid Build Coastguard Worker // It is intended to be transparent std::string replacement in most cases. 27*eb293b8fSAndroid Build Coastguard Worker class SharedString { 28*eb293b8fSAndroid Build Coastguard Worker public: SharedString()29*eb293b8fSAndroid Build Coastguard Worker SharedString() : data_() {} SharedString(std::string && s)30*eb293b8fSAndroid Build Coastguard Worker SharedString(std::string&& s) : data_(std::make_shared<const std::string>(std::move(s))) {} SharedString(const std::string & s)31*eb293b8fSAndroid Build Coastguard Worker SharedString(const std::string& s) : SharedString(std::string(s)) {} SharedString(const char * s)32*eb293b8fSAndroid Build Coastguard Worker SharedString(const char* s) : SharedString(std::string(s)) {} 33*eb293b8fSAndroid Build Coastguard Worker clear()34*eb293b8fSAndroid Build Coastguard Worker void clear() { data_.reset(); } is_null()35*eb293b8fSAndroid Build Coastguard Worker bool is_null() const { return data_.get() == nullptr; } empty()36*eb293b8fSAndroid Build Coastguard Worker bool empty() const { return is_null() ? true : data_->empty(); } c_str()37*eb293b8fSAndroid Build Coastguard Worker const char* c_str() const { return is_null() ? "" : data_->c_str(); } 38*eb293b8fSAndroid Build Coastguard Worker 39*eb293b8fSAndroid Build Coastguard Worker operator const std::string&() const { 40*eb293b8fSAndroid Build Coastguard Worker [[clang::no_destroy]] static const EmptyString empty; 41*eb293b8fSAndroid Build Coastguard Worker return data_ ? *data_.get() : empty.str; 42*eb293b8fSAndroid Build Coastguard Worker } 43*eb293b8fSAndroid Build Coastguard Worker string_view()44*eb293b8fSAndroid Build Coastguard Worker operator std::string_view() const { return static_cast<const std::string&>(*this); } 45*eb293b8fSAndroid Build Coastguard Worker 46*eb293b8fSAndroid Build Coastguard Worker private: 47*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<const std::string> data_; 48*eb293b8fSAndroid Build Coastguard Worker 49*eb293b8fSAndroid Build Coastguard Worker // Wrap the std::string in a struct with a non-constexpr user-declared 50*eb293b8fSAndroid Build Coastguard Worker // constructor, ensuring that the static variable consistently uses dynamic 51*eb293b8fSAndroid Build Coastguard Worker // initialization regardless of whether string() is a constexpr constructor 52*eb293b8fSAndroid Build Coastguard Worker // (i.e. regardless of whether the code is compiled with C++17 or C++20). If 53*eb293b8fSAndroid Build Coastguard Worker // this code were always compiled with C++20, then this struct could be 54*eb293b8fSAndroid Build Coastguard Worker // removed, and the std::string variable could be declared 55*eb293b8fSAndroid Build Coastguard Worker // `[[clang::no_destroy]] static constinit const` See b/330974273. 56*eb293b8fSAndroid Build Coastguard Worker struct EmptyString { EmptyStringEmptyString57*eb293b8fSAndroid Build Coastguard Worker EmptyString() {} 58*eb293b8fSAndroid Build Coastguard Worker std::string str; 59*eb293b8fSAndroid Build Coastguard Worker }; 60*eb293b8fSAndroid Build Coastguard Worker }; 61*eb293b8fSAndroid Build Coastguard Worker 62*eb293b8fSAndroid Build Coastguard Worker template <typename T, typename = std::enable_if_t<std::is_same_v<T, SharedString>>> 63*eb293b8fSAndroid Build Coastguard Worker static inline bool operator==(const T& a, const T& b) { 64*eb293b8fSAndroid Build Coastguard Worker return static_cast<std::string_view>(a) == static_cast<std::string_view>(b); 65*eb293b8fSAndroid Build Coastguard Worker } 66*eb293b8fSAndroid Build Coastguard Worker static inline bool operator==(const SharedString& a, std::string_view b) { 67*eb293b8fSAndroid Build Coastguard Worker return static_cast<std::string_view>(a) == b; 68*eb293b8fSAndroid Build Coastguard Worker } 69*eb293b8fSAndroid Build Coastguard Worker static inline bool operator==(std::string_view a, const SharedString& b) { 70*eb293b8fSAndroid Build Coastguard Worker return a == static_cast<std::string_view>(b); 71*eb293b8fSAndroid Build Coastguard Worker } 72*eb293b8fSAndroid Build Coastguard Worker template <typename T, typename = std::enable_if_t<std::is_same_v<T, SharedString>>> 73*eb293b8fSAndroid Build Coastguard Worker static inline bool operator!=(const T& a, const T& b) { 74*eb293b8fSAndroid Build Coastguard Worker return !(a == b); 75*eb293b8fSAndroid Build Coastguard Worker } 76*eb293b8fSAndroid Build Coastguard Worker static inline bool operator!=(const SharedString& a, std::string_view b) { 77*eb293b8fSAndroid Build Coastguard Worker return !(a == b); 78*eb293b8fSAndroid Build Coastguard Worker } 79*eb293b8fSAndroid Build Coastguard Worker static inline bool operator!=(std::string_view a, const SharedString& b) { 80*eb293b8fSAndroid Build Coastguard Worker return !(a == b); 81*eb293b8fSAndroid Build Coastguard Worker } 82*eb293b8fSAndroid Build Coastguard Worker static inline std::string operator+(const SharedString& a, const char* b) { 83*eb293b8fSAndroid Build Coastguard Worker return static_cast<const std::string&>(a) + b; 84*eb293b8fSAndroid Build Coastguard Worker } 85*eb293b8fSAndroid Build Coastguard Worker static inline std::string operator+(const char* a, const SharedString& b) { 86*eb293b8fSAndroid Build Coastguard Worker return a + static_cast<const std::string&>(b); 87*eb293b8fSAndroid Build Coastguard Worker } 88*eb293b8fSAndroid Build Coastguard Worker 89*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack 90