libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/singleton.hpp
Go to the documentation of this file.
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 */