bump product version to 6.3.0.0.beta1
[LibreOffice.git] / include / rtl / instance.hxx
blob0f673e636f813c43c4b342220e53b785c24cfdad
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 #include "osl/getglobalmutex.hxx"
30 namespace {
32 /** A non-broken version of the double-checked locking pattern.
34 See
35 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
36 for a description of double-checked locking, why it is broken, and how it
37 can be fixed. Always use this template instead of spelling out the
38 double-checked locking pattern explicitly, and only in those rare cases
39 where that is not possible and you have to spell it out explicitly, at
40 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
41 places. That way, all platform-dependent code to make double-checked
42 locking work can be kept in one place.
44 Usage scenarios:
46 1 Static instance (most common case)
48 Pattern:
50 T * getInstance()
52 static T * pInstance = 0;
53 if (!pInstance)
55 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
56 if (!pInstance)
58 static T aInstance;
59 pInstance = &aInstance;
62 return pInstance;
65 Code:
67 #include <rtl/instance.hxx>
68 #include <osl/getglobalmutex.hxx>
70 namespace {
71 struct Init
73 T * operator()()
75 static T aInstance;
76 return &aInstance;
81 T * getInstance()
83 return rtl_Instance< T, Init, ::osl::MutexGuard,
84 ::osl::GetGlobalMutex >::create(
85 Init(), ::osl::GetGlobalMutex());
88 2 Dynamic instance
90 Pattern:
92 T * getInstance()
94 static T * pInstance = 0;
95 if (!pInstance)
97 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
98 if (!pInstance)
99 pInstance = new T;
101 return pInstance;
104 Code:
106 #include <rtl/instance.hxx>
107 #include <osl/getglobalmutex.hxx>
109 namespace {
110 struct Init
112 T * operator()()
114 return new T;
119 T * getInstance()
121 return rtl_Instance< T, Init, ::osl::MutexGuard,
122 ::osl::GetGlobalMutex >::create(
123 Init(), ::osl::GetGlobalMutex());
126 3 Other guard/mutex
128 Pattern:
130 T * getInstance()
132 static T * pInstance = 0;
133 if (!pInstance)
135 SomeGuard aGuard(pSomeMutex);
136 if (!pInstance)
138 static T aInstance;
139 pInstance = &aInstance;
142 return pInstance;
145 Code:
147 #include <rtl/instance.hxx>
149 namespace {
150 struct InitInstance
152 T * operator()()
154 static T aInstance;
155 return &aInstance;
159 struct InitGuard
161 SomeMutex * operator()()
163 return pSomeMutex;
168 T * getInstance()
170 return rtl_Instance< T, InitInstance,
171 SomeGuard, InitGuard >::create(
172 InitInstance(), InitMutex());
175 4 Calculate extra data
177 Pattern:
179 T * getInstance()
181 static T * pInstance = 0;
182 if (!pInstance)
184 Data aData(...);
185 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
186 if (!pInstance)
188 static T aInstance(aData);
189 pInstance = &aInstance;
192 return pInstance;
195 Code:
197 #include <rtl/instance.hxx>
198 #include <osl/getglobalmutex.hxx>
200 namespace {
201 struct InitInstance
203 T * operator()()
205 static T aInstance;
206 return &aInstance;
210 struct InitData
212 Data const & operator()()
214 return ...;
219 T * getInstance()
221 return rtl_Instance< T, InitInstance,
222 ::osl::MutexGuard, ::osl::GetGlobalMutex,
223 Data, InitData >::create(
224 InitInstance(), ::osl::GetGlobalMutex(), InitData());
227 Some comments:
229 For any instantiation of rtl_Instance, at most one call to a create method
230 may occur in the program code: Each occurrence of a create method within
231 the program code is supposed to return a fresh object instance on the
232 first call, and that same object instance on subsequent calls; but
233 independent occurrences of create methods are supposed to return
234 independent object instances. Since there is a one-to-one correspondence
235 between object instances and instantiations of rtl_Instance, the
236 requirement should be clear. One measure to enforce the requirement is
237 that rtl_Instance lives in an unnamed namespace, so that instantiations of
238 rtl_Instance in different translation units will definitely be different
239 instantiations. A drawback of that measure is that the name of the class
240 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
241 prefix like "::rtl::".
243 A known problem with this template is when two occurrences of calls to
244 create methods with identical template arguments appear in one translation
245 unit. Those two places will share a single object instance. This can be
246 avoided by using different Init structs (see the above code samples) in
247 the two places.
249 There is no need to make m_pInstance volatile, in order to avoid usage of
250 stale copies of m_pInstance: At the first check, a thread will see that
251 m_pInstance contains either 0 or a valid pointer. If it contains a valid
252 pointer, it cannot be stale, and that pointer is used. If it contains 0,
253 acquiring the mutex will ensure that the second check sees a non-stale
254 value in all cases.
256 On some compilers, the create methods would not be inlined if they
257 contained any static variables, so m_pInstance is made a class member
258 instead (and the create methods are inlined). But on MSC, the definition
259 of the class member m_pInstance would cause compilation to fail with an
260 internal compiler error. Since MSC is able to inline methods containing
261 static variables, m_pInstance is moved into the methods there. Note that
262 this only works well because for any instantiation of rtl_Instance at most
263 one call to a create method should be present, anyway.
265 template< typename Inst, typename InstCtor,
266 typename Guard, typename GuardCtor,
267 typename Data = int, typename DataCtor = int >
268 class rtl_Instance
270 public:
271 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
273 #if defined _MSC_VER
274 static Inst * m_pInstance = 0;
275 #endif // _MSC_VER
276 Inst * p = m_pInstance;
277 if (!p)
279 Guard aGuard(aGuardCtor());
280 p = m_pInstance;
281 if (!p)
283 p = aInstCtor();
284 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
285 m_pInstance = p;
288 else
290 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
292 return p;
295 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
296 DataCtor aDataCtor)
298 #if defined _MSC_VER
299 static Inst * m_pInstance = 0;
300 #endif // _MSC_VER
301 Inst * p = m_pInstance;
302 if (!p)
304 Data aData(aDataCtor());
305 Guard aGuard(aGuardCtor());
306 p = m_pInstance;
307 if (!p)
309 p = aInstCtor(aData);
310 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
311 m_pInstance = p;
314 else
316 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
318 return p;
321 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
322 const Data &rData)
324 #if defined _MSC_VER
325 static Inst * m_pInstance = 0;
326 #endif // _MSC_VER
327 Inst * p = m_pInstance;
328 if (!p)
330 Guard aGuard(aGuardCtor());
331 p = m_pInstance;
332 if (!p)
334 p = aInstCtor(rData);
335 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
336 m_pInstance = p;
339 else
341 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
343 return p;
346 private:
347 #if !defined _MSC_VER
348 static Inst * m_pInstance;
349 #endif // _MSC_VER
352 #if !defined _MSC_VER
353 template< typename Inst, typename InstCtor,
354 typename Guard, typename GuardCtor,
355 typename Data, typename DataCtor >
356 Inst *
357 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
358 = NULL;
359 #endif // _MSC_VER
363 namespace rtl {
365 /** Helper base class for a late-initialized (default-constructed)
366 static variable, implementing the double-checked locking pattern correctly.
368 @derive
369 Derive from this class (common practice), e.g.
370 <pre>
371 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
373 MyType & rStatic = MyStatic::get();
375 </pre>
377 @tparam T
378 variable's type
379 @tparam Unique
380 Implementation trick to make the inner static holder unique,
381 using the outer class
382 (the one that derives from this base class)
384 #if defined LIBO_INTERNAL_ONLY
385 template<typename T, typename Unique>
386 class Static {
387 public:
388 /** Gets the static. Mutual exclusion is implied by a functional
389 -fthreadsafe-statics
391 @return
392 static variable
394 static T & get() {
395 static T instance;
396 return instance;
399 #else
400 template<typename T, typename Unique>
401 class Static {
402 public:
403 /** Gets the static. Mutual exclusion is performed using the
404 osl global mutex.
406 @return
407 static variable
409 static T & get() {
410 return *rtl_Instance<
411 T, StaticInstance,
412 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
413 StaticInstance(), ::osl::GetGlobalMutex() );
415 private:
416 struct StaticInstance {
417 T * operator () () {
418 static T instance;
419 return &instance;
423 #endif
425 /** Helper base class for a late-initialized (default-constructed)
426 static variable, implementing the double-checked locking pattern correctly.
428 @derive
429 Derive from this class (common practice), e.g.
430 <pre>
431 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
433 MyType & rStatic = MyStatic::get();
435 </pre>
437 @tparam T
438 variable's type
439 @tparam Unique
440 Implementation trick to make the inner static holder unique,
441 using the outer class
442 (the one that derives from this base class)
444 #if defined LIBO_INTERNAL_ONLY
445 template<typename T, typename Data, typename Unique>
446 class StaticWithArg {
447 public:
448 /** Gets the static. Mutual exclusion is implied by a functional
449 -fthreadsafe-statics
451 @return
452 static variable
454 static T & get(const Data& rData) {
455 static T instance(rData);
456 return instance;
459 /** Gets the static. Mutual exclusion is implied by a functional
460 -fthreadsafe-statics
462 @return
463 static variable
465 static T & get(Data& rData) {
466 static T instance(rData);
467 return instance;
470 #else
471 template<typename T, typename Data, typename Unique>
472 class StaticWithArg {
473 public:
474 /** Gets the static. Mutual exclusion is performed using the
475 osl global mutex.
477 @return
478 static variable
480 static T & get(const Data& rData) {
481 return *rtl_Instance<
482 T, StaticInstanceWithArg,
483 ::osl::MutexGuard, ::osl::GetGlobalMutex,
484 Data >::create( StaticInstanceWithArg(),
485 ::osl::GetGlobalMutex(),
486 rData );
489 /** Gets the static. Mutual exclusion is performed using the
490 osl global mutex.
492 @return
493 static variable
495 static T & get(Data& rData) {
496 return *rtl_Instance<
497 T, StaticInstanceWithArg,
498 ::osl::MutexGuard, ::osl::GetGlobalMutex,
499 Data >::create( StaticInstanceWithArg(),
500 ::osl::GetGlobalMutex(),
501 rData );
503 private:
504 struct StaticInstanceWithArg {
505 T * operator () (const Data& rData) {
506 static T instance(rData);
507 return &instance;
510 T * operator () (Data& rData) {
511 static T instance(rData);
512 return &instance;
516 #endif
518 /** Helper class for a late-initialized static aggregate, e.g. an array,
519 implementing the double-checked locking pattern correctly.
521 @tparam T
522 aggregate's element type
523 @tparam InitAggregate
524 initializer functor class
526 #if defined LIBO_INTERNAL_ONLY
527 template<typename T, typename InitAggregate>
528 class StaticAggregate {
529 public:
530 /** Gets the static aggregate, late-initializing.
531 Mutual exclusion is implied by a functional
532 -fthreadsafe-statics
534 @return
535 aggregate
537 static T * get() {
538 static T *instance = InitAggregate()();
539 return instance;
542 #else
543 template<typename T, typename InitAggregate>
544 class StaticAggregate {
545 public:
546 /** Gets the static aggregate, late-initializing.
547 Mutual exclusion is performed using the osl global mutex.
549 @return
550 aggregate
552 static T * get() {
553 return rtl_Instance<
554 T, InitAggregate,
555 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
556 InitAggregate(), ::osl::GetGlobalMutex() );
559 #endif
560 /** Helper base class for a late-initialized static variable,
561 implementing the double-checked locking pattern correctly.
563 @derive
564 Derive from this class (common practice),
565 providing an initializer functor class, e.g.
566 <pre>
567 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
568 MyType operator () () {
570 return MyType( ... );
574 MyType & rStatic = MyStatic::get();
576 </pre>
578 @tparam T
579 variable's type
580 @tparam InitData
581 initializer functor class
582 @tparam Unique
583 Implementation trick to make the inner static holder unique,
584 using the outer class
585 (the one that derives from this base class).
586 Default is InitData (common practice).
587 @tparam Data
588 Initializer functor's return type.
589 Default is T (common practice).
591 #if defined LIBO_INTERNAL_ONLY
592 template<typename T, typename InitData,
593 typename Unique = InitData, typename Data = T>
594 class StaticWithInit {
595 public:
596 /** Gets the static. Mutual exclusion is implied by a functional
597 -fthreadsafe-statics
599 @return
600 static variable
602 static T & get() {
603 static T instance = InitData()();
604 return instance;
607 #else
608 template<typename T, typename InitData,
609 typename Unique = InitData, typename Data = T>
610 class StaticWithInit {
611 public:
612 /** Gets the static. Mutual exclusion is performed using the
613 osl global mutex.
615 @return
616 static variable
618 static T & get() {
619 return *rtl_Instance<
620 T, StaticInstanceWithInit,
621 ::osl::MutexGuard, ::osl::GetGlobalMutex,
622 Data, InitData >::create( StaticInstanceWithInit(),
623 ::osl::GetGlobalMutex(),
624 InitData() );
626 private:
627 struct StaticInstanceWithInit {
628 T * operator () ( Data d ) {
629 static T instance(d);
630 return &instance;
634 #endif
635 } // namespace rtl
637 #endif // INCLUDED_RTL_INSTANCE_HXX
639 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */