1 //===------------------------ __refstring ---------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP_REFSTRING_H 10 #define _LIBCPP_REFSTRING_H 11 12 #include <__config> 13 #include <stdexcept> 14 #include <cstddef> 15 #include <cstring> 16 #ifdef __APPLE__ 17 #include <dlfcn.h> 18 #include <mach-o/dyld.h> 19 #endif 20 #include "atomic_support.h" 21 22 _LIBCPP_BEGIN_NAMESPACE_STD 23 24 namespace __refstring_imp { namespace { 25 typedef int count_t; 26 27 struct _Rep_base { 28 std::size_t len; 29 std::size_t cap; 30 count_t count; 31 }; 32 33 inline _Rep_base* rep_from_data(const char *data_) noexcept { 34 char *data = const_cast<char *>(data_); 35 return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); 36 } 37 38 inline char * data_from_rep(_Rep_base *rep) noexcept { 39 char *data = reinterpret_cast<char *>(rep); 40 return data + sizeof(*rep); 41 } 42 43 #if defined(__APPLE__) 44 inline 45 const char* compute_gcc_empty_string_storage() _NOEXCEPT 46 { 47 void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); 48 if (handle == nullptr) 49 return nullptr; 50 void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); 51 if (sym == nullptr) 52 return nullptr; 53 return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); 54 } 55 56 inline 57 const char* 58 get_gcc_empty_string_storage() _NOEXCEPT 59 { 60 static const char* p = compute_gcc_empty_string_storage(); 61 return p; 62 } 63 #endif 64 65 }} // namespace __refstring_imp 66 67 using namespace __refstring_imp; 68 69 inline 70 __libcpp_refstring::__libcpp_refstring(const char* msg) { 71 std::size_t len = strlen(msg); 72 _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); 73 rep->len = len; 74 rep->cap = len; 75 rep->count = 0; 76 char *data = data_from_rep(rep); 77 std::memcpy(data, msg, len + 1); 78 __imp_ = data; 79 } 80 81 inline 82 __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT 83 : __imp_(s.__imp_) 84 { 85 if (__uses_refcount()) 86 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 87 } 88 89 inline 90 __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { 91 bool adjust_old_count = __uses_refcount(); 92 struct _Rep_base *old_rep = rep_from_data(__imp_); 93 __imp_ = s.__imp_; 94 if (__uses_refcount()) 95 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); 96 if (adjust_old_count) 97 { 98 if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) 99 { 100 ::operator delete(old_rep); 101 } 102 } 103 return *this; 104 } 105 106 inline 107 __libcpp_refstring::~__libcpp_refstring() { 108 if (__uses_refcount()) { 109 _Rep_base* rep = rep_from_data(__imp_); 110 if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { 111 ::operator delete(rep); 112 } 113 } 114 } 115 116 inline 117 bool __libcpp_refstring::__uses_refcount() const { 118 #ifdef __APPLE__ 119 return __imp_ != get_gcc_empty_string_storage(); 120 #else 121 return true; 122 #endif 123 } 124 125 _LIBCPP_END_NAMESPACE_STD 126 127 #endif //_LIBCPP_REFSTRING_H 128