17d62b00eSchristos /* Reference-counted smart pointer class 27d62b00eSchristos 3*6881a400Schristos Copyright (C) 2016-2023 Free Software Foundation, Inc. 47d62b00eSchristos 57d62b00eSchristos This file is part of GDB. 67d62b00eSchristos 77d62b00eSchristos This program is free software; you can redistribute it and/or modify 87d62b00eSchristos it under the terms of the GNU General Public License as published by 97d62b00eSchristos the Free Software Foundation; either version 3 of the License, or 107d62b00eSchristos (at your option) any later version. 117d62b00eSchristos 127d62b00eSchristos This program is distributed in the hope that it will be useful, 137d62b00eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 147d62b00eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157d62b00eSchristos GNU General Public License for more details. 167d62b00eSchristos 177d62b00eSchristos You should have received a copy of the GNU General Public License 187d62b00eSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 197d62b00eSchristos 207d62b00eSchristos #ifndef COMMON_GDB_REF_PTR_H 217d62b00eSchristos #define COMMON_GDB_REF_PTR_H 227d62b00eSchristos 237d62b00eSchristos #include <cstddef> 247d62b00eSchristos 257d62b00eSchristos namespace gdb 267d62b00eSchristos { 277d62b00eSchristos 287d62b00eSchristos /* An instance of this class either holds a reference to a 297d62b00eSchristos reference-counted object or is "NULL". Reference counting is 307d62b00eSchristos handled externally by a policy class. If the object holds a 317d62b00eSchristos reference, then when the object is destroyed, the reference is 327d62b00eSchristos decref'd. 337d62b00eSchristos 347d62b00eSchristos Normally an instance is constructed using a pointer. This sort of 357d62b00eSchristos initialization lets this class manage the lifetime of that 367d62b00eSchristos reference. 377d62b00eSchristos 387d62b00eSchristos Assignment and copy construction will make a new reference as 397d62b00eSchristos appropriate. Assignment from a plain pointer is disallowed to 407d62b00eSchristos avoid confusion about whether this acquires a new reference; 417d62b00eSchristos instead use the "reset" method -- which, like the pointer 427d62b00eSchristos constructor, transfers ownership. 437d62b00eSchristos 447d62b00eSchristos The policy class must provide two static methods: 457d62b00eSchristos void incref (T *); 467d62b00eSchristos void decref (T *); 477d62b00eSchristos */ 487d62b00eSchristos template<typename T, typename Policy> 497d62b00eSchristos class ref_ptr 507d62b00eSchristos { 517d62b00eSchristos public: 527d62b00eSchristos 537d62b00eSchristos /* Create a new NULL instance. */ 547d62b00eSchristos ref_ptr () 557d62b00eSchristos : m_obj (NULL) 567d62b00eSchristos { 577d62b00eSchristos } 587d62b00eSchristos 597d62b00eSchristos /* Create a new NULL instance. Note that this is not explicit. */ 607d62b00eSchristos ref_ptr (const std::nullptr_t) 617d62b00eSchristos : m_obj (NULL) 627d62b00eSchristos { 637d62b00eSchristos } 647d62b00eSchristos 657d62b00eSchristos /* Create a new instance. OBJ is a reference, management of which 667d62b00eSchristos is now transferred to this class. */ 677d62b00eSchristos explicit ref_ptr (T *obj) 687d62b00eSchristos : m_obj (obj) 697d62b00eSchristos { 707d62b00eSchristos } 717d62b00eSchristos 727d62b00eSchristos /* Copy another instance. */ 737d62b00eSchristos ref_ptr (const ref_ptr &other) 747d62b00eSchristos : m_obj (other.m_obj) 757d62b00eSchristos { 767d62b00eSchristos if (m_obj != NULL) 777d62b00eSchristos Policy::incref (m_obj); 787d62b00eSchristos } 797d62b00eSchristos 807d62b00eSchristos /* Transfer ownership from OTHER. */ 817d62b00eSchristos ref_ptr (ref_ptr &&other) noexcept 827d62b00eSchristos : m_obj (other.m_obj) 837d62b00eSchristos { 847d62b00eSchristos other.m_obj = NULL; 857d62b00eSchristos } 867d62b00eSchristos 877d62b00eSchristos /* Destroy this instance. */ 887d62b00eSchristos ~ref_ptr () 897d62b00eSchristos { 907d62b00eSchristos if (m_obj != NULL) 917d62b00eSchristos Policy::decref (m_obj); 927d62b00eSchristos } 937d62b00eSchristos 947d62b00eSchristos /* Copy another instance. */ 957d62b00eSchristos ref_ptr &operator= (const ref_ptr &other) 967d62b00eSchristos { 977d62b00eSchristos /* Do nothing on self-assignment. */ 987d62b00eSchristos if (this != &other) 997d62b00eSchristos { 1007d62b00eSchristos reset (other.m_obj); 1017d62b00eSchristos if (m_obj != NULL) 1027d62b00eSchristos Policy::incref (m_obj); 1037d62b00eSchristos } 1047d62b00eSchristos return *this; 1057d62b00eSchristos } 1067d62b00eSchristos 1077d62b00eSchristos /* Transfer ownership from OTHER. */ 1087d62b00eSchristos ref_ptr &operator= (ref_ptr &&other) 1097d62b00eSchristos { 1107d62b00eSchristos /* Do nothing on self-assignment. */ 1117d62b00eSchristos if (this != &other) 1127d62b00eSchristos { 1137d62b00eSchristos reset (other.m_obj); 1147d62b00eSchristos other.m_obj = NULL; 1157d62b00eSchristos } 1167d62b00eSchristos return *this; 1177d62b00eSchristos } 1187d62b00eSchristos 1197d62b00eSchristos /* Change this instance's referent. OBJ is a reference, management 1207d62b00eSchristos of which is now transferred to this class. */ 1217d62b00eSchristos void reset (T *obj) 1227d62b00eSchristos { 1237d62b00eSchristos if (m_obj != NULL) 1247d62b00eSchristos Policy::decref (m_obj); 1257d62b00eSchristos m_obj = obj; 1267d62b00eSchristos } 1277d62b00eSchristos 1287d62b00eSchristos /* Return this instance's referent without changing the state of 1297d62b00eSchristos this class. */ 1307d62b00eSchristos T *get () const 1317d62b00eSchristos { 1327d62b00eSchristos return m_obj; 1337d62b00eSchristos } 1347d62b00eSchristos 1357d62b00eSchristos /* Return this instance's referent, and stop managing this 1367d62b00eSchristos reference. The caller is now responsible for the ownership of 1377d62b00eSchristos the reference. */ 1387d62b00eSchristos ATTRIBUTE_UNUSED_RESULT T *release () 1397d62b00eSchristos { 1407d62b00eSchristos T *result = m_obj; 1417d62b00eSchristos 1427d62b00eSchristos m_obj = NULL; 1437d62b00eSchristos return result; 1447d62b00eSchristos } 1457d62b00eSchristos 1467d62b00eSchristos /* Let users refer to members of the underlying pointer. */ 1477d62b00eSchristos T *operator-> () const 1487d62b00eSchristos { 1497d62b00eSchristos return m_obj; 1507d62b00eSchristos } 1517d62b00eSchristos 1527d62b00eSchristos /* Acquire a new reference and return a ref_ptr that owns it. */ 1537d62b00eSchristos static ref_ptr<T, Policy> new_reference (T *obj) 1547d62b00eSchristos { 1557d62b00eSchristos Policy::incref (obj); 1567d62b00eSchristos return ref_ptr<T, Policy> (obj); 1577d62b00eSchristos } 1587d62b00eSchristos 1597d62b00eSchristos private: 1607d62b00eSchristos 1617d62b00eSchristos T *m_obj; 1627d62b00eSchristos }; 1637d62b00eSchristos 1647d62b00eSchristos template<typename T, typename Policy> 1657d62b00eSchristos inline bool operator== (const ref_ptr<T, Policy> &lhs, 1667d62b00eSchristos const ref_ptr<T, Policy> &rhs) 1677d62b00eSchristos { 1687d62b00eSchristos return lhs.get () == rhs.get (); 1697d62b00eSchristos } 1707d62b00eSchristos 1717d62b00eSchristos template<typename T, typename Policy> 1727d62b00eSchristos inline bool operator== (const ref_ptr<T, Policy> &lhs, const T *rhs) 1737d62b00eSchristos { 1747d62b00eSchristos return lhs.get () == rhs; 1757d62b00eSchristos } 1767d62b00eSchristos 1777d62b00eSchristos template<typename T, typename Policy> 1787d62b00eSchristos inline bool operator== (const ref_ptr<T, Policy> &lhs, const std::nullptr_t) 1797d62b00eSchristos { 1807d62b00eSchristos return lhs.get () == nullptr; 1817d62b00eSchristos } 1827d62b00eSchristos 1837d62b00eSchristos template<typename T, typename Policy> 1847d62b00eSchristos inline bool operator== (const T *lhs, const ref_ptr<T, Policy> &rhs) 1857d62b00eSchristos { 1867d62b00eSchristos return lhs == rhs.get (); 1877d62b00eSchristos } 1887d62b00eSchristos 1897d62b00eSchristos template<typename T, typename Policy> 1907d62b00eSchristos inline bool operator== (const std::nullptr_t, const ref_ptr<T, Policy> &rhs) 1917d62b00eSchristos { 1927d62b00eSchristos return nullptr == rhs.get (); 1937d62b00eSchristos } 1947d62b00eSchristos 1957d62b00eSchristos template<typename T, typename Policy> 1967d62b00eSchristos inline bool operator!= (const ref_ptr<T, Policy> &lhs, 1977d62b00eSchristos const ref_ptr<T, Policy> &rhs) 1987d62b00eSchristos { 1997d62b00eSchristos return lhs.get () != rhs.get (); 2007d62b00eSchristos } 2017d62b00eSchristos 2027d62b00eSchristos template<typename T, typename Policy> 2037d62b00eSchristos inline bool operator!= (const ref_ptr<T, Policy> &lhs, const T *rhs) 2047d62b00eSchristos { 2057d62b00eSchristos return lhs.get () != rhs; 2067d62b00eSchristos } 2077d62b00eSchristos 2087d62b00eSchristos template<typename T, typename Policy> 2097d62b00eSchristos inline bool operator!= (const ref_ptr<T, Policy> &lhs, const std::nullptr_t) 2107d62b00eSchristos { 2117d62b00eSchristos return lhs.get () != nullptr; 2127d62b00eSchristos } 2137d62b00eSchristos 2147d62b00eSchristos template<typename T, typename Policy> 2157d62b00eSchristos inline bool operator!= (const T *lhs, const ref_ptr<T, Policy> &rhs) 2167d62b00eSchristos { 2177d62b00eSchristos return lhs != rhs.get (); 2187d62b00eSchristos } 2197d62b00eSchristos 2207d62b00eSchristos template<typename T, typename Policy> 2217d62b00eSchristos inline bool operator!= (const std::nullptr_t, const ref_ptr<T, Policy> &rhs) 2227d62b00eSchristos { 2237d62b00eSchristos return nullptr != rhs.get (); 2247d62b00eSchristos } 2257d62b00eSchristos 2267d62b00eSchristos } 2277d62b00eSchristos 2287d62b00eSchristos #endif /* COMMON_GDB_REF_PTR_H */ 229