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