Update ooo320-m1
[ooovba.git] / sal / inc / rtl / instance.hxx
blobdd628d63113f63edf173dd088c5de4ceb5fe4677
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: instance.hxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #if !defined INCLUDED_RTL_INSTANCE_HXX
32 #define INCLUDED_RTL_INSTANCE_HXX
34 #include "osl/doublecheckedlocking.h"
35 #include "osl/getglobalmutex.hxx"
37 namespace {
39 /** A non-broken version of the double-checked locking pattern.
41 See
42 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
43 for a description of double-checked locking, why it is broken, and how it
44 can be fixed. Always use this template instead of spelling out the
45 double-checked locking pattern explicitly, and only in those rare cases
46 where that is not possible and you have to spell it out explicitly, at
47 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
48 places. That way, all platform-dependent code to make double-checked
49 locking work can be kept in one place.
51 Usage scenarios:
53 1 Static instance (most common case)
55 Pattern:
57 T * getInstance()
59 static T * pInstance = 0;
60 if (!pInstance)
62 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
63 if (!pInstance)
65 static T aInstance;
66 pInstance = &aInstance;
69 return pInstance;
72 Code:
74 #include "rtl/instance.hxx"
75 #include "osl/getglobalmutex.hxx"
77 namespace {
78 struct Init
80 T * operator()()
82 static T aInstance;
83 return &aInstance;
88 T * getInstance()
90 return rtl_Instance< T, Init, ::osl::MutexGuard,
91 ::osl::GetGlobalMutex >::create(
92 Init(), ::osl::GetGlobalMutex());
95 2 Dynamic instance
97 Pattern:
99 T * getInstance()
101 static T * pInstance = 0;
102 if (!pInstance)
104 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
105 if (!pInstance)
106 pInstance = new T;
108 return pInstance;
111 Code:
113 #include "rtl/instance.hxx"
114 #include "osl/getglobalmutex.hxx"
116 namespace {
117 struct Init
119 T * operator()()
121 return new T;
126 T * getInstance()
128 return rtl_Instance< T, Init, ::osl::MutexGuard,
129 ::osl::GetGlobalMutex >::create(
130 Init(), ::osl::GetGlobalMutex());
133 3 Other guard/mutex
135 Pattern:
137 T * getInstance()
139 static T * pInstance = 0;
140 if (!pInstance)
142 SomeGuard aGuard(pSomeMutex);
143 if (!pInstance)
145 static T aInstance;
146 pInstance = &aInstance;
149 return pInstance;
152 Code:
154 #include "rtl/instance.hxx"
156 namespace {
157 struct InitInstance
159 T * operator()()
161 static T aInstance;
162 return &aInstance;
166 struct InitGuard
168 SomeMutex * operator()()
170 return pSomeMutex;
175 T * getInstance()
177 return rtl_Instance< T, InitInstance,
178 SomeGuard, InitGuard >::create(
179 InitInstance(), InitMutex());
182 4 Calculate extra data
184 Pattern:
186 T * getInstance()
188 static T * pInstance = 0;
189 if (!pInstance)
191 Data aData(...);
192 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
193 if (!pInstance)
195 static T aInstance(aData);
196 pInstance = &aInstance;
199 return pInstance;
202 Code:
204 #include "rtl/instance.hxx"
205 #include "osl/getglobalmutex.hxx"
207 namespace {
208 struct InitInstance
210 T * operator()()
212 static T aInstance;
213 return &aInstance;
217 struct InitData
219 Data const & operator()()
221 return ...;
226 T * getInstance()
228 return rtl_Instance< T, InitInstance,
229 ::osl::Mutex, ::osl::GetGlobalMutex,
230 Data, InitData >::create(
231 InitInstance(), ::osl::GetGlobalMutex(), InitData());
234 Some comments:
236 For any instantiation of rtl_Instance, at most one call to a create method
237 may occur in the program code: Each occurance of a create method within
238 the program code is supposed to return a fresh object instance on the
239 first call, and that same object instance on subsequent calls; but
240 independent occurances of create methods are supposed to return
241 independent object instances. Since there is a one-to-one correspondence
242 between object instances and instantiations of rtl_Instance, the
243 requirement should be clear. One measure to enforce the requirement is
244 that rtl_Instance lives in an unnamed namespace, so that instantiations of
245 rtl_Instance in different translation units will definitely be different
246 instantiations. A drawback of that measure is that the name of the class
247 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
248 prefix like "::rtl::".
250 A known problem with this template is when two occurences of calls to
251 create methods with identical template arguments appear in one translation
252 unit. Those two places will share a single object instance. This can be
253 avoided by using different Init structs (see the above code samples) in
254 the two places.
256 There is no need to make m_pInstance volatile, in order to avoid usage of
257 stale copies of m_pInstance: At the first check, a thread will see that
258 m_pInstance contains either 0 or a valid pointer. If it contains a valid
259 pointer, it cannot be stale, and that pointer is used. If it contains 0,
260 acquiring the mutex will ensure that the second check sees a non-stale
261 value in all cases.
263 On some compilers, the create methods would not be inlined if they
264 contained any static variables, so m_pInstance is made a class member
265 instead (and the create methods are inlined). But on MSC, the definition
266 of the class member m_pInstance would cause compilation to fail with an
267 internal compiler error. Since MSC is able to inline methods containing
268 static variables, m_pInstance is moved into the methods there. Note that
269 this only works well because for any instantiation of rtl_Instance at most
270 one call to a create method should be present, anyway.
272 template< typename Inst, typename InstCtor,
273 typename Guard, typename GuardCtor,
274 typename Data = int, typename DataCtor = int >
275 class rtl_Instance
277 public:
278 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
280 #if defined _MSC_VER
281 static Inst * m_pInstance = 0;
282 #endif // _MSC_VER
283 Inst * p = m_pInstance;
284 if (!p)
286 Guard aGuard(aGuardCtor());
287 p = m_pInstance;
288 if (!p)
290 p = aInstCtor();
291 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
292 m_pInstance = p;
295 else
297 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
299 return p;
302 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
303 DataCtor aDataCtor)
305 #if defined _MSC_VER
306 static Inst * m_pInstance = 0;
307 #endif // _MSC_VER
308 Inst * p = m_pInstance;
309 if (!p)
311 Data aData(aDataCtor());
312 Guard aGuard(aGuardCtor());
313 p = m_pInstance;
314 if (!p)
316 p = aInstCtor(aData);
317 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
318 m_pInstance = p;
321 else
323 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
325 return p;
328 private:
329 #if !defined _MSC_VER
330 static Inst * m_pInstance;
331 #endif // _MSC_VER
334 #if !defined _MSC_VER
335 template< typename Inst, typename InstCtor,
336 typename Guard, typename GuardCtor,
337 typename Data, typename DataCtor >
338 Inst *
339 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
340 = 0;
341 #endif // _MSC_VER
345 namespace rtl {
347 /** Helper base class for a late-initialized (default-constructed)
348 static variable, implementing the double-checked locking pattern correctly.
350 @derive
351 Derive from this class (common practice), e.g.
352 <pre>
353 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
355 MyType & rStatic = MyStatic::get();
357 </pre>
359 @tplparam T
360 variable's type
361 @tplparam Unique
362 Implementation trick to make the inner static holder unique,
363 using the outer class
364 (the one that derives from this base class)
366 template<typename T, typename Unique>
367 class Static {
368 public:
369 /** Gets the static. Mutual exclusion is performed using the
370 osl global mutex.
372 @return
373 static variable
375 static T & get() {
376 return *rtl_Instance<
377 T, StaticInstance,
378 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
379 StaticInstance(), ::osl::GetGlobalMutex() );
381 private:
382 struct StaticInstance {
383 T * operator () () {
384 static T instance;
385 return &instance;
390 /** Helper class for a late-initialized static aggregate, e.g. an array,
391 implementing the double-checked locking pattern correctly.
393 @tplparam T
394 aggregate's element type
395 @tplparam InitAggregate
396 initializer functor class
398 template<typename T, typename InitAggregate>
399 class StaticAggregate {
400 public:
401 /** Gets the static aggregate, late-initializing.
402 Mutual exclusion is performed using the osl global mutex.
404 @return
405 aggregate
407 static T * get() {
408 return rtl_Instance<
409 T, InitAggregate,
410 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
411 InitAggregate(), ::osl::GetGlobalMutex() );
415 /** Helper base class for a late-initialized static variable,
416 implementing the double-checked locking pattern correctly.
418 @derive
419 Derive from this class (common practice),
420 providing an initializer functor class, e.g.
421 <pre>
422 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
423 MyType operator () () {
425 return MyType( ... );
429 MyType & rStatic = MyStatic::get();
431 </pre>
433 @tplparam T
434 variable's type
435 @tplparam InitData
436 initializer functor class
437 @tplparam Unique
438 Implementation trick to make the inner static holder unique,
439 using the outer class
440 (the one that derives from this base class).
441 Default is InitData (common practice).
442 @tplparam Data
443 Initializer functor's return type.
444 Default is T (common practice).
446 template<typename T, typename InitData,
447 typename Unique = InitData, typename Data = T>
448 class StaticWithInit {
449 public:
450 /** Gets the static. Mutual exclusion is performed using the
451 osl global mutex.
453 @return
454 static variable
456 static T & get() {
457 return *rtl_Instance<
458 T, StaticInstanceWithInit,
459 ::osl::MutexGuard, ::osl::GetGlobalMutex,
460 Data, InitData >::create( StaticInstanceWithInit(),
461 ::osl::GetGlobalMutex(),
462 InitData() );
464 private:
465 struct StaticInstanceWithInit {
466 T * operator () ( Data d ) {
467 static T instance(d);
468 return &instance;
473 } // namespace rtl
475 #endif // INCLUDED_RTL_INSTANCE_HXX