|
libpsynth 0.2.1
|
00001 /* 00002 * File: singleton.hpp 00003 * Author: Juan Pedro Bolívar Puente <raskolnikov@es.gnu.org> 00004 * Date: 2007 00005 * Time-stamp: <2011-06-13 11:12:20 raskolnikov> 00006 * 00007 * This file implements a policy-based generic singleton. It is a 00008 * simplification (less policy implementations are provided) of 00009 * Loki singleton_holder class. 00010 * 00011 * @todo Add more longetvity policies. The follow-to-death policy 00012 * in the current Loki implementation seems interesting, as 00013 * most singletons actually depend indirectly 00014 * (through psynth::error) on Logger. 00015 */ 00016 00017 /* 00018 * Copyright (C) 2007, 2009 Juan Pedro Bolívar Puente 00019 * 00020 * This program is free software: you can redistribute it and/or modify 00021 * it under the terms of the GNU General Public License as published by 00022 * the Free Software Foundation, either version 3 of the License, or 00023 * (at your option) any later version. 00024 * 00025 * This program is distributed in the hope that it will be useful, 00026 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00027 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00028 * GNU General Public License for more details. 00029 * 00030 * You should have received a copy of the GNU General Public License 00031 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00032 * 00033 */ 00034 00035 #ifndef PSYNTH_SINGLETON_H 00036 #define PSYNTH_SINGLETON_H 00037 00038 #include <new> 00039 00040 #include <psynth/base/exception.hpp> 00041 #include <psynth/base/threads.hpp> 00042 00043 namespace psynth 00044 { 00045 namespace base 00046 { 00047 00048 /* Default parameters forward declaration. */ 00049 template <class T> 00050 class create_with_new; 00051 template <class T> 00052 class lifetime_atexit; 00053 00066 template < 00067 class T, 00068 template <class> class CreationPolicy = create_with_new, 00069 template <class> class LifetimePolicy = lifetime_atexit, 00070 template <class> class ThreadingPolicy = PSYNTH_DEFAULT_NONOBJ_THREADING 00071 > 00072 class singleton_holder : private boost::noncopyable 00073 { 00074 public: 00075 typedef T type; 00076 00081 static T& self (); 00082 00083 private: 00085 singleton_holder () = delete; 00087 ~singleton_holder () {}; 00088 00090 typedef typename ThreadingPolicy<T*>::volatile_type instance_type; 00092 static instance_type m_instance; 00094 static bool m_destroyed; 00095 00097 static void destroy_singleton (); 00098 }; 00099 00104 template <typename T> 00105 struct create_with_new 00106 { 00107 static T* create () 00108 { 00109 return new T; 00110 } 00111 00112 static void destroy (T* var) 00113 { 00114 delete var; 00115 } 00116 }; 00117 00122 template <typename T> 00123 struct create_with_malloc 00124 { 00126 static T* create () 00127 { 00128 T* mem = std::malloc (sizeof (T)); 00129 if (!mem) 00130 return 0; 00131 mem = new (mem) T; 00132 return mem; 00133 } 00134 00136 static void destroy (T* obj) 00137 { 00138 obj->~T (); 00139 std::free (obj); 00140 } 00141 }; 00142 00146 template <typename T> 00147 struct create_with_static 00148 { 00150 static T* create () 00151 { 00152 static T object; /* Should we use Loki's MaxAlign trick? */ 00153 return &object; 00154 } 00155 00157 static void destroy (T* obj) 00158 { 00159 obj->~T (); 00160 } 00161 }; 00162 00169 template<template<class> class Alloc> 00170 struct create_with 00171 { 00175 template <class T> 00176 struct alloc 00177 { 00178 static Alloc<T> allocator; 00179 00181 static T* create() 00182 { 00183 return new (allocator.allocate (1)) T; 00184 } 00185 00187 static void destroy(T* p) 00188 { 00189 p->~T(); 00190 allocator.deallocate (p, 1); 00191 } 00192 }; 00193 }; 00194 00199 typedef void (*destroy_func_t)(); 00200 00205 PSYNTH_DECLARE_ERROR (error, singleton_error); 00206 00214 template <class T> 00215 struct lifetime_atexit 00216 { 00218 static void schedule (T*, destroy_func_t fun) 00219 { 00220 std::atexit (fun); 00221 } 00222 00224 static void on_dead_reference () 00225 { 00226 throw singleton_error (); 00227 } 00228 }; 00229 00238 template <class T> 00239 struct lifetime_static_dtor 00240 { 00242 static void schedule (T*, destroy_func_t fun) 00243 { 00244 static scheduler sched (fun); 00245 } 00246 00248 static void on_dead_reference () 00249 { 00250 throw singleton_error (); 00251 } 00252 00253 private: 00255 struct scheduler 00256 { 00257 scheduler (destroy_func_t fun) 00258 : m_fun (fun) 00259 {} 00260 00261 ~scheduler () 00262 { 00263 m_fun (); 00264 } 00265 00266 destroy_func_t m_fun; 00267 }; 00268 }; 00269 00276 template <class T> 00277 class lifetime_phoenix 00278 { 00279 public: 00281 static void schedule (T*, destroy_func_t pFun) 00282 { 00283 #ifndef PSYNTH_ATEXIT_FIXED 00284 if (!m_destroyed) 00285 #endif 00286 std::atexit(pFun); 00287 } 00288 00290 static void on_dead_reference () 00291 { 00292 #ifndef PSYNTH_ATEXIT_FIXED 00293 m_destroyed = true; 00294 #endif 00295 } 00296 00297 private: 00298 #ifndef PSYNTH_ATEXIT_FIXED 00299 static bool m_destroyed; 00300 #endif 00301 }; 00302 00306 template <class T> 00307 struct lifetime_no_destroy 00308 { 00310 static void schedule (T*, destroy_func_t) 00311 {} 00312 00314 static void on_dead_reference () 00315 { 00316 throw singleton_error (); 00317 } 00318 }; 00319 00320 } /* namespace base */ 00321 } /* namespace psynth */ 00322 00323 #include <psynth/base/singleton.tpp> 00324 00325 #endif /* PSYNTH_SINGLETON_H */
1.7.4