LCOV - code coverage report
Current view: top level - core/core/utils - SPRef.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 71 97.2 %
Date: 2024-05-12 00:16:13 Functions: 3500 4325 80.9 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_CORE_UTILS_SPREF_H_
      25             : #define STAPPLER_CORE_UTILS_SPREF_H_
      26             : 
      27             : #include "SPTime.h"
      28             : 
      29             : // enable Ref debug mode to track retain/release sources
      30             : #ifndef SP_REF_DEBUG
      31             : #define SP_REF_DEBUG 0
      32             : #endif
      33             : 
      34             : namespace STAPPLER_VERSIONIZED stappler {
      35             : 
      36             : struct AtomicCounter {
      37    10051766 :         AtomicCounter() { _count.store(1); }
      38             : 
      39    51565407 :         void increment() { ++ _count; }
      40   120863898 :         bool decrement() { if (_count.fetch_sub(1) == 1) { return true; } return false; }
      41      129068 :         uint32_t get() const { return _count.load(); }
      42             : 
      43             :         std::atomic<uint32_t> _count;
      44             : };
      45             : 
      46             : template <typename Interface>
      47             : class RefBase : public Interface::AllocBaseType {
      48             : public:
      49             :         using InterfaceType = Interface;
      50             : 
      51             : #if SP_REF_DEBUG
      52             :         virtual uint64_t retain();
      53             :         virtual void release(uint64_t id);
      54             : 
      55             :         void foreachBacktrace(const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &) const;
      56             : 
      57             : #else
      58    51590277 :         uint64_t retain() { _counter.increment(); return 0; }
      59    60471972 :         void release(uint64_t id) { if (_counter.decrement()) { delete this; } }
      60             : #endif
      61             : 
      62       64534 :         uint32_t getReferenceCount() const { return _counter.get(); }
      63             : 
      64    10052837 :         virtual ~RefBase() { }
      65             : 
      66             : protected:
      67    10051936 :         RefBase() { }
      68             : 
      69             : #if SP_REF_DEBUG
      70             :         virtual bool isRetainTrackerEnabled() const {
      71             :                 return false;
      72             :         }
      73             : #endif
      74             : 
      75             :         AtomicCounter _counter;
      76             : };
      77             : 
      78             : namespace memleak {
      79             : 
      80             : uint64_t getNextRefId();
      81             : uint64_t retainBacktrace(const RefBase<memory::StandartInterface> *);
      82             : void releaseBacktrace(const RefBase<memory::StandartInterface> *, uint64_t);
      83             : void foreachBacktrace(const RefBase<memory::StandartInterface> *,
      84             :                 const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &);
      85             : 
      86             : uint64_t retainBacktrace(const RefBase<memory::PoolInterface> *);
      87             : void releaseBacktrace(const RefBase<memory::PoolInterface> *, uint64_t);
      88             : void foreachBacktrace(const RefBase<memory::PoolInterface> *,
      89             :                 const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &);
      90             : }
      91             : 
      92             : template <typename Base>
      93             : class RcBase {
      94             : public:
      95             :         using Type = typename std::remove_cv<Base>::type;
      96             :         using Self = RcBase<Base>;
      97             :         using Pointer = Type *;
      98             : 
      99             :         template <class... Args>
     100     4698985 :         static inline Self create(Args && ... args) {
     101     8302568 :                 auto pRet = new Type();
     102     4699042 :             if (pRet->init(std::forward<Args>(args)...)) {
     103     4699005 :                 return Self(pRet, true); // unsafe assignment
     104             :                 } else {
     105           0 :                         delete pRet;
     106           0 :                         return Self(nullptr);
     107             :                 }
     108             :         }
     109             : 
     110      960860 :         static inline Self alloc() {
     111     1921636 :                 return Self(new Type(), true);
     112             :         }
     113             : 
     114             :         template <class... Args>
     115      600337 :         static inline Self alloc(Args && ... args) {
     116      600337 :                 return Self(new Type(std::forward<Args>(args)...), true);
     117             :         }
     118             : 
     119   438785095 :         inline RcBase() : _ptr(nullptr) { }
     120     1056905 :         inline RcBase(const nullptr_t &) : _ptr(nullptr) { }
     121     9364507 :         inline RcBase(const Pointer &value) : _ptr(value) { doRetain(); }
     122    13573449 :         inline RcBase(const Self &v) { _ptr = v._ptr; doRetain(); }
     123    14826825 :         inline RcBase(Self &&v) {
     124    14826825 :                 _ptr = v._ptr; v._ptr = nullptr;
     125             : #if SP_REF_DEBUG
     126             :                 _id = v._id; v._id = 0;
     127             : #endif
     128    14826825 :         }
     129             : 
     130     2413295 :         inline RcBase & operator = (const nullptr_t &) {
     131     2413295 :                 doRelease();
     132     2413381 :                 _ptr = nullptr;
     133             : #if SP_REF_DEBUG
     134             :                 _id = 0;
     135             : #endif
     136     2413381 :                 return *this;
     137             :         }
     138             : 
     139             :         template <typename B, typename std::enable_if<std::is_convertible<B*, Base *>{}>::type* = nullptr>
     140        1887 :         inline RcBase & operator = (const RcBase<B> &value) { set(value); return *this; }
     141             : 
     142      462043 :         inline RcBase & operator = (const Pointer &value) { set(value); return *this; }
     143     3989720 :         inline RcBase & operator = (const Self &v) { set(v._ptr); return *this; }
     144   224284901 :         inline RcBase & operator = (Self &&v) {
     145   224284901 :                 doRelease();
     146   224279957 :                 _ptr = v._ptr; v._ptr = nullptr;
     147             : #if SP_REF_DEBUG
     148             :                 _id = v._id; v._id = 0;
     149             : #endif
     150   224279957 :                 return *this;
     151             :         }
     152             : 
     153   231328096 :         inline ~RcBase() { doRelease(); _ptr = nullptr; }
     154             : 
     155     4409906 :         inline void set(const Pointer &value) {
     156     4409906 :                 _ptr = doSwap(value);
     157     4409907 :         }
     158             : 
     159    24979244 :         inline Base *get() const {
     160             : #if SP_REF_DEBUG
     161             :                 assert(_ptr);
     162             : #endif
     163    24979244 :                 return _ptr;
     164             :         }
     165             : 
     166    16232322 :         inline operator Base * () const { return get(); }
     167   468168195 :         inline explicit operator bool () const { return _ptr != nullptr; }
     168             : 
     169             :         template <typename B, typename std::enable_if<std::is_convertible<Base *, B*>{}>::type* = nullptr>
     170     5096923 :         inline operator RcBase<B> () { return RcBase<B>(static_cast<B *>(get())); }
     171             : 
     172             :         inline void swap(Self & v) { auto ptr = _ptr; _ptr = v._ptr; v._ptr = ptr; }
     173             : 
     174   143875478 :         inline Base * operator->() const { return _ptr; }
     175             : 
     176             :         template <typename Target>
     177      271059 :         inline RcBase<Target> cast() const {
     178      271059 :                 if (auto v = dynamic_cast<Target *>(_ptr)) {
     179      270274 :                         return RcBase<Target>(v);
     180             :                 }
     181         787 :                 return RcBase<Target>(nullptr);
     182             :         }
     183             : 
     184       10439 :         inline bool operator == (const Self & other) const { return _ptr == other._ptr; }
     185        8038 :         inline bool operator == (const Base * & other) const { return _ptr == other; }
     186     2500376 :         inline bool operator == (typename std::remove_const<Base>::type * other) const { return _ptr == other; }
     187       14638 :         inline bool operator == (const std::nullptr_t other) const { return _ptr == other; }
     188             : 
     189       69162 :         inline bool operator != (const Self & other) const { return _ptr != other._ptr; }
     190             :         inline bool operator != (const Base * & other) const { return _ptr != other; }
     191      226861 :         inline bool operator != (typename std::remove_const<Base>::type * other) const { return _ptr != other; }
     192        1464 :         inline bool operator != (const std::nullptr_t other) const { return _ptr != other; }
     193             : 
     194             :         inline bool operator > (const Self & other) const { return _ptr > other._ptr; }
     195             :         inline bool operator > (const Base * other) const { return _ptr > other; }
     196             :         inline bool operator > (typename std::remove_const<Base>::type * other) const { return _ptr > other; }
     197             :         inline bool operator > (const std::nullptr_t other) const { return _ptr > other; }
     198             : 
     199     9993800 :         inline bool operator < (const Self & other) const { return _ptr < other._ptr; }
     200         812 :         inline bool operator < (const Base * other) const { return _ptr < other; }
     201             :         inline bool operator < (typename std::remove_const<Base>::type * other) const { return _ptr < other; }
     202             :         inline bool operator < (const std::nullptr_t other) const { return _ptr < other; }
     203             : 
     204             :         inline bool operator >= (const Self & other) const { return _ptr >= other._ptr; }
     205             :         inline bool operator >= (const Base * other) const { return _ptr >= other; }
     206             :         inline bool operator >= (typename std::remove_const<Base>::type * other) const { return _ptr >= other; }
     207             :         inline bool operator >= (const std::nullptr_t other) const { return _ptr >= other; }
     208             : 
     209             :         inline bool operator <= (const Self & other) const { return _ptr <= other._ptr; }
     210             :         inline bool operator <= (const Base * other) const { return _ptr <= other; }
     211             :         inline bool operator <= (typename std::remove_const<Base>::type * other) const { return _ptr <= other; }
     212             :         inline bool operator <= (const std::nullptr_t other) const { return _ptr <= other; }
     213             : 
     214             : #if SP_REF_DEBUG
     215             :         uint64_t getId() const { return _id; }
     216             : #endif
     217             : private:
     218    19899190 :         inline void doRetain() {
     219             : #if SP_REF_DEBUG
     220             :                 if (_ptr) { _id = _ptr->retain(); }
     221             : #else
     222    19899190 :                 if (_ptr) { _ptr->retain(); }
     223             : #endif
     224    19901775 :         }
     225             : 
     226   327312258 :         inline void doRelease() {
     227             : #if SP_REF_DEBUG
     228             :                 if (_ptr) { _ptr->release(_id); }
     229             : #else
     230   327312258 :                 if (_ptr) { _ptr->release(0); }
     231             : #endif
     232   327318149 :         }
     233             : 
     234     4409905 :         inline Pointer doSwap(Pointer value) {
     235             : #if SP_REF_DEBUG
     236             :                 uint64_t id = 0;
     237             :                 if (value) { id = value->retain(); }
     238             :                 if (_ptr) { _ptr->release(_id); }
     239             :                 _id = id;
     240             :                 return value;
     241             : #else
     242     4409905 :                 if (value) { value->retain(); }
     243     4409914 :                 if (_ptr) { _ptr->release(0); }
     244     4409910 :                 return value;
     245             : #endif
     246             :         }
     247             : 
     248             :         // unsafe
     249     5761488 :         inline RcBase(Pointer value, bool v) : _ptr(value) { }
     250             : 
     251             :         Pointer _ptr = nullptr;
     252             : #if SP_REF_DEBUG
     253             :         uint64_t _id = 0;
     254             : #endif
     255             : };
     256             : 
     257             : template <typename T>
     258             : using Rc = RcBase<T>;
     259             : 
     260             : #if SP_REF_DEBUG
     261             : 
     262             : template <typename Interface>
     263             : uint64_t RefBase<Interface>::retain() {
     264             :         _counter.increment();
     265             :         if (isRetainTrackerEnabled()) {
     266             :                 return memleak::retainBacktrace(this);
     267             :         }
     268             :         return 0;
     269             : }
     270             : 
     271             : template <typename Interface>
     272             : void RefBase<Interface>::release(uint64_t v) {
     273             :         if (isRetainTrackerEnabled()) {
     274             :                 memleak::releaseBacktrace(this, v);
     275             :         }
     276             :         if (_counter.decrement()) {
     277             :                 delete this;
     278             :         }
     279             : }
     280             : 
     281             : template <typename Interface>
     282             : void RefBase<Interface>::foreachBacktrace(const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &cb) const {
     283             :         memleak::foreachBacktrace(this, cb);
     284             : }
     285             : 
     286             : #endif
     287             : 
     288             : }
     289             : 
     290             : namespace STAPPLER_VERSIONIZED stappler::mem_std {
     291             : 
     292             : using Ref = RefBase<memory::StandartInterface>;
     293             : 
     294             : }
     295             : 
     296             : namespace STAPPLER_VERSIONIZED stappler::mem_pool {
     297             : 
     298             : using Ref = RefBase<memory::PoolInterface>;
     299             : 
     300             : }
     301             : 
     302             : #endif /* STAPPLER_CORE_UTILS_REF_SPREF_H_ */

Generated by: LCOV version 1.14