Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OGR 4 : * Purpose: Smart pointer around a class that has built-in reference counting. 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2026, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #ifndef OGR_REFCOUNTEDPTR_INCLUDED 14 : #define OGR_REFCOUNTEDPTR_INCLUDED 15 : 16 : /*! @cond Doxygen_Suppress */ 17 : 18 : #include <cstddef> 19 : #include <utility> 20 : 21 : /** Base (non-instantiable) class for OGRRefCountedPtr. 22 : * 23 : * Only intended to be used as the base class for OGRRefCountedPtr. 24 : * Done that way so its constructor is protected and force specializations 25 : * of redefining a public one (calling it) 26 : */ 27 : template <class T> struct OGRRefCountedPtrBase 28 : { 29 : public: 30 : /** Destructor. 31 : * 32 : * Release the raw pointer, that is decrease its reference count and delete 33 : * the object when it reaches zero. 34 : */ 35 39013 : inline ~OGRRefCountedPtrBase() 36 : { 37 39013 : reset(nullptr); 38 39013 : } 39 : 40 : /** Copy constructor. 41 : * 42 : * Increases the reference count 43 : */ 44 1059 : inline OGRRefCountedPtrBase(const OGRRefCountedPtrBase &other) 45 1059 : : OGRRefCountedPtrBase(other.m_poRawPtr, true) 46 : { 47 1059 : } 48 : 49 : /** Copy constructor 50 : * 51 : * Set the raw pointer to the one used by other, and increase the reference 52 : * count. 53 : */ 54 : // cppcheck-suppress operatorEqVarError 55 199 : inline OGRRefCountedPtrBase &operator=(const OGRRefCountedPtrBase &other) 56 : { 57 199 : if (this != &other) 58 : { 59 199 : reset(other.m_poRawPtr); 60 : } 61 199 : return *this; 62 : } 63 : 64 : /** Move constructor 65 : * 66 : * Borrows the raw pointer managed by other, without changing its reference 67 : * count, and set the managed raw pointer of other to null. 68 : */ 69 2293 : inline OGRRefCountedPtrBase(OGRRefCountedPtrBase &&other) 70 2293 : { 71 2293 : std::swap(m_poRawPtr, other.m_poRawPtr); 72 2293 : } 73 : 74 : /** Move assignment operator. 75 : * 76 : * Release the current managed raw pointer and borrow the 77 : * one from other. 78 : * Does not change the reference count of the borrowed raw pointer. 79 : */ 80 7898 : inline OGRRefCountedPtrBase &operator=(OGRRefCountedPtrBase &&other) 81 : { 82 7898 : reset(nullptr); 83 7898 : std::swap(m_poRawPtr, other.m_poRawPtr); 84 7898 : return *this; 85 : } 86 : 87 : /** Reset the managed raw pointer. 88 : * 89 : * Release the current managed raw pointer and manages a new one. 90 : * By default, increases the reference count of the new raw pointer (when 91 : * not null). 92 : */ 93 47445 : inline void reset(T *poRawPtr = nullptr, bool add_ref = true) 94 : { 95 : #ifdef __GNUC__ 96 : #pragma GCC diagnostic push 97 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 98 : #endif 99 47445 : if (m_poRawPtr) 100 10213 : m_poRawPtr->Release(); 101 47445 : m_poRawPtr = poRawPtr; 102 47445 : if (m_poRawPtr && add_ref) 103 321 : m_poRawPtr->Reference(); 104 : #ifdef __GNUC__ 105 : #pragma GCC diagnostic pop 106 : #endif 107 47445 : } 108 : 109 : /** Returns the raw pointer without changing its reference count */ 110 43041 : inline T *get() const 111 : { 112 43041 : return m_poRawPtr; 113 : } 114 : 115 : /** Returns a reference to the raw pointer without changing its reference 116 : * count. 117 : * 118 : * Must be only called when get() != nullptr. 119 : */ 120 342 : inline T &operator*() const 121 : { 122 342 : return *m_poRawPtr; 123 : } 124 : 125 : /** Forwards the access to a member or a call to a method of the raw 126 : * pointer. 127 : */ 128 28408 : inline T *operator->() const 129 : { 130 28408 : return m_poRawPtr; 131 : } 132 : 133 : /** Returns whether the raw pointer is null. */ 134 5932 : inline explicit operator bool() const 135 : { 136 5932 : return m_poRawPtr != nullptr; 137 : } 138 : 139 : protected: 140 36720 : inline explicit OGRRefCountedPtrBase(T *poRawPtr = nullptr, 141 : bool add_ref = true) 142 36720 : : m_poRawPtr(poRawPtr) 143 : { 144 : #ifdef __GNUC__ 145 : #pragma GCC diagnostic push 146 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 147 : #endif 148 36720 : if (m_poRawPtr && add_ref) 149 1285 : m_poRawPtr->Reference(); 150 : #ifdef __GNUC__ 151 : #pragma GCC diagnostic pop 152 : #endif 153 36720 : } 154 : 155 : private: 156 : T *m_poRawPtr{}; 157 : }; 158 : 159 : /** Smart pointer around a class that has built-in reference counting. 160 : * 161 : * It uses the Reference() and Release() methods of the wrapped class for 162 : * reference counting. The reference count is increased when assigning a raw 163 : * pointer to the smart pointer, and decreased when releasing it. 164 : * Somewhat similar to https://www.boost.org/doc/libs/latest/libs/smart_ptr/doc/html/smart_ptr.html#intrusive_ptr 165 : * 166 : * Only meant for T = OGRFeatureDefn and OGRSpatialReference 167 : */ 168 : template <class T> struct OGRRefCountedPtr : public OGRRefCountedPtrBase<T> 169 : { 170 : }; 171 : 172 : template <class T> 173 3056 : inline bool operator==(const OGRRefCountedPtr<T> &lhs, std::nullptr_t) 174 : { 175 3056 : return lhs.get() == nullptr; 176 : } 177 : 178 : template <class T> 179 : inline bool operator==(std::nullptr_t, const OGRRefCountedPtr<T> &rhs) 180 : { 181 : return rhs.get() == nullptr; 182 : } 183 : 184 : template <class T> 185 3337 : inline bool operator!=(const OGRRefCountedPtr<T> &lhs, std::nullptr_t) 186 : { 187 3337 : return lhs.get() != nullptr; 188 : } 189 : 190 : template <class T> 191 : inline bool operator!=(std::nullptr_t, const OGRRefCountedPtr<T> &rhs) 192 : { 193 : return rhs.get() != nullptr; 194 : } 195 : 196 : /*! @endcond */ 197 : 198 : #endif /* OGR_REFCOUNTEDPTR_INCLUDED */