/src/libreoffice/include/comphelper/singletonref.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | #pragma once |
20 | | |
21 | | #include <sal/config.h> |
22 | | #include <sal/log.hxx> |
23 | | #include <mutex> |
24 | | |
25 | | namespace comphelper |
26 | | { |
27 | | /** @short Template for implementing singleton classes. |
28 | | This is a replacement for salhelper::SingletonRef, but which uses std::mutex instead of osl::Mutex. |
29 | | |
30 | | Such classes can be instantiated every time they |
31 | | are needed. But the internal wrapped object will |
32 | | be created one times only. Of course it's used |
33 | | resources are referenced one times only too. |
34 | | This template hold it alive till the last |
35 | | reference is gone. Further all operations |
36 | | on this reference are threadsafe. Only |
37 | | calls directly to the internal object (which modify |
38 | | its state) must be made threadsafe by the object itself |
39 | | or from outside. |
40 | | |
41 | | @attention To prevent the code against race conditions, it's not |
42 | | allowed to start operations inside the ctor |
43 | | of the internal wrapped object - especially operations |
44 | | which needs a reference to the same singleton too. |
45 | | |
46 | | The only chance to suppress such strange constellations |
47 | | is a lazy-init mechanism. |
48 | | |
49 | | <ul> |
50 | | <li>a) The singleton class can provide a special init() |
51 | | method, which must be called as first after creation.</li> |
52 | | <li>b) The singleton class can call a special impl_init() |
53 | | method implicit for every called interface method.</li> |
54 | | </ul> |
55 | | |
56 | | Note further that this singleton pattern can work only, if |
57 | | all user of such singleton are located inside the same library! |
58 | | Because static values can't be exported - e.g. from windows libraries. |
59 | | */ |
60 | | template <class SingletonClass> class SingletonRef |
61 | | { |
62 | | // member |
63 | | |
64 | | private: |
65 | | /** @short pointer to the internal wrapped singleton. */ |
66 | | static SingletonClass* m_pInstance; |
67 | | |
68 | | /** @short ref count, which regulate creation and removing of m_pInstance. */ |
69 | | static sal_Int32 m_nRef; |
70 | | |
71 | | // interface |
72 | | |
73 | | public: |
74 | | /** @short standard ctor. |
75 | | |
76 | | The internal wrapped object is created only, |
77 | | if its ref count was 0. Otherwise this method |
78 | | does nothing ... except increasing of the internal |
79 | | ref count! |
80 | | */ |
81 | | SingletonRef() |
82 | 1.05M | { |
83 | | // GLOBAL SAFE -> |
84 | 1.05M | std::unique_lock aLock(SingletonRef::ownStaticLock()); |
85 | | |
86 | | // must be increased before(!) the check is done. |
87 | | // Otherwise this check can fail inside the same thread ... |
88 | 1.05M | ++m_nRef; |
89 | 1.05M | if (m_nRef == 1) |
90 | 10.3k | m_pInstance = new SingletonClass(); |
91 | | |
92 | 1.05M | SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper", |
93 | 1.05M | "Race? Ref count of singleton >0, but instance is NULL!"); |
94 | | // <- GLOBAL SAFE |
95 | 1.05M | } comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::SingletonRef() Line | Count | Source | 82 | 10.3k | { | 83 | | // GLOBAL SAFE -> | 84 | 10.3k | std::unique_lock aLock(SingletonRef::ownStaticLock()); | 85 | | | 86 | | // must be increased before(!) the check is done. | 87 | | // Otherwise this check can fail inside the same thread ... | 88 | 10.3k | ++m_nRef; | 89 | 10.3k | if (m_nRef == 1) | 90 | 10.3k | m_pInstance = new SingletonClass(); | 91 | | | 92 | 10.3k | SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper", | 93 | 10.3k | "Race? Ref count of singleton >0, but instance is NULL!"); | 94 | | // <- GLOBAL SAFE | 95 | 10.3k | } |
comphelper::SingletonRef<connectivity::DriversConfigImpl>::SingletonRef() Line | Count | Source | 82 | 1.04M | { | 83 | | // GLOBAL SAFE -> | 84 | 1.04M | std::unique_lock aLock(SingletonRef::ownStaticLock()); | 85 | | | 86 | | // must be increased before(!) the check is done. | 87 | | // Otherwise this check can fail inside the same thread ... | 88 | 1.04M | ++m_nRef; | 89 | 1.04M | if (m_nRef == 1) | 90 | 1 | m_pInstance = new SingletonClass(); | 91 | | | 92 | 1.04M | SAL_WARN_IF(!(m_nRef > 0 && m_pInstance), "comphelper", | 93 | 1.04M | "Race? Ref count of singleton >0, but instance is NULL!"); | 94 | | // <- GLOBAL SAFE | 95 | 1.04M | } |
|
96 | | |
97 | | /** @short standard dtor. |
98 | | |
99 | | The internal wrapped object is removed only, |
100 | | if its ref count will be 0. Otherwise this method |
101 | | does nothing ... except decreasing of the internal |
102 | | ref count! |
103 | | */ |
104 | | ~SingletonRef() |
105 | 1.05M | { |
106 | | // GLOBAL SAFE -> |
107 | 1.05M | std::unique_lock aLock(SingletonRef::ownStaticLock()); |
108 | | |
109 | | // must be decreased before(!) the check is done. |
110 | | // Otherwise this check can fail inside the same thread ... |
111 | 1.05M | --m_nRef; |
112 | 1.05M | if (m_nRef == 0) |
113 | 10.3k | { |
114 | 10.3k | delete m_pInstance; |
115 | 10.3k | m_pInstance = nullptr; |
116 | 10.3k | } |
117 | | // <- GLOBAL SAFE |
118 | 1.05M | } comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::~SingletonRef() Line | Count | Source | 105 | 10.3k | { | 106 | | // GLOBAL SAFE -> | 107 | 10.3k | std::unique_lock aLock(SingletonRef::ownStaticLock()); | 108 | | | 109 | | // must be decreased before(!) the check is done. | 110 | | // Otherwise this check can fail inside the same thread ... | 111 | 10.3k | --m_nRef; | 112 | 10.3k | if (m_nRef == 0) | 113 | 10.3k | { | 114 | 10.3k | delete m_pInstance; | 115 | 10.3k | m_pInstance = nullptr; | 116 | 10.3k | } | 117 | | // <- GLOBAL SAFE | 118 | 10.3k | } |
comphelper::SingletonRef<connectivity::DriversConfigImpl>::~SingletonRef() Line | Count | Source | 105 | 1.04M | { | 106 | | // GLOBAL SAFE -> | 107 | 1.04M | std::unique_lock aLock(SingletonRef::ownStaticLock()); | 108 | | | 109 | | // must be decreased before(!) the check is done. | 110 | | // Otherwise this check can fail inside the same thread ... | 111 | 1.04M | --m_nRef; | 112 | 1.04M | if (m_nRef == 0) | 113 | 0 | { | 114 | 0 | delete m_pInstance; | 115 | 0 | m_pInstance = nullptr; | 116 | 0 | } | 117 | | // <- GLOBAL SAFE | 118 | 1.04M | } |
|
119 | | |
120 | | SingletonRef& operator=(SingletonRef const&) = default; |
121 | | |
122 | | /** @short Allows rSingle->someBodyOp(). |
123 | | */ |
124 | | SingletonClass* operator->() const |
125 | 3.04M | { |
126 | | // GLOBAL SAFE -> |
127 | 3.04M | return m_pInstance; |
128 | | // <- GLOBAL SAFE |
129 | 3.04M | } comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::operator->() const Line | Count | Source | 125 | 3.04M | { | 126 | | // GLOBAL SAFE -> | 127 | 3.04M | return m_pInstance; | 128 | | // <- GLOBAL SAFE | 129 | 3.04M | } |
Unexecuted instantiation: comphelper::SingletonRef<connectivity::DriversConfigImpl>::operator->() const |
130 | | |
131 | | /** @short Allows (*rSingle).someBodyOp(). |
132 | | */ |
133 | | SingletonClass& operator*() const |
134 | | { |
135 | | // GLOBAL SAFE -> |
136 | | return *m_pInstance; |
137 | | // <- GLOBAL SAFE |
138 | | } |
139 | | |
140 | | // helper |
141 | | |
142 | | private: |
143 | | SingletonRef(SingletonRef&) = delete; |
144 | | |
145 | | static std::mutex& ownStaticLock() |
146 | 2.10M | { |
147 | 2.10M | static std::mutex aInstance; |
148 | 2.10M | return aInstance; |
149 | 2.10M | } comphelper::SingletonRef<connectivity::OSQLParseNodesContainer>::ownStaticLock() Line | Count | Source | 146 | 20.6k | { | 147 | 20.6k | static std::mutex aInstance; | 148 | 20.6k | return aInstance; | 149 | 20.6k | } |
comphelper::SingletonRef<connectivity::DriversConfigImpl>::ownStaticLock() Line | Count | Source | 146 | 2.08M | { | 147 | 2.08M | static std::mutex aInstance; | 148 | 2.08M | return aInstance; | 149 | 2.08M | } |
|
150 | | }; |
151 | | |
152 | | template <class SingletonClass> SingletonClass* SingletonRef<SingletonClass>::m_pInstance = nullptr; |
153 | | |
154 | | template <class SingletonClass> sal_Int32 SingletonRef<SingletonClass>::m_nRef = 0; |
155 | | |
156 | | } // namespace comphelper |
157 | | |
158 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |