Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

TopNMultimap.h

Go to the documentation of this file.
00001 #ifndef TOPNMULTIMAP_H 00002 #define TOPNMULTIMAP_H 00003 00004 #include <exception> 00005 #include <map> 00006 #include <algorithm> 00007 #include <iterator> 00008 #include <Exceptions.h> 00009 #include <maputil.h> 00010 00011 using namespace std; 00012 00013 // Provides a pair of multimaps that divide objects according to 00014 // whether or not an object meets the top-Nth ranking (where N is 00015 // set a constuction time of this container). 00016 // 00017 // An object A is closer to the "top" of the ranking than another 00018 // object B if A > B. 00019 // 00020 // If two objects have an equivalent priority ( (!(A<B)) && (!(B<A)) ), and 00021 // exactly one of A or B can fit into the top N group, then the first of those 00022 // objects added to this container will be in the top N group. That will remain 00023 // true until something causes that object to be ejected from the top N: Either 00024 // (1) an object with higher priority is inserted into this container, or 00025 // (2) the object in question is erased from this container. 00026 00027 // *** FUTURE IMPROVEMENT POSSIBILITIES *** 00028 // This uses a 00029 00030 template<typename TKey, typename TValue> 00031 class TopNMultimap 00032 { 00033 public: 00034 // n must be >= 0. 00035 TopNMultimap(unsigned int n) 00036 throw (std::exception); 00037 00038 // Adds an object with the specified key and value into the apprioriate 00039 // multimap. Will push some other object from the Top multimap to the Bottom 00040 // multimap if apprioate. 00041 // 00042 // If there's already an object in the map with the specified key, it's 00043 // overwritten with the new value. 00044 void insert(const pair<TKey, TValue> & p) 00045 throw (std::exception); 00046 00047 // Removes all objects with the specified (key, value) pair from this 00048 // container. This will move some object's from the Bottom multimap 00049 // into the top multimap if apprioriate. 00050 void erase(const TKey & p) 00051 throw (std::exception); 00052 00053 // If the specified key is in this container, then... 00054 // 'd' is set to that key's dependent data, and 00055 // 'inTop' is set to 'true' if the key is in the top group and 00056 // 'false' if it's in the bottom group, and 00057 // the method returns 'true'. 00058 // 00059 // If the specified key is not in this container, then this method returns 00060 // false. 00061 bool findByKey(const TKey & k, TValue & d, bool & inTop) const 00062 throw (std::exception); 00063 00064 // Gives a reference to the multimap container that contains the top N 00065 // objects. This is a reference to the TopNMultimap's live container, 00066 // so the reference's data is never stale. 00067 const multimap<TValue, TKey> & getTopMultimap() const 00068 throw (std::exception); 00069 00070 // Gives a reference to the multimap container that contains the objects that 00071 // aren't in this container but aren't in the top N ranking. This is a 00072 // reference to the TopNMultimap's live container, so the reference's data is 00073 // never stale. 00074 const multimap<TValue, TKey> & getBottomMultimap() const 00075 throw (std::exception); 00076 00077 private: 00078 unsigned int _n; 00079 00080 struct IndexContent 00081 { 00082 IndexContent(const TValue & v, char whichPool) 00083 : _v(v), 00084 _whichPool(whichPool) 00085 {} 00086 00087 // The TValue data that the user supplied to go along with the key. 00088 TValue _v; 00089 00090 // Either 't' (the object is stored in _topObjects) or 'b' (the object is 00091 // stored in _bottomObjects). 00092 char _whichPool; 00093 }; 00094 00095 // This information is indexed by key to enable fast lookups. 00096 // The char value is 't' or 'b', indicating which pool the object's data 00097 // can be found in. 00098 map<TKey, IndexContent> _index; 00099 00100 // These multimaps are used to retain sorting on the objects so that we can 00101 // quickly calculate whether or not an object is in the top(n) and also so 00102 // that our users can get the sorted data for their own uses... 00103 multimap<TValue, TKey> _topObjects; // Those objects in the top N 00104 multimap<TValue, TKey> _bottomObjects; // Those objects not in the top N 00105 00106 // Ensures the specified key isn't anywhere in this data structure. 00107 // If it had to be removed from _topObjects, this returns 't'. 00108 // If it had to be removed from _bottomObjects, this returns 'b'. 00109 // If it wasn't in this data structure, this returns 'a' (absent). 00110 char ensureKeyDeleted(const TKey & k) 00111 throw (std::exception); 00112 00113 // Deletes the specified key from the specified pool ('b' or 't'). The 00114 // specified pool must contain an entry with the specified key. 00115 // 00116 // This also removes the key's entry from _index. 00117 void deleteKeyFromPool(const TKey & k, char whichPool) 00118 throw (std::exception); 00119 00120 // Deletes the specified entry into the specified pool ('b' or 't'). The 00121 // specified pool must not contain an entry with the specified key. 00122 // 00123 // This also add the key's entry into _index. 00124 void insertKeyIntoPool(const TKey & k, const TValue & v, char whichPool) 00125 throw (std::exception); 00126 00127 // Moves the specified key and its data from the oldPool to the newPool. 00128 // The specified key must exist in the oldPool when this is called. 00129 // 00130 // This makes the appropriate changes to _index, _bottomPool, and _topPool. 00131 // 00132 // The pools are desigated 't' (top) and 'b' (bottom). 00133 void migrateKey(const TKey & k, char oldPool, char newPool) 00134 throw (std::exception); 00135 }; 00136 00137 //=============================================================================== 00138 00139 template<typename TKey, typename TValue> 00140 TopNMultimap<TKey, TValue>::TopNMultimap(unsigned int n) 00141 throw (std::exception) 00142 { 00143 _n = n; 00144 } 00145 00146 //=============================================================================== 00147 00148 template<typename TKey, typename TValue> 00149 void TopNMultimap<TKey, TValue>::insert(const pair<TKey, TValue> & p) 00150 throw (std::exception) 00151 { 00152 const TKey & keyToInsert = p.first; 00153 const TValue & valueToInsert = p.second; 00154 00155 char oldKeyLocation = ensureKeyDeleted(keyToInsert); 00156 00157 size_t topSize = _topObjects.size(); 00158 00159 if (topSize < _n) 00160 { 00161 // We know there's no need to shuffle up an existing datum from 00162 // _bottomObjects to _topObjects, so we can just go ahead and make our 00163 // insertion into _topObjects... 00164 insertKeyIntoPool(keyToInsert, valueToInsert, 't'); 00165 return; 00166 } 00167 00168 if (oldKeyLocation == 't') 00169 { 00170 // p has to compete with a top-ranked element from _bottomObjects to get 00171 // into the vacancy that we created in _topObjects when we called 00172 // ensureKeyDeleted(p)... 00173 00174 typename multimap<TValue, TKey>::reverse_iterator bottomPos = 00175 _bottomObjects.rbegin(); 00176 00177 // Use >=, not >, to minimize the reshuffling in ambiguous cases... 00178 if ((valueToInsert) >= (bottomPos->first)) 00179 { 00180 insertKeyIntoPool(keyToInsert, valueToInsert, 't'); 00181 return; 00182 } 00183 else 00184 { 00185 migrateKey(bottomPos->second, 'b', 't'); 00186 insertKeyIntoPool(keyToInsert, valueToInsert, 'b'); 00187 return; 00188 } 00189 } 00190 00191 // _topObjects hasn't been perturbed, and is full. We need to have p compete 00192 // with a lowest-ranked datum in _topObjects to see who gets to occupy that 00193 // data structure. The lower goes to _bottomObjects... 00194 typename multimap<TValue, TKey>::iterator topPos = _topObjects.begin(); 00195 00196 // Use >, not >=, to minimize the reshuffling in ambiguous cases... 00197 if (valueToInsert > topPos->first) 00198 { 00199 migrateKey(topPos->second, 't', 'b'); 00200 insertKeyIntoPool(keyToInsert, valueToInsert, 't'); 00201 return; 00202 } 00203 else 00204 { 00205 insertKeyIntoPool(keyToInsert, valueToInsert, 'b'); 00206 return; 00207 } 00208 } 00209 00210 //=============================================================================== 00211 00212 template<typename TKey, typename TValue> 00213 void TopNMultimap<TKey, TValue>::erase(const TKey & p) 00214 throw (std::exception) 00215 { 00216 char oldKeyLocation = ensureKeyDeleted(p); 00217 00218 if ((oldKeyLocation != 't') || (_bottomObjects.size() == 0)) 00219 { 00220 return; 00221 } 00222 00223 // We need to migrate a highest-ranked object from _bottomPool to _topPool to 00224 // fill the vacancy we just made... 00225 typename multimap<TValue, TKey>::iterator pos = _bottomObjects.end(); 00226 --pos; 00227 migrateKey(pos->second, 'b', 't'); 00228 } 00229 00230 //=============================================================================== 00231 00232 template<typename TKey, typename TValue> 00233 bool TopNMultimap<TKey, TValue>::findByKey(const TKey & k, 00234 TValue & d, 00235 bool & inTop) const 00236 throw (std::exception) 00237 { 00238 typename map<TKey, IndexContent>::const_iterator posIndex = _index.find(k); 00239 00240 if (posIndex == _index.end()) 00241 { 00242 return false; 00243 } 00244 00245 d = posIndex->second._v; 00246 inTop = (posIndex->second._whichPool == 't'); 00247 return true; 00248 } 00249 00250 //=============================================================================== 00251 00252 template<typename TKey, typename TValue> 00253 const multimap<TValue, TKey> & TopNMultimap<TKey, TValue>::getTopMultimap() const 00254 throw (std::exception) 00255 { 00256 return _topObjects; 00257 } 00258 00259 //=============================================================================== 00260 00261 template<typename TKey, typename TValue> 00262 const multimap<TValue, TKey> & TopNMultimap<TKey, TValue>::getBottomMultimap() const 00263 throw (std::exception) 00264 { 00265 return _bottomObjects; 00266 } 00267 00268 //=============================================================================== 00269 00270 template<typename TKey, typename TValue> 00271 char TopNMultimap<TKey, TValue>::ensureKeyDeleted(const TKey & k) 00272 throw (std::exception) 00273 { 00274 typename map<TKey, IndexContent>::iterator posIndex = _index.find(k); 00275 00276 if (posIndex == _index.end()) 00277 { 00278 return 'a'; 00279 } 00280 00281 char whichPool = posIndex->second._whichPool; 00282 deleteKeyFromPool(k, whichPool); 00283 return whichPool; 00284 } 00285 00286 //=============================================================================== 00287 00288 template<typename TKey, typename TValue> 00289 void TopNMultimap<TKey, TValue>::deleteKeyFromPool(const TKey & k, char whichPool) 00290 throw (std::exception) 00291 { 00292 // Discover its dependent value, so we can constrain our search through the 00293 // multimap when doing our delete... 00294 typename map<TKey, IndexContent>::iterator posIndex = _index.find(k); 00295 if (posIndex == _index.end()) 00296 { 00297 Throw(AuroraException, "The specified key wasn't found in _index"); 00298 } 00299 00300 const TValue & v = posIndex->second._v; 00301 00302 // Note that in the calls to make_pair(...) below, what our users think of as 00303 // the 'key' and 'data' are swapped. This is because we're about to work on 00304 // _topObjects or _bottomObjects, which have also swapped the users' notions of 00305 // key/data... 00306 00307 int numDeleted = 777; 00308 00309 if (whichPool == 't') 00310 { 00311 numDeleted = multimapEraseExact(_topObjects, make_pair(v, k)); 00312 } 00313 else if (whichPool == 'b') 00314 { 00315 numDeleted = multimapEraseExact(_bottomObjects, make_pair(v, k)); 00316 } 00317 else 00318 { 00319 Throw(AuroraException, "Invalid value supplied for 'whichPool'"); 00320 } 00321 00322 if (numDeleted != 1) 00323 { 00324 Throw(AuroraException, "An invalid number of entries was deleted."); 00325 } 00326 00327 _index.erase(posIndex); 00328 } 00329 00330 //=============================================================================== 00331 00332 template<typename TKey, typename TValue> 00333 void TopNMultimap<TKey, TValue>::insertKeyIntoPool(const TKey & k, const TValue & v, char whichPool) 00334 throw (std::exception) 00335 { 00336 // Note that in the calls to make_pair(...) below, what our users think of as 00337 // the 'key' and 'data' are swapped. This is because we're about to work on 00338 // _topObjects or _bottomObjects, which have also swapped the users' notions of 00339 // key/data... 00340 00341 if (whichPool == 't') 00342 { 00343 _index.insert(make_pair(k, IndexContent(v, 't'))); 00344 _topObjects.insert(make_pair(v, k)); 00345 } 00346 else if (whichPool = 'b') 00347 { 00348 _index.insert(make_pair(k, IndexContent(v, 'b'))); 00349 _bottomObjects.insert(make_pair(v, k)); 00350 } 00351 else 00352 { 00353 Throw(AuroraException, "Invalid value supplied for 'whichPool'"); 00354 } 00355 } 00356 00357 //=============================================================================== 00358 00359 template<typename TKey, typename TValue> 00360 void TopNMultimap<TKey, TValue>::migrateKey(const TKey & k, 00361 char oldPool, 00362 char newPool) 00363 throw (std::exception) 00364 { 00365 // Find some stuff out... 00366 typename map<TKey, IndexContent>::iterator posIndex = _index.find(k); 00367 if (posIndex == _index.end()) 00368 { 00369 Throw(AuroraException, "The specified key wasn't found in _index"); 00370 } 00371 00372 const TValue & v = posIndex->second._v; 00373 00374 // Move the pair to the correct multimap... 00375 pair<TValue, TKey> mmPair(v, k); 00376 00377 if ((oldPool == 'b') && (newPool = 't')) 00378 { 00379 multimapEraseExact(_bottomObjects, mmPair); 00380 _topObjects.insert(mmPair); 00381 } 00382 else if ((oldPool == 't') && (newPool = 'b')) 00383 { 00384 multimapEraseExact(_topObjects, mmPair); 00385 _bottomObjects.insert(mmPair); 00386 } 00387 else 00388 { 00389 Throw(AuroraException, "Invalid pair of values supplied " 00390 "for 'oldPool' and 'newPool'"); 00391 } 00392 00393 // Update the index... 00394 posIndex->second._whichPool = newPool; 00395 } 00396 00397 #endif 00398 00399

Generated on Fri Nov 12 15:15:22 2004 for Borealis by doxygen 1.3.8