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