]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/libc++/include/__refstring
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / libc++ / include / __refstring
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 #if __APPLE__
17 #include <dlfcn.h>
18 #include <mach-o/dyld.h>
19 #endif
20
21 _LIBCPP_BEGIN_NAMESPACE_STD
22
23 class _LIBCPP_HIDDEN __libcpp_refstring
24 {
25 private:
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 #if __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
87 public:
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