tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / include / rtl / instance.hxx
blob0d7d8f3fca7aebb1c2e7302a57428d6cd270946f
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 .
21 * This file is part of LibreOffice published API.
24 #ifndef INCLUDED_RTL_INSTANCE_HXX
25 #define INCLUDED_RTL_INSTANCE_HXX
27 #include "sal/config.h"
29 #include <cstddef>
31 #include "osl/doublecheckedlocking.h"
32 #include "osl/getglobalmutex.hxx"
34 namespace {
36 /** A non-broken version of the double-checked locking pattern.
38 See
39 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
40 for a description of double-checked locking, why it is broken, and how it
41 can be fixed. Always use this template instead of spelling out the
42 double-checked locking pattern explicitly, and only in those rare cases
43 where that is not possible and you have to spell it out explicitly, at
44 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
45 places. That way, all platform-dependent code to make double-checked
46 locking work can be kept in one place.
48 Usage scenarios:
50 1 Static instance (most common case)
52 Pattern:
54 T * getInstance()
56 static T * pInstance = 0;
57 if (!pInstance)
59 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
60 if (!pInstance)
62 static T aInstance;
63 pInstance = &aInstance;
66 return pInstance;
69 Code:
71 #include <rtl/instance.hxx>
72 #include <osl/getglobalmutex.hxx>
74 namespace {
75 struct Init
77 T * operator()()
79 static T aInstance;
80 return &aInstance;
85 T * getInstance()
87 return rtl_Instance< T, Init, ::osl::MutexGuard,
88 ::osl::GetGlobalMutex >::create(
89 Init(), ::osl::GetGlobalMutex());
92 2 Dynamic instance
94 Pattern:
96 T * getInstance()
98 static T * pInstance = 0;
99 if (!pInstance)
101 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
102 if (!pInstance)
103 pInstance = new T;
105 return pInstance;
108 Code:
110 #include <rtl/instance.hxx>
111 #include <osl/getglobalmutex.hxx>
113 namespace {
114 struct Init
116 T * operator()()
118 return new T;
123 T * getInstance()
125 return rtl_Instance< T, Init, ::osl::MutexGuard,
126 ::osl::GetGlobalMutex >::create(
127 Init(), ::osl::GetGlobalMutex());
130 3 Other guard/mutex
132 Pattern:
134 T * getInstance()
136 static T * pInstance = 0;
137 if (!pInstance)
139 SomeGuard aGuard(pSomeMutex);
140 if (!pInstance)
142 static T aInstance;
143 pInstance = &aInstance;
146 return pInstance;
149 Code:
151 #include <rtl/instance.hxx>
153 namespace {
154 struct InitInstance
156 T * operator()()
158 static T aInstance;
159 return &aInstance;
163 struct InitGuard
165 SomeMutex * operator()()
167 return pSomeMutex;
172 T * getInstance()
174 return rtl_Instance< T, InitInstance,
175 SomeGuard, InitGuard >::create(
176 InitInstance(), InitMutex());
179 4 Calculate extra data
181 Pattern:
183 T * getInstance()
185 static T * pInstance = 0;
186 if (!pInstance)
188 Data aData(...);
189 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
190 if (!pInstance)
192 static T aInstance(aData);
193 pInstance = &aInstance;
196 return pInstance;
199 Code:
201 #include <rtl/instance.hxx>
202 #include <osl/getglobalmutex.hxx>
204 namespace {
205 struct InitInstance
207 T * operator()()
209 static T aInstance;
210 return &aInstance;
214 struct InitData
216 Data const & operator()()
218 return ...;
223 T * getInstance()
225 return rtl_Instance< T, InitInstance,
226 ::osl::MutexGuard, ::osl::GetGlobalMutex,
227 Data, InitData >::create(
228 InitInstance(), ::osl::GetGlobalMutex(), InitData());
231 Some comments:
233 For any instantiation of rtl_Instance, at most one call to a create method
234 may occur in the program code: Each occurrence of a create method within
235 the program code is supposed to return a fresh object instance on the
236 first call, and that same object instance on subsequent calls; but
237 independent occurrences of create methods are supposed to return
238 independent object instances. Since there is a one-to-one correspondence
239 between object instances and instantiations of rtl_Instance, the
240 requirement should be clear. One measure to enforce the requirement is
241 that rtl_Instance lives in an unnamed namespace, so that instantiations of
242 rtl_Instance in different translation units will definitely be different
243 instantiations. A drawback of that measure is that the name of the class
244 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
245 prefix like "::rtl::".
247 A known problem with this template is when two occurrences of calls to
248 create methods with identical template arguments appear in one translation
249 unit. Those two places will share a single object instance. This can be
250 avoided by using different Init structs (see the above code samples) in
251 the two places.
253 There is no need to make m_pInstance volatile, in order to avoid usage of
254 stale copies of m_pInstance: At the first check, a thread will see that
255 m_pInstance contains either 0 or a valid pointer. If it contains a valid
256 pointer, it cannot be stale, and that pointer is used. If it contains 0,
257 acquiring the mutex will ensure that the second check sees a non-stale
258 value in all cases.
260 On some compilers, the create methods would not be inlined if they
261 contained any static variables, so m_pInstance is made a class member
262 instead (and the create methods are inlined). But on MSC, the definition
263 of the class member m_pInstance would cause compilation to fail with an
264 internal compiler error. Since MSC is able to inline methods containing
265 static variables, m_pInstance is moved into the methods there. Note that
266 this only works well because for any instantiation of rtl_Instance at most
267 one call to a create method should be present, anyway.
269 template< typename Inst, typename InstCtor,
270 typename Guard, typename GuardCtor,
271 typename Data = int, typename DataCtor = int >
272 class rtl_Instance
274 public:
275 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
277 #if defined _MSC_VER
278 static Inst * m_pInstance = NULL;
279 #endif // _MSC_VER
280 Inst * p = m_pInstance;
281 if (!p)
283 Guard aGuard(aGuardCtor());
284 p = m_pInstance;
285 if (!p)
287 p = aInstCtor();
288 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
289 m_pInstance = p;
292 else
294 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
296 return p;
299 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
300 DataCtor aDataCtor)
302 #if defined _MSC_VER
303 static Inst * m_pInstance = NULL;
304 #endif // _MSC_VER
305 Inst * p = m_pInstance;
306 if (!p)
308 Data aData(aDataCtor());
309 Guard aGuard(aGuardCtor());
310 p = m_pInstance;
311 if (!p)
313 p = aInstCtor(aData);
314 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
315 m_pInstance = p;
318 else
320 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
322 return p;
325 static Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
326 const Data &rData)
328 #if defined _MSC_VER
329 static Inst * m_pInstance = 0;
330 #endif // _MSC_VER
331 Inst * p = m_pInstance;
332 if (!p)
334 Guard aGuard(aGuardCtor());
335 p = m_pInstance;
336 if (!p)
338 p = aInstCtor(rData);
339 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
340 m_pInstance = p;
343 else
345 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
347 return p;
350 private:
351 #if !defined _MSC_VER
352 static Inst * m_pInstance;
353 #endif // _MSC_VER
356 #if !defined _MSC_VER
357 template< typename Inst, typename InstCtor,
358 typename Guard, typename GuardCtor,
359 typename Data, typename DataCtor >
360 Inst *
361 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
362 = NULL;
363 #endif // _MSC_VER
367 namespace rtl {
369 /** Helper base class for a late-initialized (default-constructed)
370 static variable, implementing the double-checked locking pattern correctly.
372 @derive
373 Derive from this class (common practice), e.g.
374 <pre>
375 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
377 MyType & rStatic = MyStatic::get();
379 </pre>
381 @tparam T
382 variable's type
383 @tparam Unique
384 Implementation trick to make the inner static holder unique,
385 using the outer class
386 (the one that derives from this base class)
388 #if defined LIBO_INTERNAL_ONLY
389 template<typename T, typename Unique>
390 class Static {
391 public:
392 /** Gets the static. Mutual exclusion is implied by a functional
393 -fthreadsafe-statics
395 @return
396 static variable
398 static T & get() {
399 static T instance;
400 return instance;
403 #else
404 template<typename T, typename Unique>
405 class Static {
406 public:
407 /** Gets the static. Mutual exclusion is performed using the
408 osl global mutex.
410 @return
411 static variable
413 static T & get() {
414 return *rtl_Instance<
415 T, StaticInstance,
416 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
417 StaticInstance(), ::osl::GetGlobalMutex() );
419 private:
420 struct StaticInstance {
421 T * operator () () {
422 static T instance;
423 return &instance;
427 #endif
429 /** Helper base class for a late-initialized (default-constructed)
430 static variable, implementing the double-checked locking pattern correctly.
432 @derive
433 Derive from this class (common practice), e.g.
434 <pre>
435 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
437 MyType & rStatic = MyStatic::get();
439 </pre>
441 @tparam T
442 variable's type
443 @tparam Unique
444 Implementation trick to make the inner static holder unique,
445 using the outer class
446 (the one that derives from this base class)
448 #if defined LIBO_INTERNAL_ONLY
449 template<typename T, typename Data, typename Unique>
450 class StaticWithArg {
451 public:
452 /** Gets the static. Mutual exclusion is implied by a functional
453 -fthreadsafe-statics
455 @return
456 static variable
458 static T & get(const Data& rData) {
459 static T instance(rData);
460 return instance;
463 /** Gets the static. Mutual exclusion is implied by a functional
464 -fthreadsafe-statics
466 @return
467 static variable
469 static T & get(Data& rData) {
470 static T instance(rData);
471 return instance;
474 #else
475 template<typename T, typename Data, typename Unique>
476 class StaticWithArg {
477 public:
478 /** Gets the static. Mutual exclusion is performed using the
479 osl global mutex.
481 @return
482 static variable
484 static T & get(const Data& rData) {
485 return *rtl_Instance<
486 T, StaticInstanceWithArg,
487 ::osl::MutexGuard, ::osl::GetGlobalMutex,
488 Data >::create( StaticInstanceWithArg(),
489 ::osl::GetGlobalMutex(),
490 rData );
493 /** Gets the static. Mutual exclusion is performed using the
494 osl global mutex.
496 @return
497 static variable
499 static T & get(Data& rData) {
500 return *rtl_Instance<
501 T, StaticInstanceWithArg,
502 ::osl::MutexGuard, ::osl::GetGlobalMutex,
503 Data >::create( StaticInstanceWithArg(),
504 ::osl::GetGlobalMutex(),
505 rData );
507 private:
508 struct StaticInstanceWithArg {
509 T * operator () (const Data& rData) {
510 static T instance(rData);
511 return &instance;
514 T * operator () (Data& rData) {
515 static T instance(rData);
516 return &instance;
520 #endif
522 /** Helper class for a late-initialized static aggregate, e.g. an array,
523 implementing the double-checked locking pattern correctly.
525 @tparam T
526 aggregate's element type
527 @tparam InitAggregate
528 initializer functor class
530 #if defined LIBO_INTERNAL_ONLY
531 template<typename T, typename InitAggregate>
532 class StaticAggregate {
533 public:
534 /** Gets the static aggregate, late-initializing.
535 Mutual exclusion is implied by a functional
536 -fthreadsafe-statics
538 @return
539 aggregate
541 static T * get() {
542 static T *instance = InitAggregate()();
543 return instance;
546 #else
547 template<typename T, typename InitAggregate>
548 class StaticAggregate {
549 public:
550 /** Gets the static aggregate, late-initializing.
551 Mutual exclusion is performed using the osl global mutex.
553 @return
554 aggregate
556 static T * get() {
557 return rtl_Instance<
558 T, InitAggregate,
559 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
560 InitAggregate(), ::osl::GetGlobalMutex() );
563 #endif
564 /** Helper base class for a late-initialized static variable,
565 implementing the double-checked locking pattern correctly.
567 @derive
568 Derive from this class (common practice),
569 providing an initializer functor class, e.g.
570 <pre>
571 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
572 MyType operator () () {
574 return MyType( ... );
578 MyType & rStatic = MyStatic::get();
580 </pre>
582 @tparam T
583 variable's type
584 @tparam InitData
585 initializer functor class
586 @tparam Unique
587 Implementation trick to make the inner static holder unique,
588 using the outer class
589 (the one that derives from this base class).
590 Default is InitData (common practice).
591 @tparam Data
592 Initializer functor's return type.
593 Default is T (common practice).
595 #if defined LIBO_INTERNAL_ONLY
596 template<typename T, typename InitData,
597 typename Unique = InitData, typename Data = T>
598 class StaticWithInit {
599 public:
600 /** Gets the static. Mutual exclusion is implied by a functional
601 -fthreadsafe-statics
603 @return
604 static variable
606 static T & get() {
607 static T instance = InitData()();
608 return instance;
611 #else
612 template<typename T, typename InitData,
613 typename Unique = InitData, typename Data = T>
614 class StaticWithInit {
615 public:
616 /** Gets the static. Mutual exclusion is performed using the
617 osl global mutex.
619 @return
620 static variable
622 static T & get() {
623 return *rtl_Instance<
624 T, StaticInstanceWithInit,
625 ::osl::MutexGuard, ::osl::GetGlobalMutex,
626 Data, InitData >::create( StaticInstanceWithInit(),
627 ::osl::GetGlobalMutex(),
628 InitData() );
630 private:
631 struct StaticInstanceWithInit {
632 T * operator () ( Data d ) {
633 static T instance(d);
634 return &instance;
638 #endif
639 } // namespace rtl
641 #endif // INCLUDED_RTL_INSTANCE_HXX
643 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */