1 /** @file
2 
3     This is an intrusive shared pointer class designed for internal use in various containers inside
4     Traffic Server. It is not dependent on TS and could be used elsewhere. The design tries to
5     follow that of @c std::shared_ptr as it performs a similar function. The key difference is
6     this shared pointer requires the reference count to be in the target class. This is done by
7     inheriting a class containing the counter. This has the benefits
8 
9     - improved locality for instances of the class and the reference count
10     - the ability to reliably construct shared pointers from raw pointers.
11     - lower overhead (a single reference counter).
12 
13     The requirement of modifying the target class limits the generality of this class but it is
14     still quite useful in specific cases (particularly containers and their internal node classes).
15 
16     @section license License
17 
18     Licensed to the Apache Software Foundation (ASF) under one or more contributor license
19     agreements.  See the NOTICE file distributed with this work for additional information regarding
20     copyright ownership.  The ASF licenses this file to you under the Apache License, Version 2.0
21     (the "License"); you may not use this file except in compliance with the License.  You may
22     obtain a copy of the License at
23 
24     http://www.apache.org/licenses/LICENSE-2.0
25 
26     Unless required by applicable law or agreed to in writing, software distributed under the
27     License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
28     express or implied. See the License for the specific language governing permissions and
29     limitations under the License.
30  */
31 
32 #pragma once
33 
34 #include <sys/types.h>
35 #include <type_traits>
36 #include <cassert>
37 #include <functional>
38 #include <atomic>
39 
40 namespace ts
41 {
42 template <typename T> class IntrusivePtr; // forward declare
43 
44 /* ----------------------------------------------------------------------- */
45 /** Reference counter mixin.
46 
47     To add support for @c IntrusivePtr to class @a T, it must publicly inherit
48     @c IntrusivePtrCounter. Doing so
49 
50     - provides a reference count member
51     - forces the reference count to initialize to zero
52     - prevents reference count copying on copy construction or assignment
53     - provides access to the reference counter from the shared pointer
54     - provides the `use_count` method to check the reference count.
55 
56     @note You can use this with insulated (by name only) classes. The important thing is to make
57     sure that any such class that uses @c IntrusivePtr has all of its constructors and destructors
58     declared in the header and defined in the implementation translation unit. If the compiler
59     generates any of those, it will not compile due to missing functions or methods
60 
61   */
62 class IntrusivePtrCounter
63 {
64   template <typename T> friend class IntrusivePtr;
65 
66   using self_type = IntrusivePtrCounter;
67 
68 public:
69   /** Copy constructor.
70 
71       @internal We have to define this to explicitly _not_ copy the reference count. Otherwise any
72       client that uses a default copy constructor will _copy the ref count into the new object_.
73       That way lies madness.
74   */
75   IntrusivePtrCounter(self_type const &that);
76   /// No move constructor - that won't work for an object that is the target of a shared pointer.
77   IntrusivePtrCounter(self_type &&that) = delete;
78 
79   /** Assignment operator.
80 
81       @internal We need this for the same reason as the copy constructor. The reference count must
82       not be copied.
83    */
84   self_type &operator=(self_type const &that);
85   /// No move assignment - that won't work for an object that is the target of a shared pointer.
86   self_type &operator=(self_type &&that) = delete;
87 
88 protected:
89   /// The reference counter type is signed because detecting underflow is more important than having
90   /// more than 2G references.
91   using intrusive_ptr_reference_counter_type = long int;
92   /// The reference counter.
93   intrusive_ptr_reference_counter_type m_intrusive_pointer_reference_count{0};
94   /// Default constructor (0 init counter).
95   /// @internal Only subclasses can access this.
96   IntrusivePtrCounter();
97 };
98 
99 /** Atomic reference counting mixin.
100  */
101 class IntrusivePtrAtomicCounter
102 {
103   template <typename T> friend class IntrusivePtr;
104 
105   using self_type = IntrusivePtrAtomicCounter; ///< Self reference type.
106 
107 public:
108   /// Copy constructor - do not copy reference count.
109   IntrusivePtrAtomicCounter(self_type const &that);
110   /// No move constructor - that won't work for an object that is the target of a shared pointer.
111   IntrusivePtrAtomicCounter(self_type &&that) = delete;
112 
113   /// Self assignment - do not copy reference count.
114   self_type &operator=(self_type const &that);
115   /// No move assignment - that won't work for an object that is the target of a shared pointer.
116   self_type &operator=(self_type &&that) = delete;
117 
118 protected:
119   /// The reference counter type is signed because detecting underflow is more important than having
120   /// more than 2G references.
121   using intrusive_ptr_reference_counter_type = std::atomic<long int>;
122   /// The reference counter.
123   intrusive_ptr_reference_counter_type m_intrusive_pointer_reference_count{0};
124   /// Default constructor (0 init counter).
125   /// @internal Only subclasses can access this.
126   IntrusivePtrAtomicCounter();
127 };
128 
129 /* ----------------------------------------------------------------------- */
130 /** Intrusive shared pointer.
131 
132     This is a reference counted smart pointer. A single object is jointly ownded by a set of
133     pointers. When the last of the pointers is destructed the target object is also destructed.
134 
135     To use @c IntrusivePtr on type @a T, @a T must inherit from a reference counter class,
136     such as @c IntrusivePtrCounter or @c IntrusivePtrAtomicCounter. If this inheritance is @c public
137     then no other support is required. If the inheritance is not @c public then @a T must declare
138     @c IntrusivePtr<T> as a @c friend class.
139 
140     If it is not possible to have @a T inherit from a reference counter class, use @c std::shared_ptr.
141 
142     The smart pointer actions can be changed through class specific policy by specializing the @c
143     IntrusivePtrPolicy template class.
144 */
145 template <typename T> class IntrusivePtr
146 {
147 private:                                           /* don't pollute client with these typedefs */
148   using self_type = IntrusivePtr;                  ///< Self reference type.
149   template <typename U> friend class IntrusivePtr; // Make friends with siblings for cross type casts.
150 public:
151   /// The externally used type for the reference count.
152   using counter_type = long int;
153 
154   /// Default constructor (@c nullptr initialized).
155   IntrusivePtr();
156   /// Construct from instance.
157   /// The instance becomes referenced and owned by the pointer.
158   explicit IntrusivePtr(T *obj);
159   /// Destructor. If last referencing pointer, the contained instance is destroyed.
160   ~IntrusivePtr();
161 
162   /// Copy constructor. A new reference to the object is created.
163   IntrusivePtr(self_type const &that);
164   /// Move constructor. The reference in @a that is moved to @a this.
165   IntrusivePtr(self_type &&that);
166   /// Self assignment. A new reference to the object is created.
167   self_type &operator=(self_type const &that);
168   /// Move assignment. The reference in @a that is moved to @a this.
169   self_type &operator=(self_type &&that);
170 
171   /** Assign from instance.
172 
173       The instance becomes referenced and owned by the pointer. The reference to the current object
174       is dropped.
175 
176       @internal Direct assignment of a raw pointer was supported but I think that is too dangerous.
177   */
178   void reset(T *obj = nullptr);
179 
180   /** Clear reference without cleanup.
181 
182       This unsets this smart pointer and decrements the reference count, but does @b not perform any
183       finalization on the target object. This can easily lead to memory leaks and in some sense
184       vitiates the point of this class, but it is occasionally the right thing to do. Use with
185       caution.
186 
187       @internal Unfortunately this is current used and can't be removed at this time. Hopefully some
188       refactoring elsewhere will make it obsolete.
189 
190       @return @c true if there are no references upon return,
191       @c false if the reference count is not zero.
192    */
193   T *release();
194 
195   /// Test for not @c nullptr
196   explicit operator bool() const;
197 
198   /// Member dereference.
199   T *operator->() const;
200   /// Dereference.
201   T &operator*() const;
202   /// Access raw pointer.
203   T *get() const;
204 
205   /** User conversion to raw pointer.
206 
207       @internal allow implicit conversion to the underlying pointer which is one of the advantages
208       of intrusive pointers because the reference count doesn't get lost.
209 
210   */
211   operator T *() const;
212 
213   /** Cross type construction.
214       This succeeds if an @a U* can be implicitly converted to a @a T*.
215   */
216   template <typename U> IntrusivePtr(IntrusivePtr<U> const &that);
217 
218   template <typename U> IntrusivePtr(IntrusivePtr<U> &&that);
219 
220   /** Cross type assignment.
221       This succeeds if an @a U* can be implicitily converted to a @a T*.
222   */
223   template <typename U> self_type &operator=(IntrusivePtr<U> const &that);
224 
225   template <typename U> self_type &operator=(IntrusivePtr<U> &&that);
226 
227   /// Reference count.
228   /// @return Number of references.
229   counter_type use_count() const;
230 
231 private:
232   T *m_obj{nullptr}; ///< Pointer to object.
233 
234   /// Reference @a obj.
235   void set(T *obj);
236   /// Drop the current reference.
237   void unset();
238 };
239 
240 /** Pointer dynamic cast.
241 
242     This allows a smart pointer to be cast from one type to another.  It must be used when the types
243     do not implicitly convert (generally a downcast).
244 
245     @tparam T Type of the resulting intrusive pointer. Must be explicit.
246     @tparam U Type of the intrusive pointer @a src - can be deduced.
247     @param src The original intrusive pointer.
248     @return An intrusive pointer to @a T pointing at the same object as @a src.
249 
250     @code
251     class A { ... };
252     class B : public A { ... };
253     IntrusivePtr<A> really_b(new B);
254     InstruivePtr<B> the_b;
255     the_b = dynamic_ptr_cast<B>(really_b);
256     @endcode
257 */
258 template <typename T, typename U>
259 IntrusivePtr<T>
dynamic_ptr_cast(IntrusivePtr<U> const & src)260 dynamic_ptr_cast(IntrusivePtr<U> const &src)
261 {
262   return IntrusivePtr<T>(dynamic_cast<T *>(src.get()));
263 }
264 
265 /** Pointer cast.
266 
267     This allows a smart pointer to be cast from one type to another.
268     It must be used when the types do not implicitly convert (generally
269     a downcast). This uses @c static_cast and so performs only compile
270     time checks.
271 
272     @tparam T Type of the resulting intrusive pointer. Must be explicit.
273     @tparam U Type of the intrusive pointer @a src - can be deduced.
274     @param src The original intrusive pointer.
275     @return An intrusive pointer to @a T pointing at the same object as @a src.
276 
277     @code
278     class A { ... };
279     class B : public A { ... };
280     IntrusivePtr<A> really_b(new B);
281     IntrusivePtr<B> the_b;
282     the_b = ptr_cast<B>(really_b);
283     @endcode
284 */
285 template <typename T, typename U>
286 IntrusivePtr<T>
ptr_cast(IntrusivePtr<U> const & src)287 ptr_cast(IntrusivePtr<U> const &src)
288 {
289   return IntrusivePtr<T>(static_cast<T *>(src.get()));
290 }
291 /* ----------------------------------------------------------------------- */
292 /* ----------------------------------------------------------------------- */
293 /** Default policy class for intrusive pointers.
294 
295     This allows per type policy, although not per target instance. Clients can override policy by
296     specializing @c IntrusivePtrPolicy and inheriting from this class to provide default actions.
297 
298     @code
299     template <> IntrusivePtrPolicy<SomeType>
300       : IntrusivePtrDefaultPolicy<SomeType> {
301      ... Redefinition of methods and nested types ...
302     };
303     @endcode
304 
305     The inherited class will provide the default definitions so you can
306     override only what is different. Although this can be omitted if you
307     override everything, it is more robust for maintenance to inherit
308     anyway.
309 */
310 
311 template <typename T> class IntrusivePtrDefaultPolicy
312 {
313 public:
314   /// Called when the pointer is dereferenced.
315   /// Default is empty (no action).
316   static void dereferenceCheck(T *);
317 
318   /** Perform clean up on a target object that is no longer referenced.
319 
320       @param t Instance to finalize.
321 
322       Default is calling @c delete. Any specialization that overrides this @b must clean up the
323       object. The primary use of this is to perform a clean up other than @c delete.
324 
325       @note When this is called, the target object reference count is zero. If it is necessary to
326       pass a smart pointer to the target object, it will be necessary to call @c
327       IntrusivePtr::release to drop the reference without another finalization. Further care must be
328       taken that none of the called logic keeps a copy of the smart pointer. Use with caution.
329   */
330   static void finalize(T *t);
331 
332   /// Strict weak order for STL containers.
333   class Order : public std::binary_function<IntrusivePtr<T>, IntrusivePtr<T>, bool>
334   {
335   public:
336     /// Default constructor.
Order()337     Order() {}
338     /// Compare by raw pointer.
339     bool operator()(IntrusivePtr<T> const &lhs, IntrusivePtr<T> const &rhs) const;
340   };
341 };
342 
343 // If no specialization is provided then use the default;
344 template <typename T> struct IntrusivePtrPolicy : public IntrusivePtrDefaultPolicy<T> {
345 };
346 /* ----------------------------------------------------------------------- */
347 /* ----------------------------------------------------------------------- */
348 /* Inline Methods */
IntrusivePtrCounter()349 inline IntrusivePtrCounter::IntrusivePtrCounter() {}
350 
IntrusivePtrCounter(self_type const &)351 inline IntrusivePtrCounter::IntrusivePtrCounter(self_type const &) {}
352 
353 inline IntrusivePtrCounter &
354 IntrusivePtrCounter::operator=(self_type const &)
355 {
356   return *this;
357 }
358 
IntrusivePtrAtomicCounter()359 inline IntrusivePtrAtomicCounter::IntrusivePtrAtomicCounter() {}
360 
IntrusivePtrAtomicCounter(self_type const &)361 inline IntrusivePtrAtomicCounter::IntrusivePtrAtomicCounter(self_type const &) {}
362 
363 inline IntrusivePtrAtomicCounter &
364 IntrusivePtrAtomicCounter::operator=(self_type const &)
365 {
366   return *this;
367 }
368 
369 /* ----------------------------------------------------------------------- */
370 /* ----------------------------------------------------------------------- */
371 
372 template <typename T>
373 void
dereferenceCheck(T *)374 IntrusivePtrDefaultPolicy<T>::dereferenceCheck(T *)
375 {
376 }
377 
378 template <typename T>
379 void
finalize(T * obj)380 IntrusivePtrDefaultPolicy<T>::finalize(T *obj)
381 {
382   delete obj;
383 }
384 
385 template <typename T>
386 bool
operator()387 IntrusivePtrDefaultPolicy<T>::Order::operator()(IntrusivePtr<T> const &lhs, IntrusivePtr<T> const &rhs) const
388 {
389   return lhs.get() < rhs.get();
390 }
391 /* ----------------------------------------------------------------------- */
392 /* ----------------------------------------------------------------------- */
IntrusivePtr()393 template <typename T> IntrusivePtr<T>::IntrusivePtr() {}
394 
IntrusivePtr(T * obj)395 template <typename T> IntrusivePtr<T>::IntrusivePtr(T *obj)
396 {
397   this->set(obj);
398 }
399 
~IntrusivePtr()400 template <typename T> IntrusivePtr<T>::~IntrusivePtr()
401 {
402   this->unset();
403 }
404 
IntrusivePtr(self_type const & that)405 template <typename T> IntrusivePtr<T>::IntrusivePtr(self_type const &that)
406 {
407   this->set(that.m_obj);
408 }
409 
IntrusivePtr(IntrusivePtr<U> const & that)410 template <typename T> template <typename U> IntrusivePtr<T>::IntrusivePtr(IntrusivePtr<U> const &that)
411 {
412   static_assert(std::is_convertible<U *, T *>::value, "The argument type is not implicitly convertible to the return type.");
413   this->set(that.m_obj);
414 }
415 
IntrusivePtr(self_type && that)416 template <typename T> IntrusivePtr<T>::IntrusivePtr(self_type &&that)
417 {
418   std::swap<T *>(m_obj, that.m_obj);
419 }
420 
IntrusivePtr(IntrusivePtr<U> && that)421 template <typename T> template <typename U> IntrusivePtr<T>::IntrusivePtr(IntrusivePtr<U> &&that)
422 {
423   static_assert(std::is_convertible<U *, T *>::value, "The argument type is not implicitly convertible to the return type.");
424   std::swap<T *>(m_obj, that.get());
425 }
426 
427 template <typename T>
428 IntrusivePtr<T> &
429 IntrusivePtr<T>::operator=(self_type const &that)
430 {
431   this->reset(that.get());
432   return *this;
433 }
434 
435 template <typename T>
436 template <typename U>
437 IntrusivePtr<T> &
438 IntrusivePtr<T>::operator=(IntrusivePtr<U> const &that)
439 {
440   static_assert(std::is_convertible<U *, T *>::value, "The argument type is not implicitly convertible to the return type.");
441   this->reset(that.get());
442   return *this;
443 }
444 
445 template <typename T>
446 IntrusivePtr<T> &
447 IntrusivePtr<T>::operator=(self_type &&that)
448 {
449   if (m_obj != that.m_obj) {
450     this->unset();
451     m_obj      = that.m_obj;
452     that.m_obj = nullptr;
453   } else {
454     that.unset();
455   }
456   return *this;
457 }
458 
459 template <typename T>
460 template <typename U>
461 IntrusivePtr<T> &
462 IntrusivePtr<T>::operator=(IntrusivePtr<U> &&that)
463 {
464   static_assert(std::is_convertible<U *, T *>::value, "The argument type is not implicitly convertible to the return type.");
465   if (m_obj != that.m_obj) {
466     this->unset();
467     m_obj      = that.m_obj;
468     that.m_obj = nullptr;
469   } else {
470     that.unset();
471   }
472   return *this;
473 }
474 
475 template <typename T>
476 T *
477 IntrusivePtr<T>::operator->() const
478 {
479   IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
480   return m_obj;
481 }
482 
483 template <typename T>
484 T &
485 IntrusivePtr<T>::operator*() const
486 {
487   IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
488   return *m_obj;
489 }
490 
491 template <typename T>
492 T *
get()493 IntrusivePtr<T>::get() const
494 {
495   IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
496   return m_obj;
497 }
498 
499 /* The Set/Unset methods are the basic implementation of our
500  * reference counting. The Reset method is the standard way
501  * of invoking the pair, although splitting them allows some
502  * additional efficiency in certain situations.
503  */
504 
505 /* @c set and @c unset are two half operations that don't do checks.
506    It is the caller's responsibility to do that.
507 */
508 
509 template <typename T>
510 void
unset()511 IntrusivePtr<T>::unset()
512 {
513   if (nullptr != m_obj) {
514     auto &cp = m_obj->m_intrusive_pointer_reference_count;
515 
516     if (0 == --cp) {
517       IntrusivePtrPolicy<T>::finalize(m_obj);
518     }
519     m_obj = nullptr;
520   }
521 }
522 
523 template <typename T>
524 void
set(T * obj)525 IntrusivePtr<T>::set(T *obj)
526 {
527   m_obj = obj;          /* update to new object */
528   if (nullptr != m_obj) /* if a real object, bump the ref count */
529     ++(m_obj->m_intrusive_pointer_reference_count);
530 }
531 
532 template <typename T>
533 void
reset(T * obj)534 IntrusivePtr<T>::reset(T *obj)
535 {
536   if (obj != m_obj) {
537     this->unset();
538     this->set(obj);
539   }
540 }
541 
542 template <typename T>
543 T *
release()544 IntrusivePtr<T>::release()
545 {
546   T *zret = m_obj;
547   if (m_obj) {
548     auto &cp = m_obj->m_intrusive_pointer_reference_count;
549     // If the client is using this method, they're doing something funky
550     // so be extra careful with the reference count.
551     if (cp > 0)
552       --cp;
553     m_obj = nullptr;
554   }
555   return zret;
556 }
557 
558 template <typename T> IntrusivePtr<T>::operator bool() const
559 {
560   return m_obj != nullptr;
561 }
562 
563 /* Pointer comparison */
564 template <typename T>
565 bool
566 operator==(IntrusivePtr<T> const &lhs, IntrusivePtr<T> const &rhs)
567 {
568   return lhs.get() == rhs.get();
569 }
570 
571 template <typename T>
572 bool
573 operator!=(IntrusivePtr<T> const &lhs, IntrusivePtr<T> const &rhs)
574 {
575   return lhs.get() != rhs.get();
576 }
577 
578 template <typename T>
579 bool
580 operator<(IntrusivePtr<T> const &lhs, IntrusivePtr<T> const &rhs)
581 {
582   return lhs.get() < rhs.get();
583 }
584 
585 template <typename T> IntrusivePtr<T>::operator T *() const
586 {
587   return m_obj;
588 }
589 
590 template <typename T>
591 typename IntrusivePtr<T>::counter_type
use_count()592 IntrusivePtr<T>::use_count() const
593 {
594   return m_obj ? counter_type{m_obj->m_intrusive_pointer_reference_count} : counter_type{0};
595 }
596 /* ----------------------------------------------------------------------- */
597 /* ----------------------------------------------------------------------- */
598 } // namespace ts
599