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