NCBI C++ ToolKit
ncbi_safe_static.hpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 #ifndef NCBI_SAFE_STATIC__HPP
2 #define NCBI_SAFE_STATIC__HPP
3 
4 /* $Id: ncbi_safe_static.hpp 99664 2023-04-27 18:07:41Z vasilche $
5  * ===========================================================================
6  *
7  * PUBLIC DOMAIN NOTICE
8  * National Center for Biotechnology Information
9  *
10  * This software/database is a "United States Government Work" under the
11  * terms of the United States Copyright Act. It was written as part of
12  * the author's official duties as a United States Government employee and
13  * thus cannot be copyrighted. This software/database is freely available
14  * to the public for use. The National Library of Medicine and the U.S.
15  * Government have not placed any restriction on its use or reproduction.
16  *
17  * Although all reasonable efforts have been taken to ensure the accuracy
18  * and reliability of the software and data, the NLM and the U.S.
19  * Government do not and cannot warrant the performance or results that
20  * may be obtained by using this software or data. The NLM and the U.S.
21  * Government disclaim all warranties, express or implied, including
22  * warranties of performance, merchantability or fitness for any particular
23  * purpose.
24  *
25  * Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author: Aleksey Grichenko
30  *
31  * File Description:
32  * Static variables safety - create on demand, destroy on termination
33  *
34  * CSafeStaticPtr_Base:: -- base class for CSafePtr<> and CSafeRef<>
35  * CSafeStaticPtr<>:: -- create variable on demand, destroy on program
36  * termination (see NCBIOBJ for CSafeRef<> class)
37  * CSafeStaticRef<>:: -- create variable on demand, destroy on program
38  * termination (see NCBIOBJ for CSafeRef<> class)
39  * CSafeStaticGuard:: -- guarantee for CSafePtr<> and CSafeRef<>
40  * destruction and cleanup
41  *
42  */
43 
44 /// @file ncbi_safe_static.hpp
45 /// Static variables safety - create on demand, destroy on application
46 /// termination.
47 
48 #include <corelib/ncbiobj.hpp>
49 #include <corelib/ncbimtx.hpp>
50 #include <corelib/ncbi_limits.h>
51 #include <array>
52 
53 
55 
56 class CObject;
57 
58 /////////////////////////////////////////////////////////////////////////////
59 ///
60 /// CSafeStaticLifeSpan::
61 ///
62 /// Class for specifying safe static object life span.
63 ///
64 
66 {
67 public:
68  /// Predefined life levels for the safe static objects
69  enum ELifeLevel {
71  eLifeLevel_AppMain ///< Destroyed in CNcbiApplication::AppMain, if possible
72  };
73  /// Predefined life spans for the safe static objects
74  enum ELifeSpan {
75  eLifeSpan_Min = kMin_Int, ///< std static, not adjustable
76  eLifeSpan_Shortest = -20000,
77  eLifeSpan_Short = -10000,
78  eLifeSpan_Normal = 0,
79  eLifeSpan_Long = 10000,
80  eLifeSpan_Longest = 20000
81  };
82  /// Constructs a life span object from basic level and adjustment.
83  /// Generates warning (and assertion in debug mode) if the adjustment
84  /// argument is too big (<= -5000 or >= 5000). If span is eLifeSpan_Min
85  /// "adjust" is ignored.
86  CSafeStaticLifeSpan(ELifeSpan span, int adjust = 0);
87  /// Same as above but allows to specify life level.
88  /// E.g. eLifeLevel_AppMain allows to destroy such objects on AppMain exit
89  /// (useful for static objects that join threads in their destructors,
90  /// otherwise threads might disappear before such destructors are called).
91  CSafeStaticLifeSpan(ELifeLevel level, ELifeSpan span, int adjust = 0);
92 
93  /// Get life level value.
94  ELifeLevel GetLifeLevel() const { return m_LifeLevel; }
95 
96  /// Get life span value.
97  int GetLifeSpan(void) const { return m_LifeSpan; }
98 
99  /// Get default life span (set to eLifeSpan_Min).
100  static CSafeStaticLifeSpan& GetDefault(void);
101 
102 private:
105 };
106 
107 
108 /////////////////////////////////////////////////////////////////////////////
109 ///
110 /// CSafeStaticPtr_Base::
111 ///
112 /// Base class for CSafeStaticPtr<> and CSafeStaticRef<> templates.
113 ///
114 
116 {
117 public:
118  /// User cleanup function type
119  typedef void (*FUserCleanup)(void* ptr);
120 
121  /// Life span
123 
124  ~CSafeStaticPtr_Base(void);
125 
126 protected:
128 
129  /// Cleanup function type used by derived classes
130  typedef void (*FSelfCleanup)(CSafeStaticPtr_Base* safe_static,
131  TInstanceMutexGuard& guard);
132 
133  /// Constructor.
134  ///
135  /// @param self_cleanup
136  /// Cleanup function to be executed on destruction,
137  /// provided by a derived class.
138  /// @param user_cleanup
139  /// User-provided cleanup function to be executed on destruction.
140  /// @param life_span
141  /// Life span allows to control destruction of objects. Objects with
142  /// the same life span are destroyed in the order reverse to their
143  /// creation order.
144  /// @sa CSafeStaticLifeSpan
145  CSafeStaticPtr_Base(FSelfCleanup self_cleanup,
146  FUserCleanup user_cleanup = 0,
147  TLifeSpan life_span = TLifeSpan::GetDefault())
148  : m_SelfCleanup(self_cleanup),
149  m_UserCleanup(user_cleanup),
150  m_LifeSpan(life_span),
151  m_CreationOrder(x_GetCreationOrder())
152  {}
153 
154  /// Pointer to the data
155  atomic<const void*> m_Ptr;
156 
158 
159 protected:
160  const void* x_GetPtr() const {
161  return m_Ptr.load(memory_order_acquire);
162  }
163  void x_SetPtr(const void* ptr) {
164  m_Ptr.store(ptr, memory_order_release);
165  }
166  bool x_IsSetPtr() const {
167  return x_GetPtr() != nullptr;
168  }
169  const void* x_ReleasePtr() {
170  if ( auto ptr = x_GetPtr() ) {
171  x_SetPtr(0);
172  return ptr;
173  }
174  else {
175  return nullptr;
176  }
177  }
178 
179 private:
180  friend struct SSimpleLock<CSafeStaticPtr_Base>;
181  friend struct SSimpleUnlock<CSafeStaticPtr_Base>;
182 
183  void Lock(void)
184  {
185  CMutexGuard guard(sm_ClassMutex);
186  if (!m_InstanceMutex || !m_MutexRefCount) {
187  m_InstanceMutex = new CMutex;
188  m_MutexRefCount = 1;
189  }
190  ++m_MutexRefCount;
191  guard.Release();
192  m_InstanceMutex->Lock();
193  }
194 
195  void Unlock(void)
196  {
197  m_InstanceMutex->Unlock();
198  x_ReleaseInstanceMutex();
199  }
200 
202  {
203  CMutexGuard guard(sm_ClassMutex);
204  if (--m_MutexRefCount > 0) return;
205  // Workaround for over-optimization - member assignments done immediately
206  // before exiting destructor can be dropped, so mutex and counter should
207  // be set to 0 before deleting the mutex.
208  CMutex* tmp = m_InstanceMutex;
209  m_InstanceMutex = 0;
210  m_MutexRefCount = 0;
211  delete tmp;
212  }
213 
214 protected:
215  friend class CSafeStatic_Less;
216 
217  FSelfCleanup m_SelfCleanup; // Derived class' cleanup function
218  FUserCleanup m_UserCleanup; // User-provided cleanup function
219  TLifeSpan m_LifeSpan; // Life span of the object
220  int m_CreationOrder; // Creation order of the object
221  int m_MutexRefCount; // Mutex reference counter.
222  CMutex* m_InstanceMutex; // Mutex used to create/destroy value.
223 
224  static int x_GetCreationOrder(void);
225 
226  // Return true if the object should behave like regular static
227  // (no delayed destruction).
228  bool x_IsStdStatic(void) const
229  {
230  return (m_LifeSpan.GetLifeLevel() == CSafeStaticLifeSpan::eLifeLevel_Default) &&
232  }
233 
234  // To be called by CSafeStaticGuard on the program termination
235  friend class CSafeStaticGuard;
236  void x_Cleanup(void)
237  {
238  // Note: x_Cleanup should always be called with sm_ClassMutex locked.
239  if ( m_SelfCleanup ) {
240  TInstanceMutexGuard guard(*this);
241  m_SelfCleanup(this, guard);
242  }
243  // Delete instance mutex if it's not used by other threads.
244  x_ReleaseInstanceMutex();
245  }
246 };
247 
248 
249 /// Comparison for safe static ptrs. Defines order of objects' destruction:
250 /// short living objects go first; if life span of several objects is the same,
251 /// the order of destruction is reverse to the order of their creation.
253 {
254 public:
256  bool operator()(const TPtr& ptr1, const TPtr& ptr2) const
257  {
258  if (ptr1->m_LifeSpan.GetLifeSpan() == ptr2->m_LifeSpan.GetLifeSpan()) {
259  return ptr1->m_CreationOrder > ptr2->m_CreationOrder;
260  }
261  return ptr1->m_LifeSpan.GetLifeSpan() < ptr2->m_LifeSpan.GetLifeSpan();
262  }
263 };
264 
265 
266 /////////////////////////////////////////////////////////////////////////////
267 ///
268 /// CSafeStaticGuard::
269 ///
270 /// Register all on-demand variables,
271 /// destroy them on the program termination.
272 
274 {
275 public:
276  /// Check if already initialized. If not - create the stack,
277  /// otherwise just increment the reference count.
278  CSafeStaticGuard(void);
279 
280  /// Check reference count, and if it is zero, then destroy
281  /// all registered variables.
282  ~CSafeStaticGuard(void);
283 
284  /// Add new on-demand variable to the cleanup stack.
285  static void Register(CSafeStaticPtr_Base* ptr)
286  {
287  if ( sm_RefCount > 0 && ptr->x_IsStdStatic() ) {
288  // Do not add the object to the stack
289  return;
290  }
291 
292  auto& stack = x_GetStack(ptr->m_LifeSpan.GetLifeLevel());
293 
294  if ( !stack ) {
295  x_Get();
296  }
297  stack->insert(ptr);
298  }
299 
300  /// Disable checking on child thread(s) running during destruction
301  static void DisableChildThreadsCheck();
302 
303  /// Explicitly destroy all on-demand variables up to a specified level
304  static void Destroy(CSafeStaticLifeSpan::ELifeLevel level);
305 
306 private:
307  // Initialize the guard, return pointer to it.
308  static CSafeStaticGuard* x_Get(void);
309 
310  // Stack to keep registered variables.
312 
313  // Get a stack based on a level
315  {
316  static array<TStack*, 2> stacks;
317 
318  const size_t index = level;
319  _ASSERT(level >= 0);
320  _ASSERT(index < stacks.size());
321  return stacks[index];
322  }
323 
324  // Cleanup a stack
325  static void x_Cleanup(CMutexGuard& guard, TStack*& stack);
326 
327  // Reference counter. The stack is destroyed when
328  // the last reference is removed.
329  static int sm_RefCount;
330 
331  // Whether to check on child thread(s) running during destruction
332  static bool sm_ChildThreadsCheck;
333 };
334 
335 
336 /// Helper class for object allocation/deallocation.
337 /// Required to simplify friend declarations for classes with
338 /// private constructors/destructors and to support CObject
339 /// reference counting.
340 
341 template <class T>
343 {
344 public:
345  /// Create a new class instance.
346  static T* s_Create(void) { return new T; }
347 
348  // CSafeStatic must use AddReference/RemoveReference for CObject derived
349  // classes. To do this there are two different versions of the following
350  // methods.
351  static void s_AddReference(void*) {}
352  static void s_AddReference(const void*) {}
353  static void s_AddReference(CObject* ptr)
354  {
355  if (ptr) ptr->AddReference();
356  }
357  static void s_RemoveReference(void* ptr)
358  {
359  if (ptr) delete static_cast<T*>(ptr);
360  }
361  static void s_RemoveReference(const void* ptr)
362  {
363  if (ptr) delete const_cast<T*>(static_cast<const T*>(ptr));
364  }
365  static void s_RemoveReference(CObject* ptr)
366  {
367  if (ptr) ptr->RemoveReference();
368  }
369  static void s_RemoveReference(const CObject* ptr)
370  {
371  if (ptr) ptr->RemoveReference();
372  }
373 };
374 
375 
376 /// Initialization and cleanup of a safe-static object.
377 /// Must implement at least Create() and Cleanup() methods.
378 /// Create() must create a new object and return the initialized
379 /// pointer. Cleanup() can be a no-op.
380 /// The default implementation allows to use it as a wrapper for
381 /// static callback functions.
382 template <class T>
384 {
385 public:
386  /// The default implementation allows to use callback functions
387  /// rather than a new class.
388  typedef T* (*FCreate)(void);
389  typedef void (*FCleanup)(T& value);
391 
392  /// The constructor allows to use CSafeStatic_Callbacks as a simple
393  /// wrapper for static functions.
394  /// @param create
395  /// Initialization function which must create a new object. If null,
396  /// no special initialization is performed.
397  /// @param cleanup
398  /// Cleanup function. If null, no special cleanup is performed.
400  : m_Create(create), m_Cleanup(cleanup) {}
401 
402  /// Create new object.
403  /// @return
404  /// The allocated object.
405  T* Create(void) {
406  return (m_Create) ? m_Create() : TAllocator::s_Create();
407  }
408 
409  /// Perform cleanup before destruction.
410  /// @param ptr
411  /// Object to be destroyed using the selected allocator. The cleanup
412  /// method should not destroy the object itself, just perform any
413  /// additional actions (e.g. setting some external pointers to null).
414  void Cleanup(T& value) {
415  if ( m_Cleanup ) {
416  m_Cleanup(value);
417  }
418  }
419 
420 private:
423 };
424 
425 
426 /////////////////////////////////////////////////////////////////////////////
427 ///
428 /// CSafeStatic<>::
429 ///
430 /// For on-demand object access, both non-CObject and CObject based.
431 /// Create the variable of type "T" on the first access. The default
432 /// implementation of allocator uses reference counter of CObject
433 /// class to prevent premature destruction.
434 /// Should be used only as static object. Otherwise the correct
435 /// initialization is not guaranteed.
436 /// @param T
437 /// Type of the variable to be stored.
438 /// @param Callbacks
439 /// A class implementing two methods to perform additional initialization
440 /// and cleanup:
441 /// void Create(T* ptr)
442 /// void Cleanup(T* ptr)
443 /// NOTE: The Cleanup callback must not destroy the object itself, just
444 /// perform any additional actions.
445 template <class T,
446  class Callbacks = CSafeStatic_Callbacks<T> >
448 {
449  static T* x_CastPtr(const void* ptr) {
450  return static_cast<T*>(const_cast<void*>(ptr));
451  }
452 public:
453  typedef Callbacks TCallbacks;
457 
458  /// Callback function types. The default callback class can be used
459  /// as a simple wrapper for static functions.
460  /// @sa CSafeStatic_Callbacks
463 
464  /// Constructor.
465  /// @param life_span
466  /// Life span allows to control destruction of objects. Objects with
467  /// the same life span are destroyed in the order reverse to their
468  /// creation order.
469  /// @sa CSafeStaticLifeSpan
471  : CSafeStaticPtr_Base(sx_SelfCleanup, 0, life_span)
472  {}
473 
474  /// Constructor.
475  /// @param init
476  /// Callback function to be used to create the stored object.
477  /// @param cleanup
478  /// Callback function to be used for additional cleanup.
479  /// @param life_span
480  /// Life span allows to control destruction of objects. Objects with
481  /// the same life span are destroyed in the order reverse to their
482  /// creation order.
483  /// @sa CSafeStaticLifeSpan
486  TLifeSpan life_span = TLifeSpan::GetDefault())
487  : CSafeStaticPtr_Base(sx_SelfCleanup, 0, life_span),
488  m_Callbacks(create, cleanup)
489  {}
490 
491  /// Constructor.
492  /// @param callbacks
493  /// Callbacks class instance.
494  /// @param life_span
495  /// Life span allows to control destruction of objects. Objects with
496  /// the same life span are destroyed in the order reverse to their
497  /// creation order.
498  /// @sa CSafeStaticLifeSpan
500  TLifeSpan life_span = TLifeSpan::GetDefault())
501  : CSafeStaticPtr_Base(sx_SelfCleanup, 0, life_span),
502  m_Callbacks(callbacks)
503  {}
504 
505  /// Create the variable if not created yet, return the reference.
506  T& Get(void)
507  {
508  if ( !x_IsSetPtr() ) {
509  x_Init();
510  }
511  return *x_CastPtr(x_GetPtr());
512  }
513 
514  T* operator-> (void) { return &Get(); }
515  T& operator* (void) { return Get(); }
516 
517 private:
518  CSafeStatic(const CSafeStatic&) = delete;
519  CSafeStatic& operator=(const CSafeStatic&) = delete;
520 
521  void x_Init(void) {
522  TInstanceMutexGuard guard(*this);
523  if ( !x_IsSetPtr() ) {
524  // Create the object and register for cleanup
525  T* ptr = 0;
526  try {
527  ptr = m_Callbacks.Create();
529  x_SetPtr(ptr);
531  }
532  catch (CException& e) {
534  NCBI_RETHROW_SAME(e, "CSafeStatic::Init: Register() failed");
535  }
536  catch (...) {
539  "CSafeStatic::Init: Register() failed");
540  }
541  }
542  }
543 
544  // "virtual" cleanup function
545  static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static,
546  TInstanceMutexGuard& guard)
547  {
548  TThisType* this_ptr = static_cast<TThisType*>(safe_static);
549  if ( T* ptr = x_CastPtr(this_ptr->x_ReleasePtr()) ) {
550  TCallbacks callbacks = this_ptr->m_Callbacks;
551  guard.Release();
552  callbacks.Cleanup(*ptr);
554  }
555  }
556 
558 };
559 
560 
561 /// Safe static callbacks version allowing initial value of type V
562 // to be set through template argument.
563 template<class T, class V, V value>
565 {
566 public:
567  T* Create(void) {
568  return new T(value);
569  }
570 };
571 
572 
573 /// Declare CSafeStatic<const type>, initialize it with 'init_value' of the same type.
574 #define SAFE_CONST_STATIC(type, init_value) \
575  SAFE_CONST_STATIC_EX(type, type, init_value)
576 
577 /// Declare CSafeStatic<const type>, initialize it with 'init_value' of type
578 /// 'init_value_type'.
579 #define SAFE_CONST_STATIC_EX(type, init_value_type, init_value) \
580  CSafeStatic< const type, \
581  CSafeStaticInit_Callbacks<const type, init_value_type, init_value> >
582 
583 /// Declare CSafeStatic<const string>, initialize it with 'const char* value'.
584 #define SAFE_CONST_STATIC_STRING(var, value) \
585  char SAFE_CONST_STATIC_STRING_##var[] = value; \
586  SAFE_CONST_STATIC_EX(std::string, const char*, \
587  SAFE_CONST_STATIC_STRING_##var) var
588 
589 
590 
591 /////////////////////////////////////////////////////////////////////////////
592 ///
593 /// CSafeStaticPtr<>::
594 ///
595 /// For simple on-demand variables.
596 /// Create the variable of type "T" on demand,
597 /// destroy it on the program termination.
598 /// Should be used only as static object. Otherwise
599 /// the correct initialization is not guaranteed.
600 /// @deprecated Use CSafeStatic<> instead.
601 
602 template <class T>
604 {
605  static T* x_CastPtr(const void* ptr) {
606  return static_cast<T*>(const_cast<void*>(ptr));
607  }
608 public:
610 
611  /// Constructor.
612  ///
613  /// @param user_cleanup
614  /// User-provided cleanup function to be executed on destruction.
615  /// @param life_span
616  /// Life span allows to control destruction of objects.
617  /// @sa CSafeStaticPtr_Base
618  CSafeStaticPtr(FUserCleanup user_cleanup = 0,
619  TLifeSpan life_span = TLifeSpan::GetDefault())
620  : CSafeStaticPtr_Base(sx_SelfCleanup, user_cleanup, life_span)
621  {}
622 
623  /// Create the variable if not created yet, return the reference.
624  T& Get(void)
625  {
626  if ( !x_IsSetPtr() ) {
627  x_Init();
628  }
629  return *x_CastPtr(x_GetPtr());
630  }
631  /// Get the existing object or create a new one using the provided
632  /// FUserCreate object.
633  /// @deprecated Use CSafeStatic class instead.
634  template <class FUserCreate>
636  T& Get(FUserCreate user_create)
637  {
638  if ( !x_IsSetPtr() ) {
639  x_Init(user_create);
640  }
641  return *x_CastPtr(x_GetPtr());
642  }
643 
644  T* operator -> (void) { return &Get(); }
645  T& operator * (void) { return Get(); }
646 
647  /// Initialize with an existing object. The object MUST be
648  /// allocated with "new T" -- it will be destroyed with
649  /// "delete object" in the end. Set() works only for
650  /// not yet initialized safe-static variables.
651  void Set(T* object);
652 
653 private:
654  // Initialize the object
655  void x_Init(void);
656 
657  template <class FUserCreate>
658  void x_Init(FUserCreate user_create);
659 
660  // "virtual" cleanup function
661  static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static,
662  TInstanceMutexGuard& guard)
663  {
664  CSafeStaticPtr<T>* this_ptr = static_cast<CSafeStaticPtr<T>*>(safe_static);
665  if ( T* ptr = x_CastPtr(this_ptr->x_ReleasePtr()) ) {
666  CSafeStaticPtr_Base::FUserCleanup user_cleanup = this_ptr->m_UserCleanup;
667  guard.Release();
668  if ( user_cleanup ) {
669  user_cleanup(ptr);
670  }
671  delete ptr;
672  }
673  }
674 };
675 
676 
677 
678 /////////////////////////////////////////////////////////////////////////////
679 ///
680 /// CSafeStaticRef<>::
681 ///
682 /// For on-demand CObject-derived object.
683 /// Create the variable of type "T" using CRef<>
684 /// (to avoid premature destruction).
685 /// Should be used only as static object. Otherwise
686 /// the correct initialization is not guaranteed.
687 /// @deprecated Use CSafeStatic<> instead.
688 template <class T>
690 {
691  static T* x_CastPtr(const void* ptr) {
692  return static_cast<T*>(const_cast<void*>(ptr));
693  }
694 public:
696 
697  /// Constructor.
698  ///
699  /// @param user_cleanup
700  /// User-provided cleanup function to be executed on destruction.
701  /// @param life_span
702  /// Life span allows to control destruction of objects.
703  /// @sa CSafeStaticPtr_Base
704  CSafeStaticRef(FUserCleanup user_cleanup = 0,
705  TLifeSpan life_span = TLifeSpan::GetDefault())
706  : CSafeStaticPtr_Base(sx_SelfCleanup, user_cleanup, life_span)
707  {}
708 
709  /// Create the variable if not created yet, return the reference.
710  T& Get(void)
711  {
712  if ( !x_IsSetPtr() ) {
713  x_Init();
714  }
715  return *x_CastPtr(x_GetPtr());
716  }
717  /// Get the existing object or create a new one using the provided
718  /// FUserCreate object.
719  /// @deprecated Use CSafeStatic class instead.
720  template <class FUserCreate>
722  T& Get(FUserCreate user_create)
723  {
724  if ( !x_IsSetPtr() ) {
725  x_Init(user_create);
726  }
727  return *x_CastPtr(x_GetPtr());
728  }
729 
730  T* operator -> (void) { return &Get(); }
731  T& operator * (void) { return Get(); }
732 
733  /// Initialize with an existing object. The object MUST be
734  /// allocated with "new T" to avoid premature destruction.
735  /// Set() works only for un-initialized safe-static variables.
736  void Set(T* object);
737 
738 private:
739  // Initialize the object and the reference
740  void x_Init(void);
741 
742  template <class FUserCreate>
743  void x_Init(FUserCreate user_create);
744 
745  // "virtual" cleanup function
746  static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static,
747  TInstanceMutexGuard& guard)
748  {
749  CSafeStaticRef<T>* this_ptr = static_cast<CSafeStaticRef<T>*>(safe_static);
750  if ( T* ptr = x_CastPtr(this_ptr->x_ReleasePtr()) ) {
751  CSafeStaticPtr_Base::FUserCleanup user_cleanup = this_ptr->m_UserCleanup;
752  guard.Release();
753  if ( user_cleanup ) {
754  user_cleanup(ptr);
755  }
756  ptr->RemoveReference();
757  }
758  }
759 };
760 
761 
762 /////////////////////////////////////////////////////////////////////////////
763 ///
764 /// This static variable must be present in all modules using
765 /// on-demand static variables. The guard must be created first
766 /// regardless of the modules initialization order.
767 
769 
770 
771 /////////////////////////////////////////////////////////////////////////////
772 //
773 // Large inline methods
774 
775 template <class T>
776 inline
778 {
779  TInstanceMutexGuard guard(*this);
780  if ( !x_IsSetPtr() ) {
781  // Set the new object and register for cleanup
782  if ( object ) {
783  x_SetPtr(object);
785  }
786  }
787 }
788 
789 
790 template <class T>
791 inline
793 {
794  TInstanceMutexGuard guard(*this);
795  if ( !x_IsSetPtr() ) {
796  // Create the object and register for cleanup
797  x_SetPtr(new T);
799  }
800 }
801 
802 
803 template <class T>
804 template <class FUserCreate>
805 inline
806 void CSafeStaticPtr<T>::x_Init(FUserCreate user_create)
807 {
808  TInstanceMutexGuard guard(*this);
809  if ( !x_IsSetPtr() ) {
810  // Create the object and register for cleanup
811  if ( auto ptr = user_create() ) {
812  x_SetPtr(ptr);
814  }
815  }
816 }
817 
818 
819 template <class T>
820 inline
822 {
823  TInstanceMutexGuard guard(*this);
824  if ( !x_IsSetPtr() ) {
825  // Set the new object and register for cleanup
826  if ( object ) {
827  object->AddReference();
828  x_SetPtr(object);
830  }
831  }
832 }
833 
834 
835 template <class T>
836 inline
838 {
839  TInstanceMutexGuard guard(*this);
840  if ( !x_IsSetPtr() ) {
841  // Create the object and register for cleanup
842  T* ptr = new T;
843  ptr->AddReference();
844  x_SetPtr(ptr);
846  }
847 }
848 
849 
850 template <class T>
851 template <class FUserCreate>
852 inline
853 void CSafeStaticRef<T>::x_Init(FUserCreate user_create)
854 {
855  TInstanceMutexGuard guard(*this);
856  if ( !x_IsSetPtr() ) {
857  // Create the object and register for cleanup
858  T* ptr = user_create();
859  if ( ptr ) {
860  ptr->AddReference();
861  x_SetPtr(ptr);
863  }
864  }
865 }
866 
867 
868 
870 
871 #endif /* NCBI_SAFE_STATIC__HPP */
CCoreException –.
Definition: ncbiexpt.hpp:1476
void Release()
Manually force the resource to be released.
Definition: guard.hpp:166
CMutex –.
Definition: ncbimtx.hpp:749
CObject –.
Definition: ncbiobj.hpp:180
CSafeStaticGuard::
static void Register(CSafeStaticPtr_Base *ptr)
Add new on-demand variable to the cleanup stack.
static TStack *& x_GetStack(CSafeStaticLifeSpan::ELifeLevel level)
static bool sm_ChildThreadsCheck
multiset< CSafeStaticPtr_Base *, CSafeStatic_Less > TStack
Safe static callbacks version allowing initial value of type V.
CSafeStaticLifeSpan::
ELifeLevel GetLifeLevel() const
Get life level value.
static CSafeStaticLifeSpan & GetDefault(void)
Get default life span (set to eLifeSpan_Min).
int GetLifeSpan(void) const
Get life span value.
ELifeSpan
Predefined life spans for the safe static objects.
@ eLifeSpan_Min
std static, not adjustable
ELifeLevel
Predefined life levels for the safe static objects.
CSafeStaticPtr_Base::
DECLARE_CLASS_STATIC_MUTEX(sm_ClassMutex)
void(* FUserCleanup)(void *ptr)
User cleanup function type.
const void * x_GetPtr() const
CGuard< CSafeStaticPtr_Base > TInstanceMutexGuard
CSafeStaticPtr_Base(FSelfCleanup self_cleanup, FUserCleanup user_cleanup=0, TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
CSafeStaticLifeSpan TLifeSpan
Life span.
void x_ReleaseInstanceMutex(void)
bool x_IsStdStatic(void) const
atomic< const void * > m_Ptr
Pointer to the data.
void x_SetPtr(const void *ptr)
const void * x_ReleasePtr()
CSafeStaticPtr<>::
static void sx_SelfCleanup(CSafeStaticPtr_Base *safe_static, TInstanceMutexGuard &guard)
CSafeStaticLifeSpan TLifeSpan
static T * x_CastPtr(const void *ptr)
T & Get(FUserCreate user_create)
Get the existing object or create a new one using the provided FUserCreate object.
void Set(T *object)
Initialize with an existing object.
CSafeStaticPtr(FUserCleanup user_cleanup=0, TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
T & Get(void)
Create the variable if not created yet, return the reference.
CSafeStaticRef<>::
T & Get(void)
Create the variable if not created yet, return the reference.
static void sx_SelfCleanup(CSafeStaticPtr_Base *safe_static, TInstanceMutexGuard &guard)
void x_Init(FUserCreate user_create)
static T * x_CastPtr(const void *ptr)
void Set(T *object)
Initialize with an existing object.
T & Get(FUserCreate user_create)
Get the existing object or create a new one using the provided FUserCreate object.
CSafeStaticLifeSpan TLifeSpan
CSafeStaticRef(FUserCleanup user_cleanup=0, TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
Helper class for object allocation/deallocation.
static void s_RemoveReference(CObject *ptr)
static void s_RemoveReference(const CObject *ptr)
static void s_RemoveReference(const void *ptr)
static void s_AddReference(const void *)
static void s_AddReference(void *)
static void s_RemoveReference(void *ptr)
static void s_AddReference(CObject *ptr)
static T * s_Create(void)
Create a new class instance.
Initialization and cleanup of a safe-static object.
CSafeStatic_Callbacks(FCreate create=0, FCleanup cleanup=0)
The constructor allows to use CSafeStatic_Callbacks as a simple wrapper for static functions.
void Cleanup(T &value)
Perform cleanup before destruction.
T * Create(void)
Create new object.
void(* FCleanup)(T &value)
T *(* FCreate)(void)
The default implementation allows to use callback functions rather than a new class.
CSafeStatic_Allocator< T > TAllocator
Comparison for safe static ptrs.
bool operator()(const TPtr &ptr1, const TPtr &ptr2) const
CSafeStaticPtr_Base * TPtr
CSafeStatic<>::
CSafeStatic_Callbacks< T >::FCreate FCreate
Callback function types.
CSafeStatic_Allocator< T > TAllocator
T & operator*(void)
CSafeStatic & operator=(const CSafeStatic &)=delete
CSafeStatic(FCreate create, FCleanup cleanup, TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
static void sx_SelfCleanup(CSafeStaticPtr_Base *safe_static, TInstanceMutexGuard &guard)
TCallbacks m_Callbacks
CSafeStaticLifeSpan TLifeSpan
T & Get(void)
Create the variable if not created yet, return the reference.
void x_Init(void)
CSafeStatic(const CSafeStatic &)=delete
CSafeStatic(TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
CSafeStatic< T, TCallbacks > TThisType
Callbacks TCallbacks
T * operator->(void)
CSafeStatic_Callbacks< T >::FCleanup FCleanup
static T * x_CastPtr(const void *ptr)
CSafeStatic(TCallbacks callbacks, TLifeSpan life_span=TLifeSpan::GetDefault())
Constructor.
#define T(s)
Definition: common.h:230
static void cleanup(void)
Definition: ct_dynamic.c:30
static char tmp[3200]
Definition: utf8.c:42
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
#define NCBI_RETHROW_SAME(prev_exception, message)
Generic macro to re-throw the same exception.
Definition: ncbiexpt.hpp:749
void AddReference(void) const
Add reference to object.
Definition: ncbiobj.hpp:489
void RemoveReference(void) const
Remove reference to object.
Definition: ncbiobj.hpp:500
#define kMin_Int
Definition: ncbi_limits.h:183
#define NCBI_DEPRECATED
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
void Cleanup(CTls< TValue > &value)
Definition: ncbithr.hpp:306
#define NCBI_XNCBI_EXPORT
Definition: ncbi_export.h:1283
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
static CSafeStaticGuard s_CleanupGuard
This static variable must be present in all modules using on-demand static variables.
Multi-threading – mutexes; rw-locks; semaphore.
Portable reference counted smart and weak pointers using CWeakRef, CRef, CObject and CObjectEx.
SSimpleLock is a functor to wrap calling Lock().
Definition: guard.hpp:49
SSimpleLock is a functor to wrap calling Unlock().
Definition: guard.hpp:65
#define _ASSERT
Modified on Tue Apr 16 20:11:28 2024 by modify_doxy.py rev. 669887