build fix
[LibreOffice.git] / include / rtl / instance.hxx
blob740c581df1ca07f7129c6ed55ce12ef709360ea0
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 <cstddef>
27 #include <osl/doublecheckedlocking.h>
28 #if ! HAVE_THREADSAFE_STATICS
29 #include <osl/getglobalmutex.hxx>
30 #endif
32 namespace {
34 /** A non-broken version of the double-checked locking pattern.
36 See
37 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
38 for a description of double-checked locking, why it is broken, and how it
39 can be fixed. Always use this template instead of spelling out the
40 double-checked locking pattern explicitly, and only in those rare cases
41 where that is not possible and you have to spell it out explicitly, at
42 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
43 places. That way, all platform-dependent code to make double-checked
44 locking work can be kept in one place.
46 Usage scenarios:
48 1 Static instance (most common case)
50 Pattern:
52 T * getInstance()
54 static T * pInstance = 0;
55 if (!pInstance)
57 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
58 if (!pInstance)
60 static T aInstance;
61 pInstance = &aInstance;
64 return pInstance;
67 Code:
69 #include <rtl/instance.hxx>
70 #include <osl/getglobalmutex.hxx>
72 namespace {
73 struct Init
75 T * operator()()
77 static T aInstance;
78 return &aInstance;
83 T * getInstance()
85 return rtl_Instance< T, Init, ::osl::MutexGuard,
86 ::osl::GetGlobalMutex >::create(
87 Init(), ::osl::GetGlobalMutex());
90 2 Dynamic instance
92 Pattern:
94 T * getInstance()
96 static T * pInstance = 0;
97 if (!pInstance)
99 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
100 if (!pInstance)
101 pInstance = new T;
103 return pInstance;
106 Code:
108 #include <rtl/instance.hxx>
109 #include <osl/getglobalmutex.hxx>
111 namespace {
112 struct Init
114 T * operator()()
116 return new T;
121 T * getInstance()
123 return rtl_Instance< T, Init, ::osl::MutexGuard,
124 ::osl::GetGlobalMutex >::create(
125 Init(), ::osl::GetGlobalMutex());
128 3 Other guard/mutex
130 Pattern:
132 T * getInstance()
134 static T * pInstance = 0;
135 if (!pInstance)
137 SomeGuard aGuard(pSomeMutex);
138 if (!pInstance)
140 static T aInstance;
141 pInstance = &aInstance;
144 return pInstance;
147 Code:
149 #include <rtl/instance.hxx>
151 namespace {
152 struct InitInstance
154 T * operator()()
156 static T aInstance;
157 return &aInstance;
161 struct InitGuard
163 SomeMutex * operator()()
165 return pSomeMutex;
170 T * getInstance()
172 return rtl_Instance< T, InitInstance,
173 SomeGuard, InitGuard >::create(
174 InitInstance(), InitMutex());
177 4 Calculate extra data
179 Pattern:
181 T * getInstance()
183 static T * pInstance = 0;
184 if (!pInstance)
186 Data aData(...);
187 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
188 if (!pInstance)
190 static T aInstance(aData);
191 pInstance = &aInstance;
194 return pInstance;
197 Code:
199 #include <rtl/instance.hxx>
200 #include <osl/getglobalmutex.hxx>
202 namespace {
203 struct InitInstance
205 T * operator()()
207 static T aInstance;
208 return &aInstance;
212 struct InitData
214 Data const & operator()()
216 return ...;
221 T * getInstance()
223 return rtl_Instance< T, InitInstance,
224 ::osl::Mutex, ::osl::GetGlobalMutex,
225 Data, InitData >::create(
226 InitInstance(), ::osl::GetGlobalMutex(), InitData());
229 Some comments:
231 For any instantiation of rtl_Instance, at most one call to a create method
232 may occur in the program code: Each occurrence of a create method within
233 the program code is supposed to return a fresh object instance on the
234 first call, and that same object instance on subsequent calls; but
235 independent occurrences of create methods are supposed to return
236 independent object instances. Since there is a one-to-one correspondence
237 between object instances and instantiations of rtl_Instance, the
238 requirement should be clear. One measure to enforce the requirement is
239 that rtl_Instance lives in an unnamed namespace, so that instantiations of
240 rtl_Instance in different translation units will definitely be different
241 instantiations. A drawback of that measure is that the name of the class
242 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
243 prefix like "::rtl::".
245 A known problem with this template is when two occurrences of calls to
246 create methods with identical template arguments appear in one translation
247 unit. Those two places will share a single object instance. This can be
248 avoided by using different Init structs (see the above code samples) in
249 the two places.
251 There is no need to make m_pInstance volatile, in order to avoid usage of
252 stale copies of m_pInstance: At the first check, a thread will see that
253 m_pInstance contains either 0 or a valid pointer. If it contains a valid
254 pointer, it cannot be stale, and that pointer is used. If it contains 0,
255 acquiring the mutex will ensure that the second check sees a non-stale
256 value in all cases.
258 On some compilers, the create methods would not be inlined if they
259 contained any static variables, so m_pInstance is made a class member
260 instead (and the create methods are inlined). But on MSC, the definition
261 of the class member m_pInstance would cause compilation to fail with an
262 internal compiler error. Since MSC is able to inline methods containing
263 static variables, m_pInstance is moved into the methods there. Note that
264 this only works well because for any instantiation of rtl_Instance at most
265 one call to a create method should be present, anyway.
267 template< typename Inst, typename InstCtor,
268 typename Guard, typename GuardCtor,
269 typename Data = int, typename DataCtor = int >
270 class rtl_Instance
272 public:
273 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
275 #if defined _MSC_VER
276 static Inst * m_pInstance = 0;
277 #endif // _MSC_VER
278 Inst * p = m_pInstance;
279 if (!p)
281 Guard aGuard(aGuardCtor());
282 p = m_pInstance;
283 if (!p)
285 p = aInstCtor();
286 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
287 m_pInstance = p;
290 else
292 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
294 return p;
297 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
298 DataCtor aDataCtor)
300 #if defined _MSC_VER
301 static Inst * m_pInstance = 0;
302 #endif // _MSC_VER
303 Inst * p = m_pInstance;
304 if (!p)
306 Data aData(aDataCtor());
307 Guard aGuard(aGuardCtor());
308 p = m_pInstance;
309 if (!p)
311 p = aInstCtor(aData);
312 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
313 m_pInstance = p;
316 else
318 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
320 return p;
323 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
324 const Data &rData)
326 #if defined _MSC_VER
327 static Inst * m_pInstance = 0;
328 #endif // _MSC_VER
329 Inst * p = m_pInstance;
330 if (!p)
332 Guard aGuard(aGuardCtor());
333 p = m_pInstance;
334 if (!p)
336 p = aInstCtor(rData);
337 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
338 m_pInstance = p;
341 else
343 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
345 return p;
348 private:
349 #if !defined _MSC_VER
350 static Inst * m_pInstance;
351 #endif // _MSC_VER
354 #if !defined _MSC_VER
355 template< typename Inst, typename InstCtor,
356 typename Guard, typename GuardCtor,
357 typename Data, typename DataCtor >
358 Inst *
359 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
360 = NULL;
361 #endif // _MSC_VER
365 namespace rtl {
367 /** Helper base class for a late-initialized (default-constructed)
368 static variable, implementing the double-checked locking pattern correctly.
370 @derive
371 Derive from this class (common practice), e.g.
372 <pre>
373 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
375 MyType & rStatic = MyStatic::get();
377 </pre>
379 @tparam T
380 variable's type
381 @tparam Unique
382 Implementation trick to make the inner static holder unique,
383 using the outer class
384 (the one that derives from this base class)
386 #if HAVE_THREADSAFE_STATICS
387 template<typename T, typename Unique>
388 class Static {
389 public:
390 /** Gets the static. Mutual exclusion is implied by a functional
391 -fthreadsafe-statics
393 @return
394 static variable
396 static T & get() {
397 static T instance;
398 return instance;
401 #else
402 template<typename T, typename Unique>
403 class Static {
404 public:
405 /** Gets the static. Mutual exclusion is performed using the
406 osl global mutex.
408 @return
409 static variable
411 static T & get() {
412 return *rtl_Instance<
413 T, StaticInstance,
414 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
415 StaticInstance(), ::osl::GetGlobalMutex() );
417 private:
418 struct StaticInstance {
419 T * operator () () {
420 static T instance;
421 return &instance;
425 #endif
427 /** Helper base class for a late-initialized (default-constructed)
428 static variable, implementing the double-checked locking pattern correctly.
430 @derive
431 Derive from this class (common practice), e.g.
432 <pre>
433 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
435 MyType & rStatic = MyStatic::get();
437 </pre>
439 @tparam T
440 variable's type
441 @tparam Unique
442 Implementation trick to make the inner static holder unique,
443 using the outer class
444 (the one that derives from this base class)
446 #if HAVE_THREADSAFE_STATICS
447 template<typename T, typename Data, typename Unique>
448 class StaticWithArg {
449 public:
450 /** Gets the static. Mutual exclusion is implied by a functional
451 -fthreadsafe-statics
453 @return
454 static variable
456 static T & get(const Data& rData) {
457 static T instance(rData);
458 return instance;
461 /** Gets the static. Mutual exclusion is implied by a functional
462 -fthreadsafe-statics
464 @return
465 static variable
467 static T & get(Data& rData) {
468 static T instance(rData);
469 return instance;
472 #else
473 template<typename T, typename Data, typename Unique>
474 class StaticWithArg {
475 public:
476 /** Gets the static. Mutual exclusion is performed using the
477 osl global mutex.
479 @return
480 static variable
482 static T & get(const Data& rData) {
483 return *rtl_Instance<
484 T, StaticInstanceWithArg,
485 ::osl::MutexGuard, ::osl::GetGlobalMutex,
486 Data >::create( StaticInstanceWithArg(),
487 ::osl::GetGlobalMutex(),
488 rData );
491 /** Gets the static. Mutual exclusion is performed using the
492 osl global mutex.
494 @return
495 static variable
497 static T & get(Data& rData) {
498 return *rtl_Instance<
499 T, StaticInstanceWithArg,
500 ::osl::MutexGuard, ::osl::GetGlobalMutex,
501 Data >::create( StaticInstanceWithArg(),
502 ::osl::GetGlobalMutex(),
503 rData );
505 private:
506 struct StaticInstanceWithArg {
507 T * operator () (const Data& rData) {
508 static T instance(rData);
509 return &instance;
512 T * operator () (Data& rData) {
513 static T instance(rData);
514 return &instance;
518 #endif
520 /** Helper class for a late-initialized static aggregate, e.g. an array,
521 implementing the double-checked locking pattern correctly.
523 @tparam T
524 aggregate's element type
525 @tparam InitAggregate
526 initializer functor class
528 #if HAVE_THREADSAFE_STATICS
529 template<typename T, typename InitAggregate>
530 class StaticAggregate {
531 public:
532 /** Gets the static aggregate, late-initializing.
533 Mutual exclusion is implied by a functional
534 -fthreadsafe-statics
536 @return
537 aggregate
539 static T * get() {
540 static T *instance = InitAggregate()();
541 return instance;
544 #else
545 template<typename T, typename InitAggregate>
546 class StaticAggregate {
547 public:
548 /** Gets the static aggregate, late-initializing.
549 Mutual exclusion is performed using the osl global mutex.
551 @return
552 aggregate
554 static T * get() {
555 return rtl_Instance<
556 T, InitAggregate,
557 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
558 InitAggregate(), ::osl::GetGlobalMutex() );
561 #endif
562 /** Helper base class for a late-initialized static variable,
563 implementing the double-checked locking pattern correctly.
565 @derive
566 Derive from this class (common practice),
567 providing an initializer functor class, e.g.
568 <pre>
569 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
570 MyType operator () () {
572 return MyType( ... );
576 MyType & rStatic = MyStatic::get();
578 </pre>
580 @tparam T
581 variable's type
582 @tparam InitData
583 initializer functor class
584 @tparam Unique
585 Implementation trick to make the inner static holder unique,
586 using the outer class
587 (the one that derives from this base class).
588 Default is InitData (common practice).
589 @tparam Data
590 Initializer functor's return type.
591 Default is T (common practice).
593 #if HAVE_THREADSAFE_STATICS
594 template<typename T, typename InitData,
595 typename Unique = InitData, typename Data = T>
596 class StaticWithInit {
597 public:
598 /** Gets the static. Mutual exclusion is implied by a functional
599 -fthreadsafe-statics
601 @return
602 static variable
604 static T & get() {
605 static T instance = InitData()();
606 return instance;
609 #else
610 template<typename T, typename InitData,
611 typename Unique = InitData, typename Data = T>
612 class StaticWithInit {
613 public:
614 /** Gets the static. Mutual exclusion is performed using the
615 osl global mutex.
617 @return
618 static variable
620 static T & get() {
621 return *rtl_Instance<
622 T, StaticInstanceWithInit,
623 ::osl::MutexGuard, ::osl::GetGlobalMutex,
624 Data, InitData >::create( StaticInstanceWithInit(),
625 ::osl::GetGlobalMutex(),
626 InitData() );
628 private:
629 struct StaticInstanceWithInit {
630 T * operator () ( Data d ) {
631 static T instance(d);
632 return &instance;
636 #endif
637 } // namespace rtl
639 #endif // INCLUDED_RTL_INSTANCE_HXX
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */