00001 #ifndef toast_singleton_hpp_INCLUDED
00002 #define toast_singleton_hpp_INCLUDED
00003
00004 #include <sstream>
00005 #include <boost/thread/mutex.hpp>
00006 #include <boost/thread/tss.hpp>
00007 #include <boost/optional.hpp>
00008 #include <boost/none.hpp>
00009 #include <boost/mpl/bool.hpp>
00010 #include <toast/assert.hpp>
00011 #include <toast/typeinfo.hpp>
00012 #include <toast/typed_factory.hpp>
00013 #include <toast/async/lockable.hpp>
00014
00015 #include <boost/utility/enable_if.hpp>
00016 #include <boost/type_traits/is_same.hpp>
00017
00018 #include <toast/static_init_protected.hpp>
00019
00027 namespace toast {
00028
00029 namespace detail {
00030
00031 template <typename T>
00032 std::string no_factory()
00033 {
00034 std::ostringstream os;
00035 os << "Attempt to get factory for " << type_id<T>().name() <<
00036 " when no factory has been set.";
00037 return os.str();
00038 }
00039
00040 template <typename T>
00041 std::string factory_already_exists()
00042 {
00043 std::ostringstream os;
00044 os << "Attempt to set factory for " << type_id<T>().name() <<
00045 " when factory already exists.";
00046 return os.str();
00047 }
00048
00049 template <typename T, typename U>
00050 class holder;
00051
00052 template <typename T>
00053 class holder<T, T>
00054 {
00055 T data_;
00056 public:
00057 T &get() { return data_; }
00058 void apply(typed_factory<T> const &) {}
00059 bool exists() { return true; }
00060 };
00061
00062 template <typename T, typename U>
00063 class sync_helper
00064 {
00065 boost::thread_specific_ptr<int> sync_check_;
00066 boost::mutex mutex_;
00067 U data_;
00068 void apply(typed_factory<T> const &factory, boost::optional<T> &data)
00069 {
00070 data_ = factory;
00071 }
00072 void apply(typed_factory<T> const &factory, T*)
00073 {
00074 data_ = factory.create();
00075 }
00076 static void noop(int *) {}
00077 void init(boost::optional<T> const &) {}
00078 void init(T*&t) { t = 0; }
00079 public:
00080 sync_helper() : sync_check_(&sync_helper::noop) { init(data_); }
00081 T &get() { return *data_; }
00082 void apply(typed_factory<T> const &factory)
00083 {
00084 boost::mutex::scoped_lock lock(mutex_);
00085 if(!data_)
00086 apply(factory, data_);
00087 sync_check_.reset(reinterpret_cast<int*>(1));
00088 }
00089 bool exists() { return sync_check_.get(); }
00090 };
00091
00092 template <typename T>
00093 class holder<T, boost::optional<T> >
00094 : public sync_helper<T, boost::optional<T> >
00095 {};
00096
00097 template <typename T>
00098 class holder<T, T*> : public sync_helper<T, T*>
00099 {};
00100
00101 template <typename T>
00102 class holder<T, boost::thread_specific_ptr<T> >
00103 {
00104 boost::thread_specific_ptr<T> data_;
00105 public:
00106 T &get() { return *data_; }
00107 bool exists() { return data_.get(); }
00108 void apply(typed_factory<T> const &factory)
00109 {
00110 data_.reset(factory.create());
00111 }
00112 };
00113
00114 }
00115
00129 template <typename T>
00130 struct default_factory
00131 {
00132 static typed_factory<T> get() { return typed_factory<T>(); }
00133 };
00134
00145 template <typename T>
00146 class global_factory
00147 {
00148 typedef async::lockable<boost::optional<typed_factory<T> > > factory_type;
00149 typedef detail::holder<factory_type, factory_type> holder_t;
00150 TOAST_STATIC_INIT_PROTECTED(holder_t, holder_);
00151 public:
00152 static void set(typed_factory<T> const &f)
00153 {
00154 async::locked<boost::optional<typed_factory<T> > > factory(holder_::get().get());
00155 TOAST_ASSERT_MESSAGE(!*factory,
00156 detail::factory_already_exists<T>().c_str());
00157 *factory = f;
00158 }
00159
00160 static typed_factory<T> get()
00161 {
00162 async::locked<boost::optional<typed_factory<T> > > factory(holder_::get().get());
00163 TOAST_ASSERT_MESSAGE( *factory, detail::no_factory<T>().c_str() );
00164 return **factory;
00165 }
00166 };
00167
00175 template <typename T>
00176 class thread_specific_factory
00177 {
00178 typedef boost::thread_specific_ptr<typed_factory<T> > factory_type;
00179 typedef detail::holder<factory_type, factory_type> holder_t;
00180 TOAST_STATIC_INIT_PROTECTED(holder_t, holder_);
00181 public:
00182 static void set( typed_factory<T> const &f )
00183 {
00184 TOAST_ASSERT_MESSAGE(!holder_::get().get().get(),
00185 detail::factory_already_exists<T>().c_str());
00186 holder_::get().get().reset( new typed_factory<T>(f) );
00187 }
00188
00189 static typed_factory<T> get()
00190 {
00191 TOAST_ASSERT_MESSAGE( holder_::get().get().get(),
00192 detail::no_factory<T>().c_str() );
00193 return *holder_::get().get();
00194 }
00195 };
00196
00204 template <typename T,
00205 typename HolderType = boost::optional<T>,
00206 typename FactoryType = toast::default_factory<T>,
00207 typename Enable = void>
00208 class singleton_helper
00209 {
00210 typedef singleton_helper<T, HolderType, FactoryType, Enable> this_t;
00211 typedef detail::holder<T, HolderType> real_holder_t;
00212 TOAST_STATIC_INIT_PROTECTED(real_holder_t, holder_);
00213
00214 public:
00215 typedef T type;
00216
00217 static void force_init()
00218 {
00219 holder_::get();
00220 }
00221
00225 static T & instance()
00226 {
00227 if(!holder_::get().exists()) {
00228 holder_::get().apply(FactoryType::get());
00229 }
00230
00231 return holder_::get().get();
00232 }
00233
00237 static void set_factory( toast::typed_factory<T> const &f )
00238 {
00239 FactoryType::set(f);
00240 }
00241 };
00242
00245 template<typename T>
00246 class singleton_helper< T, boost::optional<T>, thread_specific_factory<T> >
00247 {
00248 public:
00249
00250
00251
00252
00253
00254
00255 static void initialize_holder()
00256 {
00257 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00258 }
00259
00260 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00261 };
00262
00263 template<typename T>
00264 class singleton_helper< T, T*, thread_specific_factory<T> >
00265 {
00266 public:
00267
00268
00269
00270
00271
00272
00273 static void initialize_holder()
00274 {
00275 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00276 }
00277
00278 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00279 };
00280
00281 template<typename T, typename U>
00282 class singleton_helper< T, T, U,
00283 typename boost::template disable_if< boost::is_same< U, default_factory<T> > >::type >
00284 {
00285 public:
00286
00287
00288
00289
00290
00291 static void initialize_holder()
00292 {
00293 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00294 }
00295
00296 BOOST_STATIC_ASSERT(sizeof(T) == 0);
00297 };
00298
00299 }
00300
00301 #endif
00302