1 |
#ifndef ERMYTH_PHOENIX_H |
2 |
#define ERMYTH_PHOENIX_H |
3 |
|
4 |
#include <stdlib.h> // atexit() |
5 |
|
6 |
|
7 |
namespace impl |
8 |
{ |
9 |
struct no_op_phoenix_initialiser |
10 |
{ |
11 |
template<typename T> |
12 |
void operator () (T &) |
13 |
{ |
14 |
return; |
15 |
} |
16 |
}; |
17 |
|
18 |
template<typename BaseType, typename ContextType = BaseType, typename initialiserType = no_op_phoenix_initialiser> |
19 |
struct phoenix : public BaseType |
20 |
{ |
21 |
typedef ContextType context_type; |
22 |
typedef BaseType base_type; |
23 |
typedef initialiserType initialiser_type; |
24 |
|
25 |
static base_type &instance () |
26 |
{ |
27 |
static this_type meyers; |
28 |
static bool donethat = false; |
29 |
|
30 |
if (this_type::m_destroyed) |
31 |
{ |
32 |
// phoenix_CERR << "Phoenixing!" << std::endl; |
33 |
donethat = false; |
34 |
new (&meyers) this_type; |
35 |
atexit (this_type::do_atexit); |
36 |
} |
37 |
|
38 |
if (!donethat) |
39 |
{ |
40 |
// phoenix_CERR << "initialising instance" << std::endl; |
41 |
donethat = true; |
42 |
initialiser_type () (meyers); |
43 |
} |
44 |
|
45 |
// phoenix_CERR << "instance() == " <<std::hex<<&meyers<<std::endl; |
46 |
return meyers; |
47 |
} |
48 |
|
49 |
private: |
50 |
typedef phoenix<base_type,context_type,initialiser_type> this_type; |
51 |
|
52 |
static bool m_destroyed; |
53 |
|
54 |
phoenix () |
55 |
{ |
56 |
// phoenix_CERR << "phoenix() @" << std::hex<< this << std::endl; |
57 |
m_destroyed = false; |
58 |
} |
59 |
|
60 |
virtual ~phoenix () throw () |
61 |
{ |
62 |
// phoenix_CERR << "~phoenix() @" << std::hex<< this << std::endl; |
63 |
m_destroyed = true; |
64 |
} |
65 |
|
66 |
// Destroys the shared object via a manual call to it's dtor. |
67 |
static void do_atexit() |
68 |
{ |
69 |
if (m_destroyed) |
70 |
return; |
71 |
// phoenix_CERR << "::do_atexit() @ " << std::hex << &instance() << std::endl; |
72 |
static_cast<this_type &> (instance ()).~phoenix (); // will eventually trigger the BaseType dtor |
73 |
} |
74 |
}; |
75 |
|
76 |
template<typename T, typename C, typename I> |
77 |
bool phoenix<T, C, I>::m_destroyed = false; |
78 |
} // namespace |
79 |
|
80 |
#endif // ERMYTH_PHOENIX_H |