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& 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
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
00238
00239
00240