00001 /* 00002 * threadsafe_map.h 00003 * 00004 * Copyright (C) 2007,2009 Thomas A. Vaughan 00005 * All rights reserved. 00006 * 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * * Neither the name of the <organization> nor the 00016 * names of its contributors may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY 00020 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY 00023 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00026 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * 00031 * Basic threadsafe map (wrapper around std::map) 00032 */ 00033 00034 #ifndef WAVEPACKET_THREADSAFE_MAP_H__ 00035 #define WAVEPACKET_THREADSAFE_MAP_H__ 00036 00037 // includes -------------------------------------------------------------------- 00038 #include "common/common.h" 00039 #include "smart_mutex.h" 00040 00041 00042 //////////////////////////////////////////////////////////////////////////////// 00043 /// 00044 /// threadsafe map object 00045 /// 00046 /// \ingroup threadsafe 00047 /// 00048 /// A very simple map object that is safe for multiple threads to use at the 00049 /// same time. There is a single mutex protecting the entire map. 00050 /// 00051 /// You can iterate using getIterator()/getNextElement(). However, that is 00052 /// not guaranteed iteration. Your iterator will be invalidated (and 00053 /// getNextElement() will return false) if another thread has since updated 00054 /// the map. 00055 /// 00056 //////////////////////////////////////////////////////////////////////////////// 00057 template <class K, class T> 00058 class threadsafe_map : protected std::map<K,T> { 00059 private: 00060 // private typedefs ---------------------------------------------------- 00061 typedef std::map<K,T> base_map_t; 00062 typedef typename std::map<K,T>::iterator base_iterator_t; 00063 typedef threadsafe_map<K, T> map_t; 00064 00065 public: 00066 // public typedefs ----------------------------------------------------- 00067 struct iterator_t { 00068 public: 00069 friend class threadsafe_map<K, T>; 00070 private: 00071 base_iterator_t iter; 00072 dword_t rvn; 00073 }; 00074 00075 // threadsafe_map class interface methods ------------------------------ 00076 00077 /// how many elements in the map 00078 int size(void) const throw() { 00079 map_t * pThis = this->getNonConst(); 00080 mlock l(pThis->m_mutex); 00081 return base_map_t::size(); 00082 } 00083 00084 /// insert the given object at the given key value (map, not multimap!) 00085 void insert(IN const K& key, IN const T& t) { 00086 mlock l(m_mutex); 00087 ++m_rvn; 00088 this->operator[](key) = t; 00089 } 00090 00091 /// retrieve value at key--true if there is a value there 00092 bool lookup(IN const K& key, OUT T& t) const throw() { 00093 map_t * pThis = this->getNonConst(); 00094 mlock l(pThis->m_mutex); 00095 base_iterator_t i = pThis->find(key); 00096 if (pThis->end() != i) { 00097 t = i->second; // note: caller gets a copy! 00098 return true; 00099 } 00100 return false; // not found! 00101 } 00102 00103 /// remove (erase) the element at key, if there is one 00104 bool remove(IN const K& key) { 00105 mlock l(m_mutex); 00106 base_iterator_t i = this->find(key); 00107 if (this->end() != i) { 00108 ++m_rvn; 00109 this->erase(i); 00110 return true; 00111 } 00112 return false; 00113 } 00114 00115 /// clear out (erase) the entire map 00116 void clear(void) { 00117 mlock l(m_mutex); 00118 ++m_rvn; 00119 base_map_t::clear(); 00120 } 00121 00122 /// get an iterator (points to the first element in the map) 00123 void getIterator(OUT iterator_t& i) const throw() { 00124 map_t * pThis = this->getNonConst(); 00125 mlock l(pThis->m_mutex); 00126 i.rvn = m_rvn; 00127 i.iter = pThis->begin(); 00128 } 00129 00130 /// get next element in map and increment iterator 00131 bool getNextElement(IO iterator_t& i, OUT K& k, OUT T& t) const { 00132 map_t * pThis = this->getNonConst(); 00133 mlock l(pThis->m_mutex); 00134 if (i.rvn != this->m_rvn) 00135 return false; // iterator is now invalid! 00136 if (pThis->end() == i.iter) 00137 return false; // end of iteration 00138 00139 // iterator is good! 00140 k = i.iter->first; 00141 t = i.iter->second; 00142 ++i.iter; 00143 return true; 00144 } 00145 00146 private: 00147 // private helper methods ---------------------------------------------- 00148 // cast to avoid const-ness. This is because read-only operations need 00149 // to hold the mutex 00150 map_t * getNonConst(void) const throw() { 00151 return (map_t *) this; 00152 } 00153 00154 // private member data ------------------------------------------------- 00155 smart_mutex m_mutex; 00156 dword_t m_rvn; 00157 }; 00158 00159 00160 #endif // WAVEPACKET_THREADSAFE_MAP_H__ 00161