2 * Copyright 2017-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <folly/lang/SafeAssert.h>
25 // This implementation is specific to libstdc++, now accepting
26 // diffs for other libraries.
28 // Specifically, this adds support for two things:
29 // 1) incrementing/decrementing the shared count by more than 1 at a time
30 // 2) Getting the thing the shared_ptr points to, which may be different from
31 // the aliased pointer.
33 class shared_ptr_internals {
35 template <typename T, typename... Args>
36 static std::shared_ptr<T> make_ptr(Args&&... args) {
37 return std::make_shared<T>(std::forward<Args...>(args...));
39 typedef std::__shared_count<std::_S_atomic> shared_count;
40 typedef std::_Sp_counted_base<std::_S_atomic> counted_base;
42 using CountedPtr = std::shared_ptr<T>;
44 static counted_base* get_counted_base(const std::shared_ptr<T>& bar) {
45 // reinterpret_pointer_cast<const void>
46 // Not quite C++ legal, but explicit template instantiation access to
47 // private members requires full type name (i.e. shared_ptr<const void>, not
49 const std::shared_ptr<const void>& ptr(
50 reinterpret_cast<const std::shared_ptr<const void>&>(bar));
51 return (ptr.*fieldPtr(access_shared_ptr{})).*fieldPtr(access_base{});
54 static void inc_shared_count(counted_base* base, long count) {
55 // Check that we don't exceed the maximum number of atomic_shared_ptrs.
56 // Consider setting EXTERNAL_COUNT lower if this CHECK is hit.
58 base->_M_get_use_count() + count < INT_MAX,
59 "atomic_shared_ptr overflow");
60 __gnu_cxx::__atomic_add_dispatch(
61 &(base->*fieldPtr(access_use_count{})), count);
65 static void release_shared(counted_base* base, long count) {
66 // If count == 1, this is equivalent to base->_M_release()
67 if (__gnu_cxx::__exchange_and_add_dispatch(
68 &(base->*fieldPtr(access_use_count{})), -count) == count) {
71 if (__gnu_cxx::__exchange_and_add_dispatch(
72 &(base->*fieldPtr(access_weak_count{})), -1) == 1) {
79 static T* get_shared_ptr(counted_base* base) {
80 // See if this was a make_shared allocation
81 auto inplace = base->_M_get_deleter(typeid(std::_Sp_make_shared_tag));
85 // Could also be a _Sp_counted_deleter, but the layout is the same
86 using derived_type = std::_Sp_counted_ptr<const void*, std::_S_atomic>;
87 auto ptr = reinterpret_cast<derived_type*>(base);
88 return (T*)(ptr->*fieldPtr(access_counted_ptr_ptr{}));
92 static T* release_ptr(std::shared_ptr<T>& p) {
94 std::shared_ptr<const void>& ptr(
95 reinterpret_cast<std::shared_ptr<const void>&>(p));
96 ptr.*fieldPtr(access_shared_ptr_ptr{}) = nullptr;
97 (ptr.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = nullptr;
101 template <typename T>
102 static std::shared_ptr<T> get_shared_ptr_from_counted_base(
108 std::shared_ptr<const void> newp;
110 inc_shared_count(base, 1);
112 newp.*fieldPtr(access_shared_ptr_ptr{}) =
113 get_shared_ptr<const void>(base); // _M_ptr
114 (newp.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = base;
115 // reinterpret_pointer_cast<T>
116 auto res = reinterpret_cast<std::shared_ptr<T>*>(&newp);
117 return std::move(*res);
121 /* Accessors for private members using explicit template instantiation */
122 struct access_shared_ptr {
123 typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
124 friend type fieldPtr(access_shared_ptr);
128 typedef counted_base* shared_count::*type;
129 friend type fieldPtr(access_base);
132 struct access_use_count {
133 typedef _Atomic_word counted_base::*type;
134 friend type fieldPtr(access_use_count);
137 struct access_weak_count {
138 typedef _Atomic_word counted_base::*type;
139 friend type fieldPtr(access_weak_count);
142 struct access_counted_ptr_ptr {
143 typedef const void* std::_Sp_counted_ptr<const void*, std::_S_atomic>::*
145 friend type fieldPtr(access_counted_ptr_ptr);
148 struct access_shared_ptr_ptr {
149 typedef const void* std::__shared_ptr<const void, std::_S_atomic>::*type;
150 friend type fieldPtr(access_shared_ptr_ptr);
153 struct access_refcount {
154 typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
155 friend type fieldPtr(access_refcount);
158 template <typename Tag, typename Tag::type M>
160 friend typename Tag::type fieldPtr(Tag) {
166 template struct shared_ptr_internals::Rob<
167 shared_ptr_internals::access_shared_ptr,
168 &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
169 template struct shared_ptr_internals::Rob<
170 shared_ptr_internals::access_base,
171 &shared_ptr_internals::shared_count::_M_pi>;
172 template struct shared_ptr_internals::Rob<
173 shared_ptr_internals::access_use_count,
174 &shared_ptr_internals::counted_base::_M_use_count>;
175 template struct shared_ptr_internals::Rob<
176 shared_ptr_internals::access_weak_count,
177 &shared_ptr_internals::counted_base::_M_weak_count>;
178 template struct shared_ptr_internals::Rob<
179 shared_ptr_internals::access_counted_ptr_ptr,
180 &std::_Sp_counted_ptr<const void*, std::_S_atomic>::_M_ptr>;
181 template struct shared_ptr_internals::Rob<
182 shared_ptr_internals::access_shared_ptr_ptr,
183 &std::__shared_ptr<const void, std::_S_atomic>::_M_ptr>;
184 template struct shared_ptr_internals::Rob<
185 shared_ptr_internals::access_refcount,
186 &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
188 } // namespace detail