add a new logging library
[folly.git] / folly / experimental / detail / AtomicSharedPtr-detail.h
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #pragma once
17 #include <atomic>
18 #include <memory>
19
20 namespace folly {
21 namespace detail {
22
23 class shared_ptr_internals {
24  public:
25   template <typename T, typename... Args>
26   static std::shared_ptr<T> make_ptr(Args&&... args) {
27     return std::make_shared<T>(std::forward<Args...>(args...));
28   }
29   typedef std::__shared_count<std::_S_atomic> shared_count;
30   typedef std::_Sp_counted_base<std::_S_atomic> counted_base;
31   template <typename T>
32   using CountedPtr = std::shared_ptr<T>;
33   template <typename T>
34   static counted_base* get_counted_base(const std::shared_ptr<T>& bar) {
35     // reinterpret_pointer_cast<const void>
36     // Not quite C++ legal, but explicit template instantiation access to
37     // private members requires full type name (i.e. shared_ptr<const void>, not
38     // shared_ptr<T>)
39     const std::shared_ptr<const void>& ptr(
40         reinterpret_cast<const std::shared_ptr<const void>&>(bar));
41     return (ptr.*fieldPtr(access_shared_ptr{})).*fieldPtr(access_base{});
42   }
43
44   static void inc_shared_count(counted_base* base, long count) {
45     __gnu_cxx::__atomic_add_dispatch(
46         &(base->*fieldPtr(access_use_count{})), count);
47   }
48
49   template <typename T>
50   static void release_shared(counted_base* base, long count) {
51     // If count == 1, this is equivalent to base->_M_release()
52     if (__gnu_cxx::__exchange_and_add_dispatch(
53             &(base->*fieldPtr(access_use_count{})), -count) == count) {
54       base->_M_dispose();
55
56       if (__gnu_cxx::__exchange_and_add_dispatch(
57               &(base->*fieldPtr(access_weak_count{})), -1) == 1) {
58         base->_M_destroy();
59       }
60     }
61   }
62
63   template <typename T>
64   static T* get_shared_ptr(counted_base* base) {
65     // See if this was a make_shared allocation
66     auto inplace = base->_M_get_deleter(typeid(std::_Sp_make_shared_tag));
67     if (inplace) {
68       return (T*)inplace;
69     }
70     // Could also be a _Sp_counted_deleter, but the layout is the same
71     auto ptr =
72         static_cast<std::_Sp_counted_ptr<const void*, std::_S_atomic>*>(base);
73     return (T*)(ptr->*fieldPtr(access_counted_ptr_ptr{}));
74   }
75
76   template <typename T>
77   static T* release_ptr(std::shared_ptr<T>& p) {
78     auto res = p.get();
79     std::shared_ptr<const void>& ptr(
80         reinterpret_cast<std::shared_ptr<const void>&>(p));
81     ptr.*fieldPtr(access_shared_ptr_ptr{}) = nullptr;
82     (ptr.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = nullptr;
83     return res;
84   }
85
86   template <typename T>
87   static std::shared_ptr<T> get_shared_ptr_from_counted_base(
88       counted_base* base,
89       bool inc = true) {
90     if (!base) {
91       return nullptr;
92     }
93     std::shared_ptr<const void> newp;
94     if (inc) {
95       inc_shared_count(base, 1);
96     }
97     newp.*fieldPtr(access_shared_ptr_ptr{}) =
98         get_shared_ptr<const void>(base); // _M_ptr
99     (newp.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = base;
100     // reinterpret_pointer_cast<T>
101     auto res = reinterpret_cast<std::shared_ptr<T>*>(&newp);
102     return std::move(*res);
103   }
104
105  private:
106   /* Accessors for private members using explicit template instantiation */
107   struct access_shared_ptr {
108     typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
109     friend type fieldPtr(access_shared_ptr);
110   };
111
112   struct access_base {
113     typedef counted_base* shared_count::*type;
114     friend type fieldPtr(access_base);
115   };
116
117   struct access_use_count {
118     typedef _Atomic_word counted_base::*type;
119     friend type fieldPtr(access_use_count);
120   };
121
122   struct access_weak_count {
123     typedef _Atomic_word counted_base::*type;
124     friend type fieldPtr(access_weak_count);
125   };
126
127   struct access_counted_ptr_ptr {
128     typedef const void* std::_Sp_counted_ptr<const void*, std::_S_atomic>::*
129         type;
130     friend type fieldPtr(access_counted_ptr_ptr);
131   };
132
133   struct access_shared_ptr_ptr {
134     typedef const void* std::__shared_ptr<const void, std::_S_atomic>::*type;
135     friend type fieldPtr(access_shared_ptr_ptr);
136   };
137
138   struct access_refcount {
139     typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
140     friend type fieldPtr(access_refcount);
141   };
142
143   template <typename Tag, typename Tag::type M>
144   struct Rob {
145     friend typename Tag::type fieldPtr(Tag) {
146       return M;
147     }
148   };
149 };
150
151 template struct shared_ptr_internals::Rob<
152     shared_ptr_internals::access_shared_ptr,
153     &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
154 template struct shared_ptr_internals::Rob<
155     shared_ptr_internals::access_base,
156     &shared_ptr_internals::shared_count::_M_pi>;
157 template struct shared_ptr_internals::Rob<
158     shared_ptr_internals::access_use_count,
159     &shared_ptr_internals::counted_base::_M_use_count>;
160 template struct shared_ptr_internals::Rob<
161     shared_ptr_internals::access_weak_count,
162     &shared_ptr_internals::counted_base::_M_weak_count>;
163 template struct shared_ptr_internals::Rob<
164     shared_ptr_internals::access_counted_ptr_ptr,
165     &std::_Sp_counted_ptr<const void*, std::_S_atomic>::_M_ptr>;
166 template struct shared_ptr_internals::Rob<
167     shared_ptr_internals::access_shared_ptr_ptr,
168     &std::__shared_ptr<const void, std::_S_atomic>::_M_ptr>;
169 template struct shared_ptr_internals::Rob<
170     shared_ptr_internals::access_refcount,
171     &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
172
173 } // namespace detail
174 } // namespace folly