generalSimpleHashTable.tcc
Go to the documentation of this file.
00001 /* generalSimpleHashTable.cc
00002  */
00003 #include "osl/container/generalSimpleHashTable.h"
00004 #include "osl/hash/hashKey.h"
00005 #include "osl/stl/hash_map.h"
00006 #include "osl/config.h"
00007 #ifdef USE_TBB_HASH
00008 #  include <cstring>
00009 #  include <tbb/concurrent_hash_map.h>
00010 #endif
00011 #ifdef OSL_SMP
00012 #  include "osl/misc/lightMutex.h"
00013 #  include <iostream>
00014 #endif
00015 
00016 template <typename Record>
00017 struct osl::container::GeneralSimpleHashTable<Record>::Table 
00018 {
00019 #ifdef USE_TBB_HASH
00020   static const unsigned int DIVSIZE=1;
00021   typedef tbb::concurrent_hash_map<HashKey, Record, TBBHashCompare> table_t;
00022   typedef typename table_t::accessor accessor;
00023 #else
00024   typedef hash_map<HashKey, Record
00025 #  ifdef USE_BOOST_POOL_ALLOCATOR
00026                    , osl::stl::hash<HashKey>
00027                    , std::equal_to<HashKey>
00028                    , osl::stl::fast_pool_allocator<std::pair<const HashKey,Record> >
00029 #  endif
00030                    > table_t;
00031   typedef typename table_t::const_iterator const_iterator;
00032 #  ifdef OSL_SMP
00033   typedef osl::misc::LightMutex Mutex;
00034   static const unsigned int DIVSIZE=16;
00035   CArray<Mutex,DIVSIZE> mutex;
00036 #  else
00037   static const unsigned int DIVSIZE=1;
00038 #  endif
00039   // if you use USE_GPL_POOL_ALLOCATOR, take care of the object size.
00040   // usually 256 is too large.
00041 #  ifdef USE_GPL_POOL_ALLOCATOR
00042   BOOST_STATIC_ASSERT(sizeof(Record) <= 256);
00043 #  endif
00044 #endif
00045   CArray<table_t,DIVSIZE> tables;
00046 
00048   const size_t capacity;
00049   int num_cache_hit, num_record_after_full;
00050 
00051   Table(size_t c) 
00052     : capacity(c), num_cache_hit(0), num_record_after_full(0)
00053   {
00054 #ifndef USE_TBB_HASH
00055     for(size_t i=0;i<DIVSIZE;i++)
00056       tables[i]=table_t(std::min(c, (size_t)3000000) /DIVSIZE); // keep reasonable size for initial capacity
00057 #endif
00058   }
00059   ~Table()
00060   {
00061   }
00062   void clear()
00063   {
00064     for(size_t i=0;i<DIVSIZE;i++){
00065       tables[i].clear();
00066     }
00067     num_cache_hit = 0;
00068     num_record_after_full = 0;
00069   }
00070   size_t size() const
00071   {
00072     size_t ret=0;
00073     for(size_t i=0;i<DIVSIZE;i++)
00074       ret+=tables[i].size();
00075     return ret;
00076   }
00077 private:
00078   Record *findInLock(const HashKey& key,int i)
00079   {
00080 #ifdef USE_TBB_HASH
00081     accessor it;
00082     if(!tables[i].find(it,key)) return 0;
00083 #  ifndef OSL_USE_RACE_DETECTOR
00084     ++num_cache_hit;
00085 #  endif
00086     return &(it->second);
00087 #else
00088     typename table_t::iterator pos = tables[i].find(key);
00089     if (pos == tables[i].end())
00090       return 0;
00091 #  ifndef OSL_USE_RACE_DETECTOR
00092     ++num_cache_hit;
00093 #  endif
00094     return &pos->second;
00095 #endif
00096   }
00097   static int keyToIndex(const HashKey&
00098 #ifndef USE_TBB_HASH
00099                         key
00100 #endif
00101     )
00102   {
00103 #ifdef USE_TBB_HASH
00104     return 0;
00105 #else
00106     unsigned long val=key.signature();
00107     return (val>>24)%DIVSIZE;
00108 #endif
00109   }
00110 public:
00111   Record *find(const HashKey& key)
00112   {
00113     int i=keyToIndex(key);
00114 #if (defined OSL_SMP) && (! defined USE_TBB_HASH)
00115     SCOPED_LOCK(lk,mutex[i]);
00116 #endif
00117     return findInLock(key,i);
00118   }
00119     
00120   Record *allocate(const HashKey& key)
00121   {
00122     const int i=keyToIndex(key);
00123 #if (defined OSL_SMP) && (! defined USE_TBB_HASH)
00124     SCOPED_LOCK(lk,mutex[i]);
00125 #endif
00126     const size_t current_size = tables[i].size();
00127     if (current_size < capacity/DIVSIZE)
00128     {
00129 #ifdef USE_TBB_HASH
00130       accessor it;
00131       tables[i].insert(it, key);
00132       Record *record = &it->second;
00133 #else
00134       Record *record = &tables[i].operator[](key);
00135 #endif
00136 #ifndef OSL_USE_RACE_DETECTOR
00137       if (current_size == tables[i].size())
00138         ++num_cache_hit;
00139 #endif
00140       return record;
00141     }
00142     // サイズを増やさないように探す
00143     Record *result = findInLock(key,i);
00144     if ((result == 0) && capacity)
00145     {
00146 #ifdef OSL_SMP
00147       if (capacity > 10000)
00148         std::cerr << "table full " << size() << " " << capacity << "\n";
00149       // SMP環境では全てのthreadに投げる必要がある
00150       ++num_record_after_full;
00151       throw TableFull();
00152 #else
00153       if (num_record_after_full++ == 0) 
00154         throw TableFull();
00155 #endif
00156     }
00157     return result;
00158   }
00159 };
00160 
00161   
00162 template <typename Record>
00163 osl::container::GeneralSimpleHashTable<Record>::
00164 GeneralSimpleHashTable(size_t capacity) 
00165   : table(new Table(capacity))
00166 {
00167 }
00168   
00169 template <typename Record>
00170 osl::container::GeneralSimpleHashTable<Record>::
00171 ~GeneralSimpleHashTable() {
00172 }
00173 
00174 template <typename Record>
00175 void osl::container::GeneralSimpleHashTable<Record>::
00176 clear()
00177 {
00178   table->clear();
00179 }
00180 
00181 template <typename Record>
00182 Record * 
00183 osl::container::GeneralSimpleHashTable<Record>::
00184 allocate(const HashKey& key)
00185 {
00186   return table->allocate(key);
00187 }
00188 
00189 template <typename Record>
00190 Record * 
00191 osl::container::GeneralSimpleHashTable<Record>::
00192 find(const HashKey& key)
00193 {
00194   return table->find(key);
00195 }
00196 
00197 template <typename Record>
00198 const Record * 
00199 osl::container::GeneralSimpleHashTable<Record>::
00200 find(const HashKey& key) const
00201 {
00202   return table->find(key);
00203 }
00204 
00205 template <typename Record>
00206 size_t osl::container::GeneralSimpleHashTable<Record>::
00207 size() const
00208 {
00209   return table->size();
00210 }
00211 
00212 template <typename Record>
00213 size_t osl::container::GeneralSimpleHashTable<Record>::
00214 capacity() const
00215 {
00216   return table->capacity;
00217 }
00218 
00219 template <typename Record>
00220 int osl::container::GeneralSimpleHashTable<Record>::
00221 numCacheHit() const
00222 {
00223   return table->num_cache_hit;
00224 }
00225 
00226 template <typename Record>
00227 int osl::container::GeneralSimpleHashTable<Record>::
00228 numRecordAfterFull() const
00229 {
00230   return table->num_record_after_full;
00231 }
00232 
00233 template <typename Record>
00234 int osl::container::GeneralSimpleHashTable<Record>::
00235 divSize() const
00236 {
00237   return Table::DIVSIZE;
00238 }
00239 
00240 /* ------------------------------------------------------------------------- */
00241 // ;;; Local Variables:
00242 // ;;; mode:c++
00243 // ;;; c-basic-offset:2
00244 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines