1 | #ifndef BOOST_SERIALIZATION_SINGLETON_HPP |
2 | #define BOOST_SERIALIZATION_SINGLETON_HPP |
3 | |
4 | /////////1/////////2///////// 3/////////4/////////5/////////6/////////7/////////8 |
5 | // singleton.hpp |
6 | // |
7 | // Copyright David Abrahams 2006. Original version |
8 | // |
9 | // Copyright Robert Ramey 2007. Changes made to permit |
10 | // application throughout the serialization library. |
11 | // |
12 | // Distributed under the Boost |
13 | // Software License, Version 1.0. (See accompanying |
14 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
15 | // |
16 | // The intention here is to define a template which will convert |
17 | // any class into a singleton with the following features: |
18 | // |
19 | // a) initialized before first use. |
20 | // b) thread-safe for const access to the class |
21 | // c) non-locking |
22 | // |
23 | // In order to do this, |
24 | // a) Initialize dynamically when used. |
25 | // b) Require that all singletons be initialized before main |
26 | // is called or any entry point into the shared library is invoked. |
27 | // This guarentees no race condition for initialization. |
28 | // In debug mode, we assert that no non-const functions are called |
29 | // after main is invoked. |
30 | // |
31 | |
32 | // MS compatible compilers support #pragma once |
33 | #if defined(_MSC_VER) |
34 | # pragma once |
35 | #endif |
36 | |
37 | #include <boost/assert.hpp> |
38 | #include <boost/config.hpp> |
39 | #include <boost/noncopyable.hpp> |
40 | #include <boost/serialization/force_include.hpp> |
41 | |
42 | #ifdef BOOST_MSVC |
43 | # pragma warning(push) |
44 | # pragma warning(disable : 4511 4512) |
45 | #endif |
46 | |
47 | namespace boost { |
48 | namespace serialization { |
49 | |
50 | ////////////////////////////////////////////////////////////////////// |
51 | // Provides a dynamically-initialized (singleton) instance of T in a |
52 | // way that avoids LNK1179 on vc6. See http://tinyurl.com/ljdp8 or |
53 | // http://lists.boost.org/Archives/boost/2006/05/105286.php for |
54 | // details. |
55 | // |
56 | |
57 | // singletons created by this code are guarenteed to be unique |
58 | // within the executable or shared library which creates them. |
59 | // This is sufficient and in fact ideal for the serialization library. |
60 | // The singleton is created when the module is loaded and destroyed |
61 | // when the module is unloaded. |
62 | |
63 | // This base class has two functions. |
64 | |
65 | // First it provides a module handle for each singleton indicating |
66 | // the executable or shared library in which it was created. This |
67 | // turns out to be necessary and sufficient to implement the tables |
68 | // used by serialization library. |
69 | |
70 | // Second, it provides a mechanism to detect when a non-const function |
71 | // is called after initialization. |
72 | |
73 | // make a singleton to lock/unlock all singletons for alteration. |
74 | // The intent is that all singletons created/used by this code |
75 | // are to be initialized before main is called. A test program |
76 | // can lock all the singletons when main is entereed. This any |
77 | // attempt to retieve a mutable instances while locked will |
78 | // generate a assertion if compiled for debug. |
79 | |
80 | class BOOST_SYMBOL_VISIBLE singleton_module : |
81 | public boost::noncopyable |
82 | { |
83 | private: |
84 | static bool & get_lock(){ |
85 | static bool lock = false; |
86 | return lock; |
87 | } |
88 | public: |
89 | // static const void * get_module_handle(){ |
90 | // return static_cast<const void *>(get_module_handle); |
91 | // } |
92 | static void lock(){ |
93 | get_lock() = true; |
94 | } |
95 | static void unlock(){ |
96 | get_lock() = false; |
97 | } |
98 | static bool is_locked() { |
99 | return get_lock(); |
100 | } |
101 | }; |
102 | |
103 | namespace detail { |
104 | |
105 | template<class T> |
106 | class singleton_wrapper : public T |
107 | { |
108 | public: |
109 | static bool m_is_destroyed; |
110 | ~singleton_wrapper(){ |
111 | m_is_destroyed = true; |
112 | } |
113 | }; |
114 | |
115 | template<class T> |
116 | bool detail::singleton_wrapper< T >::m_is_destroyed = false; |
117 | |
118 | } // detail |
119 | |
120 | template <class T> |
121 | class singleton : public singleton_module |
122 | { |
123 | private: |
124 | BOOST_DLLEXPORT static T & instance; |
125 | // include this to provoke instantiation at pre-execution time |
126 | static void use(T const *) {} |
127 | BOOST_DLLEXPORT static T & get_instance() { |
128 | static detail::singleton_wrapper< T > t; |
129 | // refer to instance, causing it to be instantiated (and |
130 | // initialized at startup on working compilers) |
131 | BOOST_ASSERT(! detail::singleton_wrapper< T >::m_is_destroyed); |
132 | use(& instance); |
133 | return static_cast<T &>(t); |
134 | } |
135 | public: |
136 | BOOST_DLLEXPORT static T & get_mutable_instance(){ |
137 | BOOST_ASSERT(! is_locked()); |
138 | return get_instance(); |
139 | } |
140 | BOOST_DLLEXPORT static const T & get_const_instance(){ |
141 | return get_instance(); |
142 | } |
143 | BOOST_DLLEXPORT static bool is_destroyed(){ |
144 | return detail::singleton_wrapper< T >::m_is_destroyed; |
145 | } |
146 | }; |
147 | |
148 | template<class T> |
149 | BOOST_DLLEXPORT T & singleton< T >::instance = singleton< T >::get_instance(); |
150 | |
151 | } // namespace serialization |
152 | } // namespace boost |
153 | |
154 | #ifdef BOOST_MSVC |
155 | #pragma warning(pop) |
156 | #endif |
157 | |
158 | #endif // BOOST_SERIALIZATION_SINGLETON_HPP |
159 | |