17ec681f3Smrg//
27ec681f3Smrg// Copyright 2013 Francisco Jerez
37ec681f3Smrg//
47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg// copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg// to deal in the Software without restriction, including without limitation
77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg// Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg//
117ec681f3Smrg// The above copyright notice and this permission notice shall be included in
127ec681f3Smrg// all copies or substantial portions of the Software.
137ec681f3Smrg//
147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE.
217ec681f3Smrg//
227ec681f3Smrg
237ec681f3Smrg#ifndef CLOVER_UTIL_POINTER_HPP
247ec681f3Smrg#define CLOVER_UTIL_POINTER_HPP
257ec681f3Smrg
267ec681f3Smrg#include <atomic>
277ec681f3Smrg
287ec681f3Smrgnamespace clover {
297ec681f3Smrg   ///
307ec681f3Smrg   /// Some helper functions for raw pointer operations
317ec681f3Smrg   ///
327ec681f3Smrg   template <class T>
337ec681f3Smrg   static bool
347ec681f3Smrg   ptr_is_aligned(const T *ptr, uintptr_t a) noexcept {
357ec681f3Smrg      assert(a == (a & -a));
367ec681f3Smrg      uintptr_t ptr_value = reinterpret_cast<uintptr_t>(ptr);
377ec681f3Smrg      return (ptr_value & (a - 1)) == 0;
387ec681f3Smrg   }
397ec681f3Smrg
407ec681f3Smrg   ///
417ec681f3Smrg   /// Base class for objects that support reference counting.
427ec681f3Smrg   ///
437ec681f3Smrg   class ref_counter {
447ec681f3Smrg   public:
457ec681f3Smrg      ref_counter(unsigned value = 1) : _ref_count(value) {}
467ec681f3Smrg
477ec681f3Smrg      unsigned
487ec681f3Smrg      ref_count() const {
497ec681f3Smrg         return _ref_count;
507ec681f3Smrg      }
517ec681f3Smrg
527ec681f3Smrg      void
537ec681f3Smrg      retain() {
547ec681f3Smrg         _ref_count++;
557ec681f3Smrg      }
567ec681f3Smrg
577ec681f3Smrg      bool
587ec681f3Smrg      release() {
597ec681f3Smrg         return (--_ref_count) == 0;
607ec681f3Smrg      }
617ec681f3Smrg
627ec681f3Smrg   private:
637ec681f3Smrg      std::atomic<unsigned> _ref_count;
647ec681f3Smrg   };
657ec681f3Smrg
667ec681f3Smrg   ///
677ec681f3Smrg   /// Simple reference to a clover::ref_counter object.  Unlike
687ec681f3Smrg   /// clover::intrusive_ptr and clover::intrusive_ref, it does nothing
697ec681f3Smrg   /// special when the reference count drops to zero.
707ec681f3Smrg   ///
717ec681f3Smrg   class ref_holder {
727ec681f3Smrg   public:
737ec681f3Smrg      ref_holder(ref_counter &o) : p(&o) {
747ec681f3Smrg         p->retain();
757ec681f3Smrg      }
767ec681f3Smrg
777ec681f3Smrg      ref_holder(const ref_holder &ref) :
787ec681f3Smrg         ref_holder(*ref.p) {
797ec681f3Smrg      }
807ec681f3Smrg
817ec681f3Smrg      ref_holder(ref_holder &&ref) :
827ec681f3Smrg         p(ref.p) {
837ec681f3Smrg         ref.p = NULL;
847ec681f3Smrg      }
857ec681f3Smrg
867ec681f3Smrg      ~ref_holder() {
877ec681f3Smrg         if (p)
887ec681f3Smrg            p->release();
897ec681f3Smrg      }
907ec681f3Smrg
917ec681f3Smrg      ref_holder &
927ec681f3Smrg      operator=(ref_holder ref) {
937ec681f3Smrg         std::swap(ref.p, p);
947ec681f3Smrg         return *this;
957ec681f3Smrg      }
967ec681f3Smrg
977ec681f3Smrg      bool
987ec681f3Smrg      operator==(const ref_holder &ref) const {
997ec681f3Smrg         return p == ref.p;
1007ec681f3Smrg      }
1017ec681f3Smrg
1027ec681f3Smrg      bool
1037ec681f3Smrg      operator!=(const ref_holder &ref) const {
1047ec681f3Smrg         return p != ref.p;
1057ec681f3Smrg      }
1067ec681f3Smrg
1077ec681f3Smrg   private:
1087ec681f3Smrg      ref_counter *p;
1097ec681f3Smrg   };
1107ec681f3Smrg
1117ec681f3Smrg   ///
1127ec681f3Smrg   /// Intrusive smart pointer for objects that implement the
1137ec681f3Smrg   /// clover::ref_counter interface.
1147ec681f3Smrg   ///
1157ec681f3Smrg   template<typename T>
1167ec681f3Smrg   class intrusive_ptr {
1177ec681f3Smrg   public:
1187ec681f3Smrg      intrusive_ptr(T *q = NULL) : p(q) {
1197ec681f3Smrg         if (p)
1207ec681f3Smrg            p->retain();
1217ec681f3Smrg      }
1227ec681f3Smrg
1237ec681f3Smrg      intrusive_ptr(const intrusive_ptr &ptr) :
1247ec681f3Smrg         intrusive_ptr(ptr.p) {
1257ec681f3Smrg      }
1267ec681f3Smrg
1277ec681f3Smrg      intrusive_ptr(intrusive_ptr &&ptr) :
1287ec681f3Smrg         p(ptr.p) {
1297ec681f3Smrg         ptr.p = NULL;
1307ec681f3Smrg      }
1317ec681f3Smrg
1327ec681f3Smrg      ~intrusive_ptr() {
1337ec681f3Smrg         if (p && p->release())
1347ec681f3Smrg            delete p;
1357ec681f3Smrg      }
1367ec681f3Smrg
1377ec681f3Smrg      intrusive_ptr &
1387ec681f3Smrg      operator=(intrusive_ptr ptr) {
1397ec681f3Smrg         std::swap(ptr.p, p);
1407ec681f3Smrg         return *this;
1417ec681f3Smrg      }
1427ec681f3Smrg
1437ec681f3Smrg      bool
1447ec681f3Smrg      operator==(const intrusive_ptr &ref) const {
1457ec681f3Smrg         return p == ref.p;
1467ec681f3Smrg      }
1477ec681f3Smrg
1487ec681f3Smrg      bool
1497ec681f3Smrg      operator!=(const intrusive_ptr &ref) const {
1507ec681f3Smrg         return p != ref.p;
1517ec681f3Smrg      }
1527ec681f3Smrg
1537ec681f3Smrg      T &
1547ec681f3Smrg      operator*() const {
1557ec681f3Smrg         return *p;
1567ec681f3Smrg      }
1577ec681f3Smrg
1587ec681f3Smrg      T *
1597ec681f3Smrg      operator->() const {
1607ec681f3Smrg         return p;
1617ec681f3Smrg      }
1627ec681f3Smrg
1637ec681f3Smrg      T *
1647ec681f3Smrg      operator()() const {
1657ec681f3Smrg         return p;
1667ec681f3Smrg      }
1677ec681f3Smrg
1687ec681f3Smrg      explicit operator bool() const {
1697ec681f3Smrg         return p;
1707ec681f3Smrg      }
1717ec681f3Smrg
1727ec681f3Smrg      explicit operator T *() const {
1737ec681f3Smrg         return p;
1747ec681f3Smrg      }
1757ec681f3Smrg
1767ec681f3Smrg   private:
1777ec681f3Smrg      T *p;
1787ec681f3Smrg   };
1797ec681f3Smrg
1807ec681f3Smrg   ///
1817ec681f3Smrg   /// Intrusive smart reference for objects that implement the
1827ec681f3Smrg   /// clover::ref_counter interface.
1837ec681f3Smrg   ///
1847ec681f3Smrg   template<typename T>
1857ec681f3Smrg   class intrusive_ref {
1867ec681f3Smrg   public:
1877ec681f3Smrg      intrusive_ref(T &o) : p(&o) {
1887ec681f3Smrg         p->retain();
1897ec681f3Smrg      }
1907ec681f3Smrg
1917ec681f3Smrg      intrusive_ref(const intrusive_ref &ref) :
1927ec681f3Smrg         intrusive_ref(*ref.p) {
1937ec681f3Smrg      }
1947ec681f3Smrg
1957ec681f3Smrg      intrusive_ref(intrusive_ref &&ref) :
1967ec681f3Smrg         p(ref.p) {
1977ec681f3Smrg         ref.p = NULL;
1987ec681f3Smrg      }
1997ec681f3Smrg
2007ec681f3Smrg      ~intrusive_ref() {
2017ec681f3Smrg         if (p && p->release())
2027ec681f3Smrg            delete p;
2037ec681f3Smrg      }
2047ec681f3Smrg
2057ec681f3Smrg      intrusive_ref &
2067ec681f3Smrg      operator=(intrusive_ref ref) {
2077ec681f3Smrg         std::swap(ref.p, p);
2087ec681f3Smrg         return *this;
2097ec681f3Smrg      }
2107ec681f3Smrg
2117ec681f3Smrg      bool
2127ec681f3Smrg      operator==(const intrusive_ref &ref) const {
2137ec681f3Smrg         return p == ref.p;
2147ec681f3Smrg      }
2157ec681f3Smrg
2167ec681f3Smrg      bool
2177ec681f3Smrg      operator!=(const intrusive_ref &ref) const {
2187ec681f3Smrg         return p != ref.p;
2197ec681f3Smrg      }
2207ec681f3Smrg
2217ec681f3Smrg      T &
2227ec681f3Smrg      operator()() const {
2237ec681f3Smrg         return *p;
2247ec681f3Smrg      }
2257ec681f3Smrg
2267ec681f3Smrg      operator T &() const {
2277ec681f3Smrg         return *p;
2287ec681f3Smrg      }
2297ec681f3Smrg
2307ec681f3Smrg   private:
2317ec681f3Smrg      T *p;
2327ec681f3Smrg   };
2337ec681f3Smrg
2347ec681f3Smrg   ///
2357ec681f3Smrg   /// Initialize a clover::intrusive_ref from a newly created object
2367ec681f3Smrg   /// using the specified constructor arguments.
2377ec681f3Smrg   ///
2387ec681f3Smrg   template<typename T, typename... As>
2397ec681f3Smrg   intrusive_ref<T>
2407ec681f3Smrg   create(As &&... as) {
2417ec681f3Smrg      intrusive_ref<T> ref { *new T(std::forward<As>(as)...) };
2427ec681f3Smrg      ref().release();
2437ec681f3Smrg      return ref;
2447ec681f3Smrg   }
2457ec681f3Smrg
2467ec681f3Smrg   ///
2477ec681f3Smrg   /// Class that implements the usual pointer interface but in fact
2487ec681f3Smrg   /// contains the object it seems to be pointing to.
2497ec681f3Smrg   ///
2507ec681f3Smrg   template<typename T>
2517ec681f3Smrg   class pseudo_ptr {
2527ec681f3Smrg   public:
2537ec681f3Smrg      pseudo_ptr(T x) : x(x) {
2547ec681f3Smrg      }
2557ec681f3Smrg
2567ec681f3Smrg      pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
2577ec681f3Smrg      }
2587ec681f3Smrg
2597ec681f3Smrg      pseudo_ptr &
2607ec681f3Smrg      operator=(const pseudo_ptr &p) {
2617ec681f3Smrg         x = p.x;
2627ec681f3Smrg         return *this;
2637ec681f3Smrg      }
2647ec681f3Smrg
2657ec681f3Smrg      T &
2667ec681f3Smrg      operator*() {
2677ec681f3Smrg         return x;
2687ec681f3Smrg      }
2697ec681f3Smrg
2707ec681f3Smrg      T *
2717ec681f3Smrg      operator->() {
2727ec681f3Smrg         return &x;
2737ec681f3Smrg      }
2747ec681f3Smrg
2757ec681f3Smrg      explicit operator bool() const {
2767ec681f3Smrg         return true;
2777ec681f3Smrg      }
2787ec681f3Smrg
2797ec681f3Smrg   private:
2807ec681f3Smrg      T x;
2817ec681f3Smrg   };
2827ec681f3Smrg}
2837ec681f3Smrg
2847ec681f3Smrg#endif
285