1 /** @file
2 
3   Reference-counting shared pointer, like std::shared_ptr.
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include "tscore/ink_atomic.h"
27 
28 ////////////////////////////////////////////////////////////////////
29 ////////////////////////////////////////////////////////////////////
30 //////              ATOMIC VERSIONS
31 ////////////////////////////////////////////////////////////////////
32 ////////////////////////////////////////////////////////////////////
33 
34 struct ForceVFPTToTop {
~ForceVFPTToTopForceVFPTToTop35   virtual ~ForceVFPTToTop() {}
36 };
37 
38 ////////////////////////////////////////////////////////////////////////
39 //
40 // class RefCountObj
41 // prototypical class for reference counting
42 //
43 ////////////////////////////////////////////////////////////////////////
44 class RefCountObj : public ForceVFPTToTop
45 {
46 public:
RefCountObj()47   RefCountObj() {}
RefCountObj(const RefCountObj & s)48   RefCountObj(const RefCountObj &s)
49   {
50     (void)s;
51     return;
52   }
53 
~RefCountObj()54   ~RefCountObj() override {}
55   RefCountObj &
56   operator=(const RefCountObj &s)
57   {
58     (void)s;
59     return (*this);
60   }
61 
62   // Increment the reference count, returning the new count.
63   int
refcount_inc()64   refcount_inc()
65   {
66     return ink_atomic_increment((int *)&m_refcount, 1) + 1;
67   }
68 
69   // Decrement the reference count, returning the new count.
70   int
refcount_dec()71   refcount_dec()
72   {
73     return ink_atomic_increment((int *)&m_refcount, -1) - 1;
74   }
75 
76   int
refcount()77   refcount() const
78   {
79     return m_refcount;
80   }
81 
82   virtual void
free()83   free()
84   {
85     delete this;
86   }
87 
88 private:
89   int m_refcount = 0;
90 };
91 
92 ////////////////////////////////////////////////////////////////////////
93 //
94 // class Ptr
95 //
96 ////////////////////////////////////////////////////////////////////////
97 template <class T> class Ptr
98 {
99 public:
100   explicit Ptr(T *p = nullptr);
101   Ptr(const Ptr<T> &);
102   ~Ptr();
103 
104   void clear();
105   Ptr<T> &operator=(const Ptr<T> &);
106   Ptr<T> &operator=(T *);
107 
108   T *
109   operator->() const
110   {
111     return (m_ptr);
112   }
113   T &
114   operator*() const
115   {
116     return (*m_ptr);
117   }
118 
119   // Making this explicit avoids unwanted conversions.  See https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool .
120   explicit operator bool() const { return m_ptr != nullptr; }
121 
122   int
123   operator==(const T *p)
124   {
125     return (m_ptr == p);
126   }
127 
128   int
129   operator==(const Ptr<T> &p)
130   {
131     return (m_ptr == p.m_ptr);
132   }
133 
134   int
135   operator!=(const T *p)
136   {
137     return (m_ptr != p);
138   }
139 
140   int
141   operator!=(const Ptr<T> &p)
142   {
143     return (m_ptr != p.m_ptr);
144   }
145 
146   // Return the raw pointer.
147   T *
get()148   get() const
149   {
150     return m_ptr;
151   }
152 
153   // Return the raw pointer as a RefCount object. Typically
154   // this is for keeping a collection of ogenous objects.
155   RefCountObj *
object()156   object() const
157   {
158     return static_cast<RefCountObj *>(m_ptr);
159   }
160 
161   // Return the stored pointer, storing NULL instead. Do not increment
162   // the refcount; the caller is now responsible for owning the RefCountObj.
163   T *
detach()164   detach()
165   {
166     T *tmp = m_ptr;
167     m_ptr  = nullptr;
168     return tmp;
169   }
170 
171   // XXX Clearly this is not safe. This is used in HdrHeap::unmarshal() to swizzle
172   // the refcount of the managed heap pointers. That code needs to be cleaned up
173   // so that this can be removed. Do not use this in new code.
174   void
swizzle(RefCountObj * ptr)175   swizzle(RefCountObj *ptr)
176   {
177     m_ptr = ptr;
178   }
179 
180 private:
181   T *m_ptr;
182 
183   friend class CoreUtils;
184 };
185 
186 template <typename T>
187 Ptr<T>
make_ptr(T * p)188 make_ptr(T *p)
189 {
190   return Ptr<T>(p);
191 }
192 
193 ////////////////////////////////////////////////////////////////////////
194 //
195 // inline functions definitions
196 //
197 ////////////////////////////////////////////////////////////////////////
Ptr(T * ptr)198 template <class T> inline Ptr<T>::Ptr(T *ptr /* = 0 */) : m_ptr(ptr)
199 {
200   if (m_ptr) {
201     m_ptr->refcount_inc();
202   }
203 }
204 
Ptr(const Ptr<T> & src)205 template <class T> inline Ptr<T>::Ptr(const Ptr<T> &src) : m_ptr(src.m_ptr)
206 {
207   if (m_ptr) {
208     m_ptr->refcount_inc();
209   }
210 }
211 
~Ptr()212 template <class T> inline Ptr<T>::~Ptr()
213 {
214   if (m_ptr && m_ptr->refcount_dec() == 0) {
215     m_ptr->free();
216   }
217 }
218 
219 template <class T>
220 inline Ptr<T> &
221 Ptr<T>::operator=(T *p)
222 {
223   T *temp_ptr = m_ptr;
224 
225   if (m_ptr == p) {
226     return (*this);
227   }
228 
229   m_ptr = p;
230 
231   if (m_ptr) {
232     m_ptr->refcount_inc();
233   }
234 
235   if (temp_ptr && temp_ptr->refcount_dec() == 0) {
236     temp_ptr->free();
237   }
238 
239   return (*this);
240 }
241 
242 template <class T>
243 inline void
clear()244 Ptr<T>::clear()
245 {
246   if (m_ptr) {
247     if (!m_ptr->refcount_dec())
248       m_ptr->free();
249     m_ptr = nullptr;
250   }
251 }
252 
253 template <class T>
254 inline Ptr<T> &
255 Ptr<T>::operator=(const Ptr<T> &src)
256 {
257   return (operator=(src.m_ptr));
258 }
259 
260 // Bit of subtly here for the flipped version of equality checks
261 // With only the template versions, the compiler will try to substitute @c nullptr_t
262 // for @c T and fail, because that's not the type and no operator will be found.
263 // Therefore there needs to be specific overrides for @c nullptr_t.
264 
265 template <typename T>
266 inline bool
267 operator==(std::nullptr_t, Ptr<T> const &rhs)
268 {
269   return rhs.get() == nullptr;
270 }
271 
272 template <typename T>
273 inline bool
274 operator!=(std::nullptr_t, Ptr<T> const &rhs)
275 {
276   return rhs.get() != nullptr;
277 }
278 
279 template <typename T>
280 inline bool
281 operator==(T const *lhs, Ptr<T> const &rhs)
282 {
283   return rhs.get() == lhs;
284 }
285 
286 template <typename T>
287 inline bool
288 operator!=(T const *lhs, Ptr<T> const &rhs)
289 {
290   return rhs.get() != lhs;
291 }
292