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& key)
00098   {
00099 #ifdef USE_TBB_HASH
00100     return 0;
00101 #else
00102     unsigned long val=key.signature();
00103     return (val>>24)%DIVSIZE;
00104 #endif
00105   }
00106 public:
00107   Record *find(const HashKey& key)
00108   {
00109     int i=keyToIndex(key);
00110 #if (defined OSL_SMP) && (! defined USE_TBB_HASH)
00111     SCOPED_LOCK(lk,mutex[i]);
00112 #endif
00113     return findInLock(key,i);
00114   }
00115     
00116   Record *allocate(const HashKey& key)
00117   {
00118     const int i=keyToIndex(key);
00119 #if (defined OSL_SMP) && (! defined USE_TBB_HASH)
00120     SCOPED_LOCK(lk,mutex[i]);
00121 #endif
00122     const size_t current_size = tables[i].size();
00123     if (current_size < capacity/DIVSIZE)
00124     {
00125 #ifdef USE_TBB_HASH
00126       accessor it;
00127       tables[i].insert(it, key);
00128       Record *record = &it->second;
00129 #else
00130       Record *record = &tables[i].operator[](key);
00131 #endif
00132 #ifndef OSL_USE_RACE_DETECTOR
00133       if (current_size == tables[i].size())
00134         ++num_cache_hit;
00135 #endif
00136       return record;
00137     }
00138     // サイズを増やさないように探す
00139     Record *result = findInLock(key,i);
00140     if ((result == 0) && capacity)
00141     {
00142 #ifdef OSL_SMP
00143       if (capacity > 10000)
00144         std::cerr << "table full " << size() << " " << capacity << "\n";
00145       // SMP環境では全てのthreadに投げる必要がある
00146       ++num_record_after_full;
00147       throw TableFull();
00148 #else
00149       if (num_record_after_full++ == 0) 
00150         throw TableFull();
00151 #endif
00152     }
00153     return result;
00154   }
00155 };
00156 
00157   
00158 template <typename Record>
00159 osl::container::GeneralSimpleHashTable<Record>::
00160 GeneralSimpleHashTable(size_t capacity) 
00161   : table(new Table(capacity))
00162 {
00163 }
00164   
00165 template <typename Record>
00166 osl::container::GeneralSimpleHashTable<Record>::
00167 ~GeneralSimpleHashTable() {
00168 }
00169 
00170 template <typename Record>
00171 void osl::container::GeneralSimpleHashTable<Record>::
00172 clear()
00173 {
00174   table->clear();
00175 }
00176 
00177 template <typename Record>
00178 Record * 
00179 osl::container::GeneralSimpleHashTable<Record>::
00180 allocate(const HashKey& key)
00181 {
00182   return table->allocate(key);
00183 }
00184 
00185 template <typename Record>
00186 Record * 
00187 osl::container::GeneralSimpleHashTable<Record>::
00188 find(const HashKey& key)
00189 {
00190   return table->find(key);
00191 }
00192 
00193 template <typename Record>
00194 const Record * 
00195 osl::container::GeneralSimpleHashTable<Record>::
00196 find(const HashKey& key) const
00197 {
00198   return table->find(key);
00199 }
00200 
00201 template <typename Record>
00202 size_t osl::container::GeneralSimpleHashTable<Record>::
00203 size() const
00204 {
00205   return table->size();
00206 }
00207 
00208 template <typename Record>
00209 size_t osl::container::GeneralSimpleHashTable<Record>::
00210 capacity() const
00211 {
00212   return table->capacity;
00213 }
00214 
00215 template <typename Record>
00216 int osl::container::GeneralSimpleHashTable<Record>::
00217 numCacheHit() const
00218 {
00219   return table->num_cache_hit;
00220 }
00221 
00222 template <typename Record>
00223 int osl::container::GeneralSimpleHashTable<Record>::
00224 numRecordAfterFull() const
00225 {
00226   return table->num_record_after_full;
00227 }
00228 
00229 template <typename Record>
00230 int osl::container::GeneralSimpleHashTable<Record>::
00231 divSize() const
00232 {
00233   return Table::DIVSIZE;
00234 }
00235 
00236 /* ------------------------------------------------------------------------- */
00237 // ;;; Local Variables:
00238 // ;;; mode:c++
00239 // ;;; c-basic-offset:2
00240 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines