Go to the documentation of this file.00001
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
00040
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);
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
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
00242
00243
00244