bump product version to 4.1.6.2
[LibreOffice.git] / include / rtl / instance.hxx
blob1efda808abec1e8644a27ed0c34379c6f7630b78
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #ifndef INCLUDED_RTL_INSTANCE_HXX
21 #define INCLUDED_RTL_INSTANCE_HXX
23 #include "sal/config.h"
25 #include "osl/doublecheckedlocking.h"
26 #include "osl/getglobalmutex.hxx"
28 namespace {
30 /** A non-broken version of the double-checked locking pattern.
32 See
33 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
34 for a description of double-checked locking, why it is broken, and how it
35 can be fixed. Always use this template instead of spelling out the
36 double-checked locking pattern explicitly, and only in those rare cases
37 where that is not possible and you have to spell it out explicitly, at
38 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
39 places. That way, all platform-dependent code to make double-checked
40 locking work can be kept in one place.
42 Usage scenarios:
44 1 Static instance (most common case)
46 Pattern:
48 T * getInstance()
50 static T * pInstance = 0;
51 if (!pInstance)
53 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
54 if (!pInstance)
56 static T aInstance;
57 pInstance = &aInstance;
60 return pInstance;
63 Code:
65 #include "rtl/instance.hxx"
66 #include "osl/getglobalmutex.hxx"
68 namespace {
69 struct Init
71 T * operator()()
73 static T aInstance;
74 return &aInstance;
79 T * getInstance()
81 return rtl_Instance< T, Init, ::osl::MutexGuard,
82 ::osl::GetGlobalMutex >::create(
83 Init(), ::osl::GetGlobalMutex());
86 2 Dynamic instance
88 Pattern:
90 T * getInstance()
92 static T * pInstance = 0;
93 if (!pInstance)
95 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
96 if (!pInstance)
97 pInstance = new T;
99 return pInstance;
102 Code:
104 #include "rtl/instance.hxx"
105 #include "osl/getglobalmutex.hxx"
107 namespace {
108 struct Init
110 T * operator()()
112 return new T;
117 T * getInstance()
119 return rtl_Instance< T, Init, ::osl::MutexGuard,
120 ::osl::GetGlobalMutex >::create(
121 Init(), ::osl::GetGlobalMutex());
124 3 Other guard/mutex
126 Pattern:
128 T * getInstance()
130 static T * pInstance = 0;
131 if (!pInstance)
133 SomeGuard aGuard(pSomeMutex);
134 if (!pInstance)
136 static T aInstance;
137 pInstance = &aInstance;
140 return pInstance;
143 Code:
145 #include "rtl/instance.hxx"
147 namespace {
148 struct InitInstance
150 T * operator()()
152 static T aInstance;
153 return &aInstance;
157 struct InitGuard
159 SomeMutex * operator()()
161 return pSomeMutex;
166 T * getInstance()
168 return rtl_Instance< T, InitInstance,
169 SomeGuard, InitGuard >::create(
170 InitInstance(), InitMutex());
173 4 Calculate extra data
175 Pattern:
177 T * getInstance()
179 static T * pInstance = 0;
180 if (!pInstance)
182 Data aData(...);
183 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
184 if (!pInstance)
186 static T aInstance(aData);
187 pInstance = &aInstance;
190 return pInstance;
193 Code:
195 #include "rtl/instance.hxx"
196 #include "osl/getglobalmutex.hxx"
198 namespace {
199 struct InitInstance
201 T * operator()()
203 static T aInstance;
204 return &aInstance;
208 struct InitData
210 Data const & operator()()
212 return ...;
217 T * getInstance()
219 return rtl_Instance< T, InitInstance,
220 ::osl::Mutex, ::osl::GetGlobalMutex,
221 Data, InitData >::create(
222 InitInstance(), ::osl::GetGlobalMutex(), InitData());
225 Some comments:
227 For any instantiation of rtl_Instance, at most one call to a create method
228 may occur in the program code: Each occurrence of a create method within
229 the program code is supposed to return a fresh object instance on the
230 first call, and that same object instance on subsequent calls; but
231 independent occurrences of create methods are supposed to return
232 independent object instances. Since there is a one-to-one correspondence
233 between object instances and instantiations of rtl_Instance, the
234 requirement should be clear. One measure to enforce the requirement is
235 that rtl_Instance lives in an unnamed namespace, so that instantiations of
236 rtl_Instance in different translation units will definitely be different
237 instantiations. A drawback of that measure is that the name of the class
238 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
239 prefix like "::rtl::".
241 A known problem with this template is when two occurrences of calls to
242 create methods with identical template arguments appear in one translation
243 unit. Those two places will share a single object instance. This can be
244 avoided by using different Init structs (see the above code samples) in
245 the two places.
247 There is no need to make m_pInstance volatile, in order to avoid usage of
248 stale copies of m_pInstance: At the first check, a thread will see that
249 m_pInstance contains either 0 or a valid pointer. If it contains a valid
250 pointer, it cannot be stale, and that pointer is used. If it contains 0,
251 acquiring the mutex will ensure that the second check sees a non-stale
252 value in all cases.
254 On some compilers, the create methods would not be inlined if they
255 contained any static variables, so m_pInstance is made a class member
256 instead (and the create methods are inlined). But on MSC, the definition
257 of the class member m_pInstance would cause compilation to fail with an
258 internal compiler error. Since MSC is able to inline methods containing
259 static variables, m_pInstance is moved into the methods there. Note that
260 this only works well because for any instantiation of rtl_Instance at most
261 one call to a create method should be present, anyway.
263 template< typename Inst, typename InstCtor,
264 typename Guard, typename GuardCtor,
265 typename Data = int, typename DataCtor = int >
266 class rtl_Instance
268 public:
269 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
271 #if defined _MSC_VER
272 static Inst * m_pInstance = 0;
273 #endif // _MSC_VER
274 Inst * p = m_pInstance;
275 if (!p)
277 Guard aGuard(aGuardCtor());
278 p = m_pInstance;
279 if (!p)
281 p = aInstCtor();
282 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
283 m_pInstance = p;
286 else
288 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
290 return p;
293 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
294 DataCtor aDataCtor)
296 #if defined _MSC_VER
297 static Inst * m_pInstance = 0;
298 #endif // _MSC_VER
299 Inst * p = m_pInstance;
300 if (!p)
302 Data aData(aDataCtor());
303 Guard aGuard(aGuardCtor());
304 p = m_pInstance;
305 if (!p)
307 p = aInstCtor(aData);
308 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
309 m_pInstance = p;
312 else
314 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
316 return p;
319 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
320 const Data &rData)
322 #if defined _MSC_VER
323 static Inst * m_pInstance = 0;
324 #endif // _MSC_VER
325 Inst * p = m_pInstance;
326 if (!p)
328 Guard aGuard(aGuardCtor());
329 p = m_pInstance;
330 if (!p)
332 p = aInstCtor(rData);
333 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
334 m_pInstance = p;
337 else
339 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
341 return p;
344 private:
345 #if !defined _MSC_VER
346 static Inst * m_pInstance;
347 #endif // _MSC_VER
350 #if !defined _MSC_VER
351 template< typename Inst, typename InstCtor,
352 typename Guard, typename GuardCtor,
353 typename Data, typename DataCtor >
354 Inst *
355 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
356 = 0;
357 #endif // _MSC_VER
361 namespace rtl {
363 /** Helper base class for a late-initialized (default-constructed)
364 static variable, implementing the double-checked locking pattern correctly.
366 @derive
367 Derive from this class (common practice), e.g.
368 <pre>
369 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
371 MyType & rStatic = MyStatic::get();
373 </pre>
375 @tparam T
376 variable's type
377 @tparam Unique
378 Implementation trick to make the inner static holder unique,
379 using the outer class
380 (the one that derives from this base class)
382 #if HAVE_THREADSAFE_STATICS
383 template<typename T, typename Unique>
384 class Static {
385 public:
386 /** Gets the static. Mutual exclusion is implied by a functional
387 -fthreadsafe-statics
389 @return
390 static variable
392 static T & get() {
393 static T instance;
394 return instance;
397 #else
398 template<typename T, typename Unique>
399 class Static {
400 public:
401 /** Gets the static. Mutual exclusion is performed using the
402 osl global mutex.
404 @return
405 static variable
407 static T & get() {
408 return *rtl_Instance<
409 T, StaticInstance,
410 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
411 StaticInstance(), ::osl::GetGlobalMutex() );
413 private:
414 struct StaticInstance {
415 T * operator () () {
416 static T instance;
417 return &instance;
421 #endif
423 /** Helper base class for a late-initialized (default-constructed)
424 static variable, implementing the double-checked locking pattern correctly.
426 @derive
427 Derive from this class (common practice), e.g.
428 <pre>
429 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
431 MyType & rStatic = MyStatic::get();
433 </pre>
435 @tparam T
436 variable's type
437 @tparam 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)
442 #if HAVE_THREADSAFE_STATICS
443 template<typename T, typename Data, typename Unique>
444 class StaticWithArg {
445 public:
446 /** Gets the static. Mutual exclusion is implied by a functional
447 -fthreadsafe-statics
449 @return
450 static variable
452 static T & get(const Data& rData) {
453 static T instance(rData);
454 return instance;
457 /** Gets the static. Mutual exclusion is implied by a functional
458 -fthreadsafe-statics
460 @return
461 static variable
463 static T & get(Data& rData) {
464 static T instance(rData);
465 return instance;
468 #else
469 template<typename T, typename Data, typename Unique>
470 class StaticWithArg {
471 public:
472 /** Gets the static. Mutual exclusion is performed using the
473 osl global mutex.
475 @return
476 static variable
478 static T & get(const Data& rData) {
479 return *rtl_Instance<
480 T, StaticInstanceWithArg,
481 ::osl::MutexGuard, ::osl::GetGlobalMutex,
482 Data >::create( StaticInstanceWithArg(),
483 ::osl::GetGlobalMutex(),
484 rData );
487 /** Gets the static. Mutual exclusion is performed using the
488 osl global mutex.
490 @return
491 static variable
493 static T & get(Data& rData) {
494 return *rtl_Instance<
495 T, StaticInstanceWithArg,
496 ::osl::MutexGuard, ::osl::GetGlobalMutex,
497 Data >::create( StaticInstanceWithArg(),
498 ::osl::GetGlobalMutex(),
499 rData );
501 private:
502 struct StaticInstanceWithArg {
503 T * operator () (const Data& rData) {
504 static T instance(rData);
505 return &instance;
508 T * operator () (Data& rData) {
509 static T instance(rData);
510 return &instance;
514 #endif
516 /** Helper class for a late-initialized static aggregate, e.g. an array,
517 implementing the double-checked locking pattern correctly.
519 @tparam T
520 aggregate's element type
521 @tparam InitAggregate
522 initializer functor class
524 #if HAVE_THREADSAFE_STATICS
525 template<typename T, typename InitAggregate>
526 class StaticAggregate {
527 public:
528 /** Gets the static aggregate, late-initializing.
529 Mutual exclusion is implied by a functional
530 -fthreadsafe-statics
532 @return
533 aggregate
535 static T * get() {
536 static T *instance = InitAggregate()();
537 return instance;
540 #else
541 template<typename T, typename InitAggregate>
542 class StaticAggregate {
543 public:
544 /** Gets the static aggregate, late-initializing.
545 Mutual exclusion is performed using the osl global mutex.
547 @return
548 aggregate
550 static T * get() {
551 return rtl_Instance<
552 T, InitAggregate,
553 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
554 InitAggregate(), ::osl::GetGlobalMutex() );
557 #endif
558 /** Helper base class for a late-initialized static variable,
559 implementing the double-checked locking pattern correctly.
561 @derive
562 Derive from this class (common practice),
563 providing an initializer functor class, e.g.
564 <pre>
565 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
566 MyType operator () () {
568 return MyType( ... );
572 MyType & rStatic = MyStatic::get();
574 </pre>
576 @tparam T
577 variable's type
578 @tparam InitData
579 initializer functor class
580 @tparam Unique
581 Implementation trick to make the inner static holder unique,
582 using the outer class
583 (the one that derives from this base class).
584 Default is InitData (common practice).
585 @tparam Data
586 Initializer functor's return type.
587 Default is T (common practice).
589 #if HAVE_THREADSAFE_STATICS
590 template<typename T, typename InitData,
591 typename Unique = InitData, typename Data = T>
592 class StaticWithInit {
593 public:
594 /** Gets the static. Mutual exclusion is implied by a functional
595 -fthreadsafe-statics
597 @return
598 static variable
600 static T & get() {
601 static T instance = InitData()();
602 return instance;
605 #else
606 template<typename T, typename InitData,
607 typename Unique = InitData, typename Data = T>
608 class StaticWithInit {
609 public:
610 /** Gets the static. Mutual exclusion is performed using the
611 osl global mutex.
613 @return
614 static variable
616 static T & get() {
617 return *rtl_Instance<
618 T, StaticInstanceWithInit,
619 ::osl::MutexGuard, ::osl::GetGlobalMutex,
620 Data, InitData >::create( StaticInstanceWithInit(),
621 ::osl::GetGlobalMutex(),
622 InitData() );
624 private:
625 struct StaticInstanceWithInit {
626 T * operator () ( Data d ) {
627 static T instance(d);
628 return &instance;
632 #endif
633 } // namespace rtl
635 #endif // INCLUDED_RTL_INSTANCE_HXX
637 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */