blob: 6866bf1b9736e5fc59ad2fcd8f82b6490901e6e2 [file] [log] [blame]
Joerg Sonnenberger55622072014-04-30 19:54:11 +00001//===------------------------ __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
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#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
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