xref: /aosp_15_r20/system/unwinding/libunwindstack/include/unwindstack/SharedString.h (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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