Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2025 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * This file defines a C++ referenced counted object that auto deletes when
21 : * all references to it have been removed.
22 : */
23 :
24 : #pragma once
25 :
26 : #include <atomic>
27 : #include <limits>
28 : #include <stdlib.h>
29 :
30 : #include <lib/support/CHIPMem.h>
31 : #include <lib/support/CodeUtils.h>
32 :
33 : namespace chip {
34 :
35 : template <class T>
36 : class DeleteDeletor
37 : {
38 : public:
39 4 : static void Release(T * obj) { chip::Platform::Delete(obj); }
40 : };
41 :
42 : template <class T>
43 : class NoopDeletor
44 : {
45 : public:
46 399 : static void Release(T * obj) {}
47 : };
48 :
49 : template <typename T>
50 : class ReferenceCountedPtr;
51 :
52 : /**
53 : * Like ReferenceCounted but with protected visibility of reference count management.
54 : * Use ReferenceCountedPtr<T> to automatically increment/decrement the ref count.
55 : *
56 : * NOTE: The default kInitRefCount here is 0, unlike ReferenceCounted where it's 1
57 : * The reason for this is that the expectation is that the owner of this object will
58 : * immediately wrap it in a `ReferenceCountedPtr` before exposing it to callers, which
59 : * will increment the count to 1.
60 : */
61 : template <class Subclass, class Deletor, int kInitRefCount = 0, typename CounterType = uint32_t>
62 : class ReferenceCountedProtected
63 : {
64 : public:
65 : /** Get the current reference counter value */
66 25071 : CounterType GetReferenceCount() const { return mRefCount; }
67 :
68 : protected:
69 : friend class ReferenceCountedPtr<Subclass>;
70 :
71 : /** Adds one to the usage count of this class */
72 908466 : Subclass * Ref()
73 : {
74 : if constexpr (kInitRefCount)
75 : {
76 42864 : VerifyOrDie(mRefCount > 0);
77 : }
78 908466 : VerifyOrDie(mRefCount < std::numeric_limits<CounterType>::max());
79 908466 : ++mRefCount;
80 :
81 908466 : return static_cast<Subclass *>(this);
82 : }
83 :
84 : /**
85 : * Decrements the reference count by 1;
86 : * Not called "Release" to avoid confusion with Pool::Release & Deletor::Release
87 : */
88 913065 : void Unref()
89 : {
90 913065 : VerifyOrDie(mRefCount != 0);
91 :
92 913065 : if (--mRefCount == 0)
93 : {
94 140752 : Deletor::Release(static_cast<Subclass *>(this));
95 : }
96 913065 : }
97 :
98 : private:
99 : CounterType mRefCount = kInitRefCount;
100 : };
101 :
102 : /**
103 : * A reference counted object maintains a count of usages and when the usage
104 : * count drops to 0, it deletes itself.
105 : */
106 : template <class Subclass, class Deletor = DeleteDeletor<Subclass>, int kInitRefCount = 1, typename CounterType = uint32_t>
107 : class ReferenceCounted : public ReferenceCountedProtected<Subclass, Deletor, kInitRefCount, CounterType>
108 : {
109 : public:
110 : /** Backwards compatibility; consider using ReferenceCountedProtected instead. */
111 907843 : Subclass * Retain() { return this->Ref(); }
112 :
113 : /** Backwards compatibility; consider using ReferenceCountedProtected instead. */
114 912442 : void Release() { this->Unref(); }
115 : };
116 :
117 : } // namespace chip
|