libmoost
/home/mhx/git/github/libmoost/include/moost/container/resource_stack.hpp
Go to the documentation of this file.
00001 /* vim:set ts=2 sw=2 sts=2 et: */
00028 #ifndef MOOST_CONTAINER_RESOURCE_STACK_HPP__
00029 #define MOOST_CONTAINER_RESOURCE_STACK_HPP__
00030 
00031 #include <exception>
00032 #include <stack>
00033 #include <string>
00034 #include <boost/thread/mutex.hpp>
00035 #include <boost/thread/condition.hpp>
00036 #include <boost/shared_ptr.hpp>
00037 #include "../thread/xtime_util.hpp"
00038 #include "../compiler/attributes/deprecated.hpp"
00039 
00040 namespace moost { namespace container {
00041 
00042 class no_resource_available : public std::runtime_error
00043 {
00044 public:
00045    no_resource_available(const std::string resource_name = "") throw()
00046      : std::runtime_error("no resource available for " + resource_name) {}
00047 };
00048 
00052 template<typename T>
00053 class resource_stack
00054 {
00055 private:
00056 
00057   std::stack< boost::shared_ptr<T> > m_resources;
00058   boost::mutex                       m_mutex;
00059   boost::condition                   m_cond;
00060   size_t                             m_total_size;
00061   std::string                        m_resource_name;
00062 
00063 public:
00064 
00065    typedef T resource_type;
00066 
00067 public:
00068 
00070   class scoped_resource
00071   {
00072   private:
00073     boost::shared_ptr<T> m_resource;
00074     resource_stack &     m_resource_stack;
00075   public:
00076     scoped_resource(resource_stack & resource_stack_, bool wait_on_empty = true);
00077     scoped_resource(resource_stack & resource_stack_, int timeout_ms, bool wait_on_empty = true);
00078     ~scoped_resource();
00079     T & operator* ();
00080     T * operator->();
00081   };
00082 
00084   resource_stack();
00085   resource_stack(const std::string& resource_name);
00086 
00088   void set_resource_name(const std::string& resource_name)
00089   { m_resource_name = resource_name; }
00090 
00093   deprecated__ void add_resource(T * presource);
00094 
00095   void add_resource(boost::shared_ptr<T> spresource);
00096 
00099   size_t size();
00100 
00102   size_t total_size();
00103 };
00104 
00105 // implementation:
00106 
00107 template<typename T>
00108 resource_stack<T>::resource_stack()
00109    : m_total_size(0)
00110    , m_resource_name(
00111 #if (defined(__GNUC__) && !defined(__GXX_RTTI))
00112         "undef"
00113 #else
00114         typeid(T).name() // using RTTI
00115 #endif
00116      )
00117 {
00118 }
00119 
00120 template<typename T>
00121 resource_stack<T>::resource_stack(const std::string& resource_name)
00122    : m_total_size(0)
00123    , m_resource_name(resource_name)
00124 {
00125 }
00126 
00127 // NOTE: this is really dangerous - what if T* wasn't created on the heap? For this reason this method is now
00128 //  deprecated. Please use void add_resource(boost::shared_ptr<T> spresource) instead.
00129 template<typename T>
00130 void resource_stack<T>::add_resource(T * presource)
00131 {
00132   boost::shared_ptr<T> spresource(presource);
00133   boost::mutex::scoped_lock lock(m_mutex);
00134   m_resources.push(spresource);
00135   ++m_total_size;
00136   m_cond.notify_one();
00137 }
00138 
00139 template<typename T>
00140 void resource_stack<T>::add_resource(boost::shared_ptr<T> spresource)
00141 {
00142    boost::mutex::scoped_lock lock(m_mutex);
00143    m_resources.push(spresource);
00144    ++m_total_size;
00145    m_cond.notify_one();
00146 }
00147 
00148 template<typename T>
00149 size_t resource_stack<T>::size()
00150 {
00151   boost::mutex::scoped_lock lock(m_mutex);
00152   return m_resources.size();
00153 }
00154 
00155 template<typename T>
00156 size_t resource_stack<T>::total_size()
00157 {
00158   boost::mutex::scoped_lock lock(m_mutex);
00159   return m_total_size;
00160 }
00161 
00162 // scoped_resource:
00163 
00164 template<typename T>
00165 resource_stack<T>::scoped_resource::scoped_resource(resource_stack<T> & resource_stack_, bool wait_on_empty)
00166 : m_resource_stack(resource_stack_)
00167 {
00168   boost::mutex::scoped_lock lock(m_resource_stack.m_mutex);
00169   if ( !wait_on_empty && m_resource_stack.m_resources.empty() )
00170      throw no_resource_available(m_resource_stack.m_resource_name);
00171 
00172   while (m_resource_stack.m_resources.empty())
00173     m_resource_stack.m_cond.wait(lock);
00174   m_resource = m_resource_stack.m_resources.top();
00175   m_resource_stack.m_resources.pop();
00176 }
00177 
00178 template<typename T>
00179 resource_stack<T>::scoped_resource::scoped_resource(resource_stack<T> & resource_stack_, int timeout_ms, bool wait_on_empty)
00180 : m_resource_stack(resource_stack_)
00181 {
00182   boost::mutex::scoped_lock lock(m_resource_stack.m_mutex);
00183   if ( !wait_on_empty && m_resource_stack.m_resources.empty() )
00184      throw no_resource_available(m_resource_stack.m_resource_name);
00185 
00186   while (m_resource_stack.m_resources.empty())
00187   {
00188     boost::xtime deadline =
00189        moost::thread::xtime_util::add_ms(moost::thread::xtime_util::now(), timeout_ms);
00190     if (!m_resource_stack.m_cond.timed_wait(lock, deadline))
00191       throw no_resource_available(m_resource_stack.m_resource_name);
00192   }
00193   m_resource = m_resource_stack.m_resources.top();
00194   m_resource_stack.m_resources.pop();
00195 }
00196 
00197 template<typename T>
00198 resource_stack<T>::scoped_resource::~scoped_resource()
00199 {
00200   boost::mutex::scoped_lock lock(m_resource_stack.m_mutex);
00201   m_resource_stack.m_resources.push(m_resource);
00202   m_resource_stack.m_cond.notify_one();
00203 }
00204 
00205 template<typename T>
00206 T & resource_stack<T>::scoped_resource::operator* ()
00207 {
00208   return *m_resource;
00209 }
00210 
00211 template<typename T>
00212 T * resource_stack<T>::scoped_resource::operator-> ()
00213 {
00214   return m_resource.get();
00215 }
00216 
00217 }} // moost::container
00218 
00219 #endif // MOOST_CONTAINER_RESOURCE_STACK_HPP__