1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QTHREADSTORAGE_H
41 #define QTHREADSTORAGE_H
42 
43 #include <QtCore/qglobal.h>
44 
45 #if QT_CONFIG(thread)
46 
47 QT_BEGIN_NAMESPACE
48 
49 
50 class Q_CORE_EXPORT QThreadStorageData
51 {
52 public:
53     explicit QThreadStorageData(void (*func)(void *));
54     ~QThreadStorageData();
55 
56     void** get() const;
57     void** set(void* p);
58 
59     static void finish(void**);
60     int id;
61 };
62 
63 #if !defined(QT_MOC_CPP)
64 // MOC_SKIP_BEGIN
65 
66 // pointer specialization
67 template <typename T>
68 inline
qThreadStorage_localData(QThreadStorageData & d,T **)69 T *&qThreadStorage_localData(QThreadStorageData &d, T **)
70 {
71     void **v = d.get();
72     if (!v) v = d.set(nullptr);
73     return *(reinterpret_cast<T**>(v));
74 }
75 
76 template <typename T>
77 inline
qThreadStorage_localData_const(const QThreadStorageData & d,T **)78 T *qThreadStorage_localData_const(const QThreadStorageData &d, T **)
79 {
80     void **v = d.get();
81     return v ? *(reinterpret_cast<T**>(v)) : 0;
82 }
83 
84 template <typename T>
85 inline
qThreadStorage_setLocalData(QThreadStorageData & d,T ** t)86 void qThreadStorage_setLocalData(QThreadStorageData &d, T **t)
87 { (void) d.set(*t); }
88 
89 template <typename T>
90 inline
qThreadStorage_deleteData(void * d,T **)91 void qThreadStorage_deleteData(void *d, T **)
92 { delete static_cast<T *>(d); }
93 
94 // value-based specialization
95 template <typename T>
96 inline
qThreadStorage_localData(QThreadStorageData & d,T *)97 T &qThreadStorage_localData(QThreadStorageData &d, T *)
98 {
99     void **v = d.get();
100     if (!v) v = d.set(new T());
101     return *(reinterpret_cast<T*>(*v));
102 }
103 
104 template <typename T>
105 inline
qThreadStorage_localData_const(const QThreadStorageData & d,T *)106 T qThreadStorage_localData_const(const QThreadStorageData &d, T *)
107 {
108     void **v = d.get();
109     return v ? *(reinterpret_cast<T*>(*v)) : T();
110 }
111 
112 template <typename T>
113 inline
qThreadStorage_setLocalData(QThreadStorageData & d,T * t)114 void qThreadStorage_setLocalData(QThreadStorageData &d, T *t)
115 { (void) d.set(new T(*t)); }
116 
117 template <typename T>
118 inline
qThreadStorage_deleteData(void * d,T *)119 void qThreadStorage_deleteData(void *d, T *)
120 { delete static_cast<T *>(d); }
121 
122 
123 // MOC_SKIP_END
124 #endif
125 
126 template <class T>
127 class QThreadStorage
128 {
129 private:
130     QThreadStorageData d;
131 
Q_DISABLE_COPY(QThreadStorage)132     Q_DISABLE_COPY(QThreadStorage)
133 
134     static inline void deleteData(void *x)
135     { qThreadStorage_deleteData(x, reinterpret_cast<T*>(0)); }
136 
137 public:
QThreadStorage()138     inline QThreadStorage() : d(deleteData) { }
~QThreadStorage()139     inline ~QThreadStorage() { }
140 
hasLocalData()141     inline bool hasLocalData() const
142     { return d.get() != nullptr; }
143 
localData()144     inline T& localData()
145     { return qThreadStorage_localData(d, reinterpret_cast<T*>(0)); }
localData()146     inline T localData() const
147     { return qThreadStorage_localData_const(d, reinterpret_cast<T*>(0)); }
148 
setLocalData(T t)149     inline void setLocalData(T t)
150     { qThreadStorage_setLocalData(d, &t); }
151 };
152 
153 QT_END_NAMESPACE
154 
155 #else // !QT_CONFIG(thread)
156 
157 #include <QtCore/qscopedpointer.h>
158 
159 #include <type_traits>
160 
161 template <typename T, typename U>
162 inline bool qThreadStorage_hasLocalData(const QScopedPointer<T, U> &data)
163 {
164     return !!data;
165 }
166 
167 template <typename T, typename U>
168 inline bool qThreadStorage_hasLocalData(const QScopedPointer<T*, U> &data)
169 {
170     return !!data ? *data != nullptr : false;
171 }
172 
173 template <typename T>
174 inline void qThreadStorage_deleteLocalData(T *t)
175 {
176     delete t;
177 }
178 
179 template <typename T>
180 inline void qThreadStorage_deleteLocalData(T **t)
181 {
182     delete *t;
183     delete t;
184 }
185 
186 template <class T>
187 class QThreadStorage
188 {
189 private:
190     struct ScopedPointerThreadStorageDeleter
191     {
192         static inline void cleanup(T *t)
193         {
194             if (t == nullptr)
195                 return;
196             qThreadStorage_deleteLocalData(t);
197         }
198     };
199     QScopedPointer<T, ScopedPointerThreadStorageDeleter> data;
200 
201 public:
202     QThreadStorage() = default;
203     ~QThreadStorage() = default;
204     QThreadStorage(const QThreadStorage &rhs) = delete;
205     QThreadStorage &operator=(const QThreadStorage &rhs) = delete;
206 
207     inline bool hasLocalData() const
208     {
209         return qThreadStorage_hasLocalData(data);
210     }
211 
212     inline T& localData()
213     {
214         if (!data)
215             data.reset(new T());
216         return *data;
217     }
218 
219     inline T localData() const
220     {
221         return !!data ? *data : T();
222     }
223 
224     inline void setLocalData(T t)
225     {
226         data.reset(new T(t));
227     }
228 };
229 
230 #endif // QT_CONFIG(thread)
231 
232 #endif // QTHREADSTORAGE_H
233