EPICS Base  7.0.6.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
epicsSingleton.h
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * SPDX-License-Identifier: EPICS
7 * EPICS Base is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /*
12  * Author: Jeffrey O. Hill
13  */
14 
15 #ifndef epicsSingleton_h
16 #define epicsSingleton_h
17 
18 #include <new>
19 #include <cstddef>
20 
21 #include "libComAPI.h"
22 #include "epicsAssert.h"
23 
24 class LIBCOM_API SingletonUntyped {
25 public:
27  ~SingletonUntyped ();
28  typedef void * ( * PBuild ) ();
29  void incrRefCount ( PBuild );
30  typedef void ( * PDestroy ) ( void * );
31  void decrRefCount ( PDestroy );
32  void * pInstance () const;
33 private:
34  void * _pInstance;
35  std :: size_t _refCount;
37  SingletonUntyped & operator = ( const SingletonUntyped & );
38 };
39 
40 // This class exists for the purpose of avoiding file scope
41 // object chicken and egg problems. It implements thread safe
42 // lazy initialization. To avoid locking overhead retain a
43 // copy of the epicsSingleton :: reference for future use.
44 template < class TYPE >
46 public:
47  class reference {
48  public:
50  reference ( const reference & );
51  ~reference ();
52  // this somewhat convoluted reference of the return
53  // type ref through the epicsSingleton template is
54  // required for the archaic Tornado gnu compiler
56  operator = ( const reference & );
57  TYPE * operator -> ();
58  const TYPE * operator -> () const;
59  TYPE & operator * ();
60  const TYPE & operator * () const;
61  private:
62  epicsSingleton * _pSingleton;
63  };
64  friend class reference;
65  epicsSingleton () {}
66  // mutex lock/unlock pair overhead incurred
67  // when either of these are called
68  reference getReference ();
69  const reference getReference () const;
70 private:
71  SingletonUntyped _singletonUntyped;
72  static void * _build ();
73  static void _destroy ( void * );
74  epicsSingleton ( const epicsSingleton & );
75  epicsSingleton & operator = ( const epicsSingleton & );
76 };
77 
78 template < class TYPE >
79 inline epicsSingleton < TYPE > :: reference ::
80  reference ( epicsSingleton & es ):
81  _pSingleton ( & es )
82 {
83  es._singletonUntyped.
84  incrRefCount ( & epicsSingleton < TYPE > :: _build );
85 }
86 
87 template < class TYPE >
88 inline epicsSingleton < TYPE > :: reference ::
89  reference ( const reference & ref ) :
90  _pSingleton ( ref._pSingleton )
91 {
92  assert ( _pSingleton );
93  _pSingleton->_singletonUntyped.
94  incrRefCount ( & epicsSingleton < TYPE > :: _build );
95 }
96 
97 template < class TYPE >
98 inline epicsSingleton < TYPE > :: reference ::
99  ~reference ()
100 {
101  assert ( _pSingleton );
102  _pSingleton->_singletonUntyped.
103  decrRefCount ( & epicsSingleton < TYPE > :: _destroy );
104 }
105 
106 template < class TYPE >
107 typename epicsSingleton < TYPE > :: reference &
108  epicsSingleton < TYPE > :: reference ::
109  operator = ( const reference & ref )
110 {
111  if ( _pSingleton != ref._pSingleton ) {
112  assert ( _pSingleton );
113  _pSingleton->_singletonUntyped.
114  decrRefCount ( epicsSingleton < TYPE > :: _destroy );
115  _pSingleton = ref._pSingleton;
116  assert ( _pSingleton );
117  _pSingleton->_singletonUntyped.
118  incrRefCount ( & epicsSingleton < TYPE > :: _build );
119  }
120  return *this;
121 }
122 
123 template < class TYPE >
124 inline TYPE *
125  epicsSingleton < TYPE > :: reference ::
126  operator -> ()
127 {
128  assert ( _pSingleton );
129  return reinterpret_cast < TYPE * >
130  ( _pSingleton->_singletonUntyped.pInstance () );
131 }
132 
133 template < class TYPE >
134 inline const TYPE *
135  epicsSingleton < TYPE > :: reference ::
136  operator -> () const
137 {
138  assert ( _pSingleton );
139  return reinterpret_cast < const TYPE * >
140  ( _pSingleton->_singletonUntyped.pInstance () );
141 }
142 
143 template < class TYPE >
144 inline TYPE &
145  epicsSingleton < TYPE > :: reference ::
146  operator * ()
147 {
148  return * this->operator -> ();
149 }
150 
151 template < class TYPE >
152 inline const TYPE &
153  epicsSingleton < TYPE > :: reference ::
154  operator * () const
155 {
156  return * this->operator -> ();
157 }
158 
159 inline SingletonUntyped :: SingletonUntyped () :
160  _pInstance ( 0 ), _refCount ( 0 )
161 {
162 }
163 
164 inline void * SingletonUntyped :: pInstance () const
165 {
166  return _pInstance;
167 }
168 
169 inline SingletonUntyped :: ~SingletonUntyped ()
170 {
171  // we don't assert fail on non-zero _refCount
172  // and or non nill _pInstance here because this
173  // is designed to tolerate situations where
174  // file scope epicsSingleton objects (which
175  // theoretically don't have storage lifespan
176  // issues) are deleted in a non-deterministic
177  // order
178 # if 0
179  assert ( _refCount == 0 );
180  assert ( _pInstance == 0 );
181 # endif
182 }
183 
184 template < class TYPE >
185 void * epicsSingleton < TYPE > :: _build ()
186 {
187  return new TYPE ();
188 }
189 
190 template < class TYPE >
192  _destroy ( void * pDestroyTypeless )
193 {
194  TYPE * pDestroy =
195  reinterpret_cast < TYPE * > ( pDestroyTypeless );
196  delete pDestroy;
197 }
198 
199 template < class TYPE >
200 inline typename epicsSingleton < TYPE > :: reference
201  epicsSingleton < TYPE > :: getReference ()
202 {
203  return reference ( * this );
204 }
205 
206 template < class TYPE >
207 inline const typename epicsSingleton < TYPE > :: reference
208  epicsSingleton < TYPE > :: getReference () const
209 {
210  epicsSingleton < TYPE > * pConstCastAway =
211  const_cast < epicsSingleton < TYPE > * > ( this );
212  return pConstCastAway->getReference ();
213 }
214 
215 #endif // epicsSingleton_h
216 
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:71
An EPICS-specific replacement for ANSI C&#39;s assert.