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