Home | History | Annotate | Download | only in include
      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 <stdexcept>
     15 #include <cstddef>
     16 #include <cstring>
     17 #ifdef __APPLE__
     18 #include <dlfcn.h>
     19 #include <mach-o/dyld.h>
     20 #endif
     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         __sync_add_and_fetch(&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         __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1);
     96     if (adjust_old_count)
     97     {
     98         if (__sync_add_and_fetch(&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 (__sync_add_and_fetch(&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
    128