Home | History | Annotate | Line # | Download | only in gdbsupport
      1 /* Reference-counted smart pointer class
      2 
      3    Copyright (C) 2016-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #ifndef GDBSUPPORT_GDB_REF_PTR_H
     21 #define GDBSUPPORT_GDB_REF_PTR_H
     22 
     23 #include <cstddef>
     24 
     25 namespace gdb
     26 {
     27 
     28 /* An instance of this class either holds a reference to a
     29    reference-counted object or is "NULL".  Reference counting is
     30    handled externally by a policy class.  If the object holds a
     31    reference, then when the object is destroyed, the reference is
     32    decref'd.
     33 
     34    Normally an instance is constructed using a pointer.  This sort of
     35    initialization lets this class manage the lifetime of that
     36    reference.
     37 
     38    Assignment and copy construction will make a new reference as
     39    appropriate.  Assignment from a plain pointer is disallowed to
     40    avoid confusion about whether this acquires a new reference;
     41    instead use the "reset" method -- which, like the pointer
     42    constructor, transfers ownership.
     43 
     44    The policy class must provide two static methods:
     45    void incref (T *);
     46    void decref (T *);
     47 */
     48 template<typename T, typename Policy>
     49 class ref_ptr
     50 {
     51  public:
     52 
     53   /* Create a new NULL instance.  */
     54   ref_ptr ()
     55     : m_obj (NULL)
     56   {
     57   }
     58 
     59   /* Create a new NULL instance.  Note that this is not explicit.  */
     60   ref_ptr (const std::nullptr_t)
     61     : m_obj (NULL)
     62   {
     63   }
     64 
     65   /* Create a new instance.  OBJ is a reference, management of which
     66      is now transferred to this class.  */
     67   explicit ref_ptr (T *obj)
     68     : m_obj (obj)
     69   {
     70   }
     71 
     72   /* Copy another instance.  */
     73   ref_ptr (const ref_ptr &other)
     74     : m_obj (other.m_obj)
     75   {
     76     if (m_obj != NULL)
     77       Policy::incref (m_obj);
     78   }
     79 
     80   /* Transfer ownership from OTHER.  */
     81   ref_ptr (ref_ptr &&other) noexcept
     82     : m_obj (other.m_obj)
     83   {
     84     other.m_obj = NULL;
     85   }
     86 
     87   /* Destroy this instance.  */
     88   ~ref_ptr ()
     89   {
     90     if (m_obj != NULL)
     91       Policy::decref (m_obj);
     92   }
     93 
     94   /* Copy another instance.  */
     95   ref_ptr &operator= (const ref_ptr &other)
     96   {
     97     /* Do nothing on self-assignment.  */
     98     if (this != &other)
     99       {
    100 	reset (other.m_obj);
    101 	if (m_obj != NULL)
    102 	  Policy::incref (m_obj);
    103       }
    104     return *this;
    105   }
    106 
    107   /* Transfer ownership from OTHER.  */
    108   ref_ptr &operator= (ref_ptr &&other)
    109   {
    110     /* Do nothing on self-assignment.  */
    111     if (this != &other)
    112       {
    113 	reset (other.m_obj);
    114 	other.m_obj = NULL;
    115       }
    116     return *this;
    117   }
    118 
    119   /* Change this instance's referent.  OBJ is a reference, management
    120      of which is now transferred to this class.  */
    121   void reset (T *obj)
    122   {
    123     if (m_obj != NULL)
    124       Policy::decref (m_obj);
    125     m_obj = obj;
    126   }
    127 
    128   /* Return this instance's referent without changing the state of
    129      this class.  */
    130   T *get () const
    131   {
    132     return m_obj;
    133   }
    134 
    135   /* Return this instance's referent, and stop managing this
    136      reference.  The caller is now responsible for the ownership of
    137      the reference.  */
    138   ATTRIBUTE_UNUSED_RESULT T *release ()
    139   {
    140     T *result = m_obj;
    141 
    142     m_obj = NULL;
    143     return result;
    144   }
    145 
    146   /* Let users refer to members of the underlying pointer.  */
    147   T *operator-> () const
    148   {
    149     return m_obj;
    150   }
    151 
    152   /* Acquire a new reference and return a ref_ptr that owns it.  */
    153   static ref_ptr<T, Policy> new_reference (T *obj)
    154   {
    155     Policy::incref (obj);
    156     return ref_ptr<T, Policy> (obj);
    157   }
    158 
    159  private:
    160 
    161   T *m_obj;
    162 };
    163 
    164 template<typename T, typename Policy>
    165 inline bool operator== (const ref_ptr<T, Policy> &lhs,
    166 			const ref_ptr<T, Policy> &rhs)
    167 {
    168   return lhs.get () == rhs.get ();
    169 }
    170 
    171 template<typename T, typename Policy>
    172 inline bool operator== (const ref_ptr<T, Policy> &lhs, const T *rhs)
    173 {
    174   return lhs.get () == rhs;
    175 }
    176 
    177 template<typename T, typename Policy>
    178 inline bool operator== (const ref_ptr<T, Policy> &lhs, const std::nullptr_t)
    179 {
    180   return lhs.get () == nullptr;
    181 }
    182 
    183 template<typename T, typename Policy>
    184 inline bool operator== (const T *lhs, const ref_ptr<T, Policy> &rhs)
    185 {
    186   return lhs == rhs.get ();
    187 }
    188 
    189 template<typename T, typename Policy>
    190 inline bool operator== (const std::nullptr_t, const ref_ptr<T, Policy> &rhs)
    191 {
    192   return nullptr == rhs.get ();
    193 }
    194 
    195 template<typename T, typename Policy>
    196 inline bool operator!= (const ref_ptr<T, Policy> &lhs,
    197 			const ref_ptr<T, Policy> &rhs)
    198 {
    199   return lhs.get () != rhs.get ();
    200 }
    201 
    202 template<typename T, typename Policy>
    203 inline bool operator!= (const ref_ptr<T, Policy> &lhs, const T *rhs)
    204 {
    205   return lhs.get () != rhs;
    206 }
    207 
    208 template<typename T, typename Policy>
    209 inline bool operator!= (const ref_ptr<T, Policy> &lhs, const std::nullptr_t)
    210 {
    211   return lhs.get () != nullptr;
    212 }
    213 
    214 template<typename T, typename Policy>
    215 inline bool operator!= (const T *lhs, const ref_ptr<T, Policy> &rhs)
    216 {
    217   return lhs != rhs.get ();
    218 }
    219 
    220 template<typename T, typename Policy>
    221 inline bool operator!= (const std::nullptr_t, const ref_ptr<T, Policy> &rhs)
    222 {
    223   return nullptr != rhs.get ();
    224 }
    225 
    226 }
    227 
    228 #endif /* GDBSUPPORT_GDB_REF_PTR_H */
    229