Home | History | Annotate | Download | only in util
      1 //
      2 // Copyright 2013 Francisco Jerez
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a
      5 // copy of this software and associated documentation files (the "Software"),
      6 // to deal in the Software without restriction, including without limitation
      7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 // and/or sell copies of the Software, and to permit persons to whom the
      9 // Software is furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 // OTHER DEALINGS IN THE SOFTWARE.
     21 //
     22 
     23 #ifndef CLOVER_UTIL_POINTER_HPP
     24 #define CLOVER_UTIL_POINTER_HPP
     25 
     26 #include <atomic>
     27 
     28 namespace clover {
     29    ///
     30    /// Base class for objects that support reference counting.
     31    ///
     32    class ref_counter {
     33    public:
     34       ref_counter(unsigned value = 1) : _ref_count(value) {}
     35 
     36       unsigned
     37       ref_count() const {
     38          return _ref_count;
     39       }
     40 
     41       void
     42       retain() {
     43          _ref_count++;
     44       }
     45 
     46       bool
     47       release() {
     48          return (--_ref_count) == 0;
     49       }
     50 
     51    private:
     52       std::atomic<unsigned> _ref_count;
     53    };
     54 
     55    ///
     56    /// Simple reference to a clover::ref_counter object.  Unlike
     57    /// clover::intrusive_ptr and clover::intrusive_ref, it does nothing
     58    /// special when the reference count drops to zero.
     59    ///
     60    class ref_holder {
     61    public:
     62       ref_holder(ref_counter &o) : p(&o) {
     63          p->retain();
     64       }
     65 
     66       ref_holder(const ref_holder &ref) :
     67          ref_holder(*ref.p) {
     68       }
     69 
     70       ref_holder(ref_holder &&ref) :
     71          p(ref.p) {
     72          ref.p = NULL;
     73       }
     74 
     75       ~ref_holder() {
     76          if (p)
     77             p->release();
     78       }
     79 
     80       ref_holder &
     81       operator=(ref_holder ref) {
     82          std::swap(ref.p, p);
     83          return *this;
     84       }
     85 
     86       bool
     87       operator==(const ref_holder &ref) const {
     88          return p == ref.p;
     89       }
     90 
     91       bool
     92       operator!=(const ref_holder &ref) const {
     93          return p != ref.p;
     94       }
     95 
     96    private:
     97       ref_counter *p;
     98    };
     99 
    100    ///
    101    /// Intrusive smart pointer for objects that implement the
    102    /// clover::ref_counter interface.
    103    ///
    104    template<typename T>
    105    class intrusive_ptr {
    106    public:
    107       intrusive_ptr(T *q = NULL) : p(q) {
    108          if (p)
    109             p->retain();
    110       }
    111 
    112       intrusive_ptr(const intrusive_ptr &ptr) :
    113          intrusive_ptr(ptr.p) {
    114       }
    115 
    116       intrusive_ptr(intrusive_ptr &&ptr) :
    117          p(ptr.p) {
    118          ptr.p = NULL;
    119       }
    120 
    121       ~intrusive_ptr() {
    122          if (p && p->release())
    123             delete p;
    124       }
    125 
    126       intrusive_ptr &
    127       operator=(intrusive_ptr ptr) {
    128          std::swap(ptr.p, p);
    129          return *this;
    130       }
    131 
    132       bool
    133       operator==(const intrusive_ptr &ref) const {
    134          return p == ref.p;
    135       }
    136 
    137       bool
    138       operator!=(const intrusive_ptr &ref) const {
    139          return p != ref.p;
    140       }
    141 
    142       T &
    143       operator*() const {
    144          return *p;
    145       }
    146 
    147       T *
    148       operator->() const {
    149          return p;
    150       }
    151 
    152       T *
    153       operator()() const {
    154          return p;
    155       }
    156 
    157       explicit operator bool() const {
    158          return p;
    159       }
    160 
    161       explicit operator T *() const {
    162          return p;
    163       }
    164 
    165    private:
    166       T *p;
    167    };
    168 
    169    ///
    170    /// Intrusive smart reference for objects that implement the
    171    /// clover::ref_counter interface.
    172    ///
    173    template<typename T>
    174    class intrusive_ref {
    175    public:
    176       intrusive_ref(T &o) : p(&o) {
    177          p->retain();
    178       }
    179 
    180       intrusive_ref(const intrusive_ref &ref) :
    181          intrusive_ref(*ref.p) {
    182       }
    183 
    184       intrusive_ref(intrusive_ref &&ref) :
    185          p(ref.p) {
    186          ref.p = NULL;
    187       }
    188 
    189       ~intrusive_ref() {
    190          if (p && p->release())
    191             delete p;
    192       }
    193 
    194       intrusive_ref &
    195       operator=(intrusive_ref ref) {
    196          std::swap(ref.p, p);
    197          return *this;
    198       }
    199 
    200       bool
    201       operator==(const intrusive_ref &ref) const {
    202          return p == ref.p;
    203       }
    204 
    205       bool
    206       operator!=(const intrusive_ref &ref) const {
    207          return p != ref.p;
    208       }
    209 
    210       T &
    211       operator()() const {
    212          return *p;
    213       }
    214 
    215       operator T &() const {
    216          return *p;
    217       }
    218 
    219    private:
    220       T *p;
    221    };
    222 
    223    ///
    224    /// Initialize a clover::intrusive_ref from a newly created object
    225    /// using the specified constructor arguments.
    226    ///
    227    template<typename T, typename... As>
    228    intrusive_ref<T>
    229    create(As &&... as) {
    230       intrusive_ref<T> ref { *new T(std::forward<As>(as)...) };
    231       ref().release();
    232       return ref;
    233    }
    234 
    235    ///
    236    /// Class that implements the usual pointer interface but in fact
    237    /// contains the object it seems to be pointing to.
    238    ///
    239    template<typename T>
    240    class pseudo_ptr {
    241    public:
    242       pseudo_ptr(T x) : x(x) {
    243       }
    244 
    245       pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
    246       }
    247 
    248       pseudo_ptr &
    249       operator=(const pseudo_ptr &p) {
    250          x = p.x;
    251          return *this;
    252       }
    253 
    254       T &
    255       operator*() {
    256          return x;
    257       }
    258 
    259       T *
    260       operator->() {
    261          return &x;
    262       }
    263 
    264       explicit operator bool() const {
    265          return true;
    266       }
    267 
    268    private:
    269       T x;
    270    };
    271 }
    272 
    273 #endif
    274