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 Andric inline _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 Andric inline 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 Andric const 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 Andric get_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 Andric bool __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