1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef UTILS_BASE_SINGLETON_H
17 #define UTILS_BASE_SINGLETON_H
18
19 #include "nocopyable.h"
20 #include <mutex>
21 #include <memory>
22
23 namespace OHOS {
24
25 /**
26 * The purpose of the following macro definitions is to reduce the need
27 * to write repetitive code when defining singleton classes on the client side.
28 *
29 * Taking DelayedSingleton as an example, when declaring the target class as a
30 * singleton, add the DECLARE_DELAYED_SINGLETON (class_name) to the class
31 * declaration.\n
32 * When using the target singleton, call class_name::GetInstance()->.
33 */
34
35 /**
36 * @brief Set `MyClass` as a `DelayedSingleton`.
37 *
38 * `MyClass` object can be obtained by calling
39 * `DelayedSingleton<MyClass>::GetInstance()`.
40 *
41 * @param MyClass Target class to be set as a singleton.
42 * @note This macro definition should be used into the body of a class
43 * definition.
44 */
45 #define DECLARE_DELAYED_SINGLETON(MyClass)\
46 public:\
47 ~MyClass();\
48 private:\
49 friend DelayedSingleton<MyClass>;\
50 MyClass();
51
52 /**
53 * @brief Set `MyClass` as a `DelayedRefSingleton`.
54 *
55 * `MyClass` object can be obtained by calling
56 * `DelayedRefSingleton<MyClass>::GetInstance()`.
57 *
58 * @param MyClass Target class to be set as a singleton.
59 * @note This macro definition should be used into the body of a class
60 * definition.
61 */
62 #define DECLARE_DELAYED_REF_SINGLETON(MyClass)\
63 private:\
64 friend DelayedRefSingleton<MyClass>;\
65 ~MyClass();\
66 MyClass();
67
68 /**
69 * @brief Set `MyClass` as a `Singleton`.
70 *
71 * `MyClass` object can be obtained by calling
72 * `Singleton<MyClass>::GetInstance()`.
73 *
74 * @param MyClass Target class to be set as a singleton.
75 * @note This macro definition should be used into the body of a class
76 * definition.
77 */
78 #define DECLARE_SINGLETON(MyClass)\
79 private:\
80 friend Singleton<MyClass>;\
81 MyClass& operator=(const MyClass&) = delete;\
82 MyClass(const MyClass&) = delete;\
83 MyClass();\
84 ~MyClass();
85
86 /**
87 * @brief class DelayedSingleton is a thread-safe, memory-safe lazy initialized
88 * singleton (with smart pointer and lock).
89 */
90 template<typename T>
91 class DelayedSingleton : public NoCopyable {
92 public:
93 /**
94 * @brief Create a unique instance object and return.
95 *
96 * Use smart pointer to manage resources, and when all shared_ptrs are
97 * destroyed, the new object will also be deleted. This avoids memory
98 * leaks.\n
99 * Lock is added only when the pointer is empty to avoid locking every time
100 * the `GetInstance()` method is called, reducing the overhead of lock.
101 */
102 static std::shared_ptr<T> GetInstance();
103 /**
104 * @brief Release the ownership of managed object of the smart pointer.
105 *
106 * @note After calling this method, the 'GetInstance()' method will create
107 * a new object, and if the old object has an external 'std::shared_ptr'
108 * reference, the developer needs to release it himself to guarantee a
109 * singleton.
110 */
111 static void DestroyInstance();
112
113 private:
114 static std::shared_ptr<T> instance_;
115 static std::mutex mutex_;
116 };
117
118 template<typename T>
119 std::shared_ptr<T> DelayedSingleton<T>::instance_ = nullptr;
120
121 template<typename T>
122 std::mutex DelayedSingleton<T>::mutex_;
123
124 template<typename T>
GetInstance()125 std::shared_ptr<T> DelayedSingleton<T>::GetInstance()
126 {
127 if (instance_ == nullptr) {
128 std::lock_guard<std::mutex> lock(mutex_);
129 if (instance_ == nullptr) {
130 std::shared_ptr<T> temp(new (std::nothrow) T);
131 instance_ = temp;
132 }
133 }
134
135 return instance_;
136 }
137
138 template<typename T>
DestroyInstance()139 void DelayedSingleton<T>::DestroyInstance()
140 {
141 std::lock_guard<std::mutex> lock(mutex_);
142 if (instance_ != nullptr) {
143 instance_.reset();
144 instance_ = nullptr;
145 }
146 }
147
148 /**
149 * @brief class DelayedRefSingleton is a thread-safe, lazy initialized
150 * singleton(with ordinary pointer and lock).
151 */
152 template<typename T>
153 class DelayedRefSingleton : public NoCopyable {
154 public:
155 /**
156 * @brief Create a unique instance object and return.
157 *
158 * Pointer is used in the implementation, and the return type is a
159 * reference:the instance returned by reference has a lifetime that is
160 * managed by non-user code.
161 *
162 * @note The instance may not have been created at a certain point in time,
163 * or it can be deleted, which cannot prevent the user from using delete
164 * keyword to cause the object to be destroyed in advance.
165 */
166 static T& GetInstance();
167
168 private:
169 static T* instance_; // Record the DelayedRefSingleton instance created.
170 static std::mutex mutex_;
171 };
172
173 template<typename T>
174 T* DelayedRefSingleton<T>::instance_ = nullptr;
175
176 template<typename T>
177 std::mutex DelayedRefSingleton<T>::mutex_;
178
179 template<typename T>
GetInstance()180 T& DelayedRefSingleton<T>::GetInstance()
181 {
182 if (instance_ == nullptr) {
183 std::lock_guard<std::mutex> lock(mutex_);
184 if (instance_ == nullptr) {
185 instance_ = new T();
186 }
187 }
188
189 return *instance_;
190 }
191
192 /**
193 * @brief class Singleton is a normal initialized singleton(no pointers and
194 * locks are used).
195 */
196 template<typename T>
197 class Singleton : public NoCopyable {
198 public:
199
200 /**
201 * @brief Return a unique instance object.
202 */
GetInstance()203 static T& GetInstance() { return instance_; }
204
205 private:
206 static T instance_;
207 };
208
209 template<typename T>
210 T Singleton<T>::instance_;
211 } // namespace OHOS
212
213 #endif
214