OpenMW
|
00001 #ifndef OPENMW_MWWORLD_STORE_H 00002 #define OPENMW_MWWORLD_STORE_H 00003 00004 #include <string> 00005 #include <vector> 00006 #include <map> 00007 #include <stdexcept> 00008 00009 #include "recordcmp.hpp" 00010 00011 namespace MWWorld 00012 { 00013 struct StoreBase 00014 { 00015 virtual ~StoreBase() {} 00016 00017 virtual void setUp() {} 00018 virtual void listIdentifier(std::vector<std::string> &list) const {} 00019 00020 virtual size_t getSize() const = 0; 00021 virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; 00022 00023 virtual bool eraseStatic(const std::string &id) {return false;} 00024 virtual void clearDynamic() {} 00025 }; 00026 00027 template <class T> 00028 class SharedIterator 00029 { 00030 typedef typename std::vector<T *>::const_iterator Iter; 00031 00032 Iter mIter; 00033 00034 public: 00035 SharedIterator() {} 00036 00037 SharedIterator(const SharedIterator &orig) 00038 : mIter(orig.mIter) 00039 {} 00040 00041 SharedIterator(const Iter &iter) 00042 : mIter(iter) 00043 {} 00044 00045 SharedIterator &operator++() { 00046 ++mIter; 00047 return *this; 00048 } 00049 00050 SharedIterator operator++(int) { 00051 SharedIterator iter = *this; 00052 ++mIter; 00053 00054 return iter; 00055 } 00056 00057 SharedIterator &operator--() { 00058 --mIter; 00059 return *this; 00060 } 00061 00062 SharedIterator operator--(int) { 00063 SharedIterator iter = *this; 00064 --mIter; 00065 00066 return iter; 00067 } 00068 00069 bool operator==(const SharedIterator &x) const { 00070 return mIter == x.mIter; 00071 } 00072 00073 bool operator!=(const SharedIterator &x) const { 00074 return !(*this == x); 00075 } 00076 00077 const T &operator*() const { 00078 return **mIter; 00079 } 00080 00081 const T *operator->() const { 00082 return &(**mIter); 00083 } 00084 }; 00085 00086 class ESMStore; 00087 00088 template <class T> 00089 class Store : public StoreBase 00090 { 00091 std::map<std::string, T> mStatic; 00092 std::vector<T *> mShared; 00093 std::map<std::string, T> mDynamic; 00094 00095 typedef std::map<std::string, T> Dynamic; 00096 typedef std::map<std::string, T> Static; 00097 00098 class GetRecords { 00099 const std::string mFind; 00100 std::vector<const T*> *mRecords; 00101 00102 public: 00103 GetRecords(const std::string &str, std::vector<const T*> *records) 00104 : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) 00105 { } 00106 00107 void operator()(const T *item) 00108 { 00109 if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) 00110 mRecords->push_back(item); 00111 } 00112 }; 00113 00114 00115 friend class ESMStore; 00116 00117 public: 00118 Store() 00119 {} 00120 00121 Store(const Store<T> &orig) 00122 : mStatic(orig.mData) 00123 {} 00124 00125 typedef SharedIterator<T> iterator; 00126 00127 // setUp needs to be called again after 00128 virtual void clearDynamic() 00129 { 00130 mDynamic.clear(); 00131 mShared.clear(); 00132 } 00133 00134 const T *search(const std::string &id) const { 00135 T item; 00136 item.mId = Misc::StringUtils::lowerCase(id); 00137 00138 typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId); 00139 00140 if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { 00141 return &(it->second); 00142 } 00143 00144 typename Dynamic::const_iterator dit = mDynamic.find(item.mId); 00145 if (dit != mDynamic.end()) { 00146 return &dit->second; 00147 } 00148 00149 return 0; 00150 } 00151 00153 const T *searchRandom(const std::string &id) const 00154 { 00155 std::vector<const T*> results; 00156 std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); 00157 if(!results.empty()) 00158 return results[int(std::rand()/((double)RAND_MAX+1)*results.size())]; 00159 return NULL; 00160 } 00161 00162 const T *find(const std::string &id) const { 00163 const T *ptr = search(id); 00164 if (ptr == 0) { 00165 std::ostringstream msg; 00166 msg << "Object '" << id << "' not found (const)"; 00167 throw std::runtime_error(msg.str()); 00168 } 00169 return ptr; 00170 } 00171 00174 const T *findRandom(const std::string &id) const 00175 { 00176 const T *ptr = searchRandom(id); 00177 if(ptr == 0) 00178 { 00179 std::ostringstream msg; 00180 msg << "Object starting with '"<<id<<"' not found (const)"; 00181 throw std::runtime_error(msg.str()); 00182 } 00183 return ptr; 00184 } 00185 00186 void load(ESM::ESMReader &esm, const std::string &id) { 00187 std::string idLower = Misc::StringUtils::lowerCase(id); 00188 mStatic[idLower] = T(); 00189 mStatic[idLower].mId = idLower; 00190 mStatic[idLower].load(esm); 00191 } 00192 00193 void setUp() { 00194 //std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); 00195 00196 mShared.reserve(mStatic.size()); 00197 typename std::map<std::string, T>::iterator it = mStatic.begin(); 00198 for (; it != mStatic.end(); ++it) { 00199 mShared.push_back(&(it->second)); 00200 } 00201 } 00202 00203 iterator begin() const { 00204 return mShared.begin(); 00205 } 00206 00207 iterator end() const { 00208 return mShared.end(); 00209 } 00210 00211 size_t getSize() const { 00212 return mShared.size(); 00213 } 00214 00215 void listIdentifier(std::vector<std::string> &list) const { 00216 list.reserve(list.size() + getSize()); 00217 typename std::vector<T *>::const_iterator it = mShared.begin(); 00218 for (; it != mShared.end(); ++it) { 00219 list.push_back((*it)->mId); 00220 } 00221 } 00222 00223 T *insert(const T &item) { 00224 std::string id = Misc::StringUtils::lowerCase(item.mId); 00225 std::pair<typename Dynamic::iterator, bool> result = 00226 mDynamic.insert(std::pair<std::string, T>(id, item)); 00227 T *ptr = &result.first->second; 00228 if (result.second) { 00229 mShared.push_back(ptr); 00230 } else { 00231 *ptr = item; 00232 } 00233 return ptr; 00234 } 00235 00236 T *insertStatic(const T &item) { 00237 std::string id = Misc::StringUtils::lowerCase(item.mId); 00238 std::pair<typename Static::iterator, bool> result = 00239 mStatic.insert(std::pair<std::string, T>(id, item)); 00240 T *ptr = &result.first->second; 00241 if (result.second) { 00242 mShared.push_back(ptr); 00243 } else { 00244 *ptr = item; 00245 } 00246 return ptr; 00247 } 00248 00249 00250 bool eraseStatic(const std::string &id) { 00251 T item; 00252 item.mId = Misc::StringUtils::lowerCase(id); 00253 00254 typename std::map<std::string, T>::iterator it = mStatic.find(item.mId); 00255 00256 if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { 00257 // delete from the static part of mShared 00258 typename std::vector<T *>::iterator sharedIter = mShared.begin(); 00259 typename std::vector<T *>::iterator end = sharedIter + mStatic.size(); 00260 00261 while (sharedIter != mShared.end() && sharedIter != end) { 00262 if((*sharedIter)->mId == item.mId) { 00263 mShared.erase(sharedIter); 00264 break; 00265 } 00266 ++sharedIter; 00267 } 00268 mStatic.erase(it); 00269 } 00270 00271 return true; 00272 } 00273 00274 bool erase(const std::string &id) { 00275 std::string key = Misc::StringUtils::lowerCase(id); 00276 typename Dynamic::iterator it = mDynamic.find(key); 00277 if (it == mDynamic.end()) { 00278 return false; 00279 } 00280 mDynamic.erase(it); 00281 00282 // have to reinit the whole shared part 00283 mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); 00284 for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { 00285 mShared.push_back(&it->second); 00286 } 00287 return true; 00288 } 00289 00290 bool erase(const T &item) { 00291 return erase(item.mId); 00292 } 00293 }; 00294 00295 template <> 00296 inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) { 00297 std::string idLower = Misc::StringUtils::lowerCase(id); 00298 00299 std::map<std::string, ESM::Dialogue>::iterator it = mStatic.find(idLower); 00300 if (it == mStatic.end()) { 00301 it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; 00302 it->second.mId = id; // don't smash case here, as this line is printed... I think 00303 } 00304 00305 //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins 00306 it->second.load(esm); 00307 } 00308 00309 template <> 00310 inline void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) { 00311 ESM::Script scpt; 00312 scpt.load(esm); 00313 Misc::StringUtils::toLower(scpt.mId); 00314 mStatic[scpt.mId] = scpt; 00315 } 00316 00317 template <> 00318 inline void Store<ESM::StartScript>::load(ESM::ESMReader &esm, const std::string &id) { 00319 ESM::StartScript s; 00320 s.load(esm); 00321 s.mId = Misc::StringUtils::toLower(s.mScript); 00322 mStatic[s.mId] = s; 00323 } 00324 00325 template <> 00326 class Store<ESM::LandTexture> : public StoreBase 00327 { 00328 // For multiple ESM/ESP files we need one list per file. 00329 typedef std::vector<ESM::LandTexture> LandTextureList; 00330 std::vector<LandTextureList> mStatic; 00331 00332 public: 00333 Store<ESM::LandTexture>() { 00334 mStatic.push_back(LandTextureList()); 00335 LandTextureList <exl = mStatic[0]; 00336 // More than enough to hold Morrowind.esm. Extra lists for plugins will we 00337 // added on-the-fly in a different method. 00338 ltexl.reserve(128); 00339 } 00340 00341 typedef std::vector<ESM::LandTexture>::const_iterator iterator; 00342 00343 const ESM::LandTexture *search(size_t index, size_t plugin) const { 00344 assert(plugin < mStatic.size()); 00345 const LandTextureList <exl = mStatic[plugin]; 00346 00347 assert(index < ltexl.size()); 00348 return <exl.at(index); 00349 } 00350 00351 const ESM::LandTexture *find(size_t index, size_t plugin) const { 00352 const ESM::LandTexture *ptr = search(index, plugin); 00353 if (ptr == 0) { 00354 std::ostringstream msg; 00355 msg << "Land texture with index " << index << " not found"; 00356 throw std::runtime_error(msg.str()); 00357 } 00358 return ptr; 00359 } 00360 00361 size_t getSize() const { 00362 return mStatic.size(); 00363 } 00364 00365 size_t getSize(size_t plugin) const { 00366 assert(plugin < mStatic.size()); 00367 return mStatic[plugin].size(); 00368 } 00369 00370 void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { 00371 ESM::LandTexture lt; 00372 lt.load(esm); 00373 lt.mId = id; 00374 00375 // Make sure we have room for the structure 00376 if (plugin >= mStatic.size()) { 00377 mStatic.resize(plugin+1); 00378 } 00379 LandTextureList <exl = mStatic[plugin]; 00380 if(lt.mIndex + 1 > (int)ltexl.size()) 00381 ltexl.resize(lt.mIndex+1); 00382 00383 // Store it 00384 ltexl[lt.mIndex] = lt; 00385 } 00386 00387 void load(ESM::ESMReader &esm, const std::string &id) { 00388 load(esm, id, esm.getIndex()); 00389 } 00390 00391 iterator begin(size_t plugin) const { 00392 assert(plugin < mStatic.size()); 00393 return mStatic[plugin].begin(); 00394 } 00395 00396 iterator end(size_t plugin) const { 00397 assert(plugin < mStatic.size()); 00398 return mStatic[plugin].end(); 00399 } 00400 }; 00401 00402 template <> 00403 class Store<ESM::Land> : public StoreBase 00404 { 00405 std::vector<ESM::Land *> mStatic; 00406 00407 struct Compare 00408 { 00409 bool operator()(const ESM::Land *x, const ESM::Land *y) { 00410 if (x->mX == y->mX) { 00411 return x->mY < y->mY; 00412 } 00413 return x->mX < y->mX; 00414 } 00415 }; 00416 00417 public: 00418 typedef SharedIterator<ESM::Land> iterator; 00419 00420 virtual ~Store<ESM::Land>() 00421 { 00422 for (std::vector<ESM::Land *>::const_iterator it = 00423 mStatic.begin(); it != mStatic.end(); ++it) 00424 { 00425 delete *it; 00426 } 00427 00428 } 00429 00430 size_t getSize() const { 00431 return mStatic.size(); 00432 } 00433 00434 iterator begin() const { 00435 return iterator(mStatic.begin()); 00436 } 00437 00438 iterator end() const { 00439 return iterator(mStatic.end()); 00440 } 00441 00442 ESM::Land *search(int x, int y) const { 00443 ESM::Land land; 00444 land.mX = x, land.mY = y; 00445 00446 std::vector<ESM::Land *>::const_iterator it = 00447 std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); 00448 00449 if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { 00450 return const_cast<ESM::Land *>(*it); 00451 } 00452 return 0; 00453 } 00454 00455 ESM::Land *find(int x, int y) const{ 00456 ESM::Land *ptr = search(x, y); 00457 if (ptr == 0) { 00458 std::ostringstream msg; 00459 msg << "Land at (" << x << ", " << y << ") not found"; 00460 throw std::runtime_error(msg.str()); 00461 } 00462 return ptr; 00463 } 00464 00465 void load(ESM::ESMReader &esm, const std::string &id) { 00466 ESM::Land *ptr = new ESM::Land(); 00467 ptr->load(esm); 00468 00469 // Same area defined in multiple plugins? -> last plugin wins 00470 // Can't use search() because we aren't sorted yet - is there any other way to speed this up? 00471 for (std::vector<ESM::Land*>::iterator it = mStatic.begin(); it != mStatic.end(); ++it) 00472 { 00473 if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) 00474 { 00475 delete *it; 00476 mStatic.erase(it); 00477 break; 00478 } 00479 } 00480 00481 mStatic.push_back(ptr); 00482 } 00483 00484 void setUp() { 00485 std::sort(mStatic.begin(), mStatic.end(), Compare()); 00486 } 00487 }; 00488 00489 template <> 00490 class Store<ESM::Cell> : public StoreBase 00491 { 00492 struct ExtCmp 00493 { 00494 bool operator()(const ESM::Cell &x, const ESM::Cell &y) { 00495 if (x.mData.mX == y.mData.mX) { 00496 return x.mData.mY < y.mData.mY; 00497 } 00498 return x.mData.mX < y.mData.mX; 00499 } 00500 }; 00501 00502 struct DynamicExtCmp 00503 { 00504 bool operator()(const std::pair<int, int> &left, const std::pair<int, int> &right) const { 00505 if (left.first == right.first) { 00506 return left.second < right.second; 00507 } 00508 return left.first < right.first; 00509 } 00510 }; 00511 00512 typedef std::map<std::string, ESM::Cell> DynamicInt; 00513 typedef std::map<std::pair<int, int>, ESM::Cell, DynamicExtCmp> DynamicExt; 00514 00515 DynamicInt mInt; 00516 DynamicExt mExt; 00517 00518 std::vector<ESM::Cell *> mSharedInt; 00519 std::vector<ESM::Cell *> mSharedExt; 00520 00521 DynamicInt mDynamicInt; 00522 DynamicExt mDynamicExt; 00523 00524 const ESM::Cell *search(const ESM::Cell &cell) const { 00525 if (cell.isExterior()) { 00526 return search(cell.getGridX(), cell.getGridY()); 00527 } 00528 return search(cell.mName); 00529 } 00530 00531 public: 00532 ESMStore *mEsmStore; 00533 00534 typedef SharedIterator<ESM::Cell> iterator; 00535 00536 Store<ESM::Cell>() 00537 {} 00538 00539 const ESM::Cell *search(const std::string &id) const { 00540 ESM::Cell cell; 00541 cell.mName = Misc::StringUtils::lowerCase(id); 00542 00543 std::map<std::string, ESM::Cell>::const_iterator it = mInt.find(cell.mName); 00544 00545 if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { 00546 return &(it->second); 00547 } 00548 00549 DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); 00550 if (dit != mDynamicInt.end()) { 00551 return &dit->second; 00552 } 00553 00554 return 0; 00555 } 00556 00557 const ESM::Cell *search(int x, int y) const { 00558 ESM::Cell cell; 00559 cell.mData.mX = x, cell.mData.mY = y; 00560 00561 std::pair<int, int> key(x, y); 00562 DynamicExt::const_iterator it = mExt.find(key); 00563 if (it != mExt.end()) { 00564 return &(it->second); 00565 } 00566 00567 DynamicExt::const_iterator dit = mDynamicExt.find(key); 00568 if (dit != mDynamicExt.end()) { 00569 return &dit->second; 00570 } 00571 00572 return 0; 00573 } 00574 00575 const ESM::Cell *searchOrCreate(int x, int y) { 00576 ESM::Cell cell; 00577 cell.mData.mX = x, cell.mData.mY = y; 00578 00579 std::pair<int, int> key(x, y); 00580 DynamicExt::const_iterator it = mExt.find(key); 00581 if (it != mExt.end()) { 00582 return &(it->second); 00583 } 00584 00585 DynamicExt::const_iterator dit = mDynamicExt.find(key); 00586 if (dit != mDynamicExt.end()) { 00587 return &dit->second; 00588 } 00589 00590 ESM::Cell *newCell = new ESM::Cell; 00591 newCell->mData.mX = x; 00592 newCell->mData.mY = y; 00593 mExt[std::make_pair(x, y)] = *newCell; 00594 delete newCell; 00595 00596 return &mExt[std::make_pair(x, y)]; 00597 } 00598 00599 const ESM::Cell *find(const std::string &id) const { 00600 const ESM::Cell *ptr = search(id); 00601 if (ptr == 0) { 00602 std::ostringstream msg; 00603 msg << "Interior cell '" << id << "' not found"; 00604 throw std::runtime_error(msg.str()); 00605 } 00606 return ptr; 00607 } 00608 00609 const ESM::Cell *find(int x, int y) const { 00610 const ESM::Cell *ptr = search(x, y); 00611 if (ptr == 0) { 00612 std::ostringstream msg; 00613 msg << "Exterior at (" << x << ", " << y << ") not found"; 00614 throw std::runtime_error(msg.str()); 00615 } 00616 return ptr; 00617 } 00618 00619 void setUp() { 00620 //typedef std::vector<ESM::Cell>::iterator Iterator; 00621 typedef DynamicExt::iterator ExtIterator; 00622 typedef std::map<std::string, ESM::Cell>::iterator IntIterator; 00623 00624 //std::sort(mInt.begin(), mInt.end(), RecordCmp()); 00625 mSharedInt.reserve(mInt.size()); 00626 for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { 00627 mSharedInt.push_back(&(it->second)); 00628 } 00629 00630 //std::sort(mExt.begin(), mExt.end(), ExtCmp()); 00631 mSharedExt.reserve(mExt.size()); 00632 for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { 00633 mSharedExt.push_back(&(it->second)); 00634 } 00635 } 00636 00637 // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get 00638 // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. 00639 // There some nasty three-way cyclic header dependency involved, which I could only fix by moving 00640 // this method. 00641 void load(ESM::ESMReader &esm, const std::string &id); 00642 00643 iterator intBegin() const { 00644 return iterator(mSharedInt.begin()); 00645 } 00646 00647 iterator intEnd() const { 00648 return iterator(mSharedInt.end()); 00649 } 00650 00651 iterator extBegin() const { 00652 return iterator(mSharedExt.begin()); 00653 } 00654 00655 iterator extEnd() const { 00656 return iterator(mSharedExt.end()); 00657 } 00658 00659 // Return the northernmost cell in the easternmost column. 00660 const ESM::Cell *searchExtByName(const std::string &id) const { 00661 ESM::Cell *cell = 0; 00662 std::vector<ESM::Cell *>::const_iterator it = mSharedExt.begin(); 00663 for (; it != mSharedExt.end(); ++it) { 00664 if (Misc::StringUtils::ciEqual((*it)->mName, id)) { 00665 if ( cell == 0 || 00666 ( (*it)->mData.mX > cell->mData.mX ) || 00667 ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) 00668 { 00669 cell = *it; 00670 } 00671 } 00672 } 00673 return cell; 00674 } 00675 00676 // Return the northernmost cell in the easternmost column. 00677 const ESM::Cell *searchExtByRegion(const std::string &id) const { 00678 ESM::Cell *cell = 0; 00679 std::vector<ESM::Cell *>::const_iterator it = mSharedExt.begin(); 00680 for (; it != mSharedExt.end(); ++it) { 00681 if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { 00682 if ( cell == 0 || 00683 ( (*it)->mData.mX > cell->mData.mX ) || 00684 ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) 00685 { 00686 cell = *it; 00687 } 00688 } 00689 } 00690 return cell; 00691 } 00692 00693 size_t getSize() const { 00694 return mSharedInt.size() + mSharedExt.size(); 00695 } 00696 00697 void listIdentifier(std::vector<std::string> &list) const { 00698 list.reserve(list.size() + mSharedInt.size()); 00699 00700 std::vector<ESM::Cell *>::const_iterator it = mSharedInt.begin(); 00701 for (; it != mSharedInt.end(); ++it) { 00702 list.push_back((*it)->mName); 00703 } 00704 } 00705 00706 ESM::Cell *insert(const ESM::Cell &cell) { 00707 if (search(cell) != 0) { 00708 std::ostringstream msg; 00709 msg << "Failed to create "; 00710 msg << ((cell.isExterior()) ? "exterior" : "interior"); 00711 msg << " cell"; 00712 00713 throw std::runtime_error(msg.str()); 00714 } 00715 ESM::Cell *ptr; 00716 if (cell.isExterior()) { 00717 std::pair<int, int> key(cell.getGridX(), cell.getGridY()); 00718 00719 // duplicate insertions are avoided by search(ESM::Cell &) 00720 std::pair<DynamicExt::iterator, bool> result = 00721 mDynamicExt.insert(std::make_pair(key, cell)); 00722 00723 ptr = &result.first->second; 00724 mSharedExt.push_back(ptr); 00725 } else { 00726 std::string key = Misc::StringUtils::lowerCase(cell.mName); 00727 00728 // duplicate insertions are avoided by search(ESM::Cell &) 00729 std::pair<DynamicInt::iterator, bool> result = 00730 mDynamicInt.insert(std::make_pair(key, cell)); 00731 00732 ptr = &result.first->second; 00733 mSharedInt.push_back(ptr); 00734 } 00735 return ptr; 00736 } 00737 00738 bool erase(const ESM::Cell &cell) { 00739 if (cell.isExterior()) { 00740 return erase(cell.getGridX(), cell.getGridY()); 00741 } 00742 return erase(cell.mName); 00743 } 00744 00745 bool erase(const std::string &id) { 00746 std::string key = Misc::StringUtils::lowerCase(id); 00747 DynamicInt::iterator it = mDynamicInt.find(key); 00748 00749 if (it == mDynamicInt.end()) { 00750 return false; 00751 } 00752 mDynamicInt.erase(it); 00753 mSharedInt.erase( 00754 mSharedInt.begin() + mSharedInt.size(), 00755 mSharedInt.end() 00756 ); 00757 00758 for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { 00759 mSharedInt.push_back(&it->second); 00760 } 00761 00762 return true; 00763 } 00764 00765 bool erase(int x, int y) { 00766 std::pair<int, int> key(x, y); 00767 DynamicExt::iterator it = mDynamicExt.find(key); 00768 00769 if (it == mDynamicExt.end()) { 00770 return false; 00771 } 00772 mDynamicExt.erase(it); 00773 mSharedExt.erase( 00774 mSharedExt.begin() + mSharedExt.size(), 00775 mSharedExt.end() 00776 ); 00777 00778 for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { 00779 mSharedExt.push_back(&it->second); 00780 } 00781 00782 return true; 00783 } 00784 }; 00785 00786 template <> 00787 class Store<ESM::Pathgrid> : public StoreBase 00788 { 00789 public: 00790 typedef std::vector<ESM::Pathgrid>::const_iterator iterator; 00791 00792 private: 00793 std::vector<ESM::Pathgrid> mStatic; 00794 00795 std::vector<ESM::Pathgrid>::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd; 00796 00797 struct IntExtOrdering 00798 { 00799 bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { 00800 // interior pathgrids precedes exterior ones (x < y) 00801 if ((x.mData.mX == 0 && x.mData.mY == 0) && 00802 (y.mData.mX != 0 || y.mData.mY != 0)) 00803 { 00804 return true; 00805 } 00806 return false; 00807 } 00808 }; 00809 00810 struct ExtCompare 00811 { 00812 bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { 00813 if (x.mData.mX == y.mData.mX) { 00814 return x.mData.mY < y.mData.mY; 00815 } 00816 return x.mData.mX < y.mData.mX; 00817 } 00818 }; 00819 00820 public: 00821 00822 void load(ESM::ESMReader &esm, const std::string &id) { 00823 mStatic.push_back(ESM::Pathgrid()); 00824 mStatic.back().load(esm); 00825 } 00826 00827 size_t getSize() const { 00828 return mStatic.size(); 00829 } 00830 00831 void setUp() { 00832 IntExtOrdering cmp; 00833 std::sort(mStatic.begin(), mStatic.end(), cmp); 00834 00835 ESM::Pathgrid pg; 00836 pg.mData.mX = pg.mData.mY = 1; 00837 mExtBegin = 00838 std::lower_bound(mStatic.begin(), mStatic.end(), pg, cmp); 00839 mExtEnd = mStatic.end(); 00840 00841 mIntBegin = mStatic.begin(); 00842 mIntEnd = mExtBegin; 00843 00844 std::sort(mIntBegin, mIntEnd, RecordCmp()); 00845 std::sort(mExtBegin, mExtEnd, ExtCompare()); 00846 } 00847 00848 const ESM::Pathgrid *search(int x, int y) const { 00849 ESM::Pathgrid pg; 00850 pg.mData.mX = x; 00851 pg.mData.mY = y; 00852 00853 iterator it = 00854 std::lower_bound(mExtBegin, mExtEnd, pg, ExtCompare()); 00855 if (it != mExtEnd && it->mData.mX == x && it->mData.mY == y) { 00856 return &(*it); 00857 } 00858 return 0; 00859 } 00860 00861 const ESM::Pathgrid *find(int x, int y) const { 00862 const ESM::Pathgrid *ptr = search(x, y); 00863 if (ptr == 0) { 00864 std::ostringstream msg; 00865 msg << "Pathgrid at (" << x << ", " << y << ") not found"; 00866 throw std::runtime_error(msg.str()); 00867 } 00868 return ptr; 00869 } 00870 00871 const ESM::Pathgrid *search(const std::string &name) const { 00872 ESM::Pathgrid pg; 00873 pg.mCell = name; 00874 00875 iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, RecordCmp()); 00876 if (it != mIntEnd && Misc::StringUtils::ciEqual(it->mCell, name)) { 00877 return &(*it); 00878 } 00879 return 0; 00880 } 00881 00882 const ESM::Pathgrid *find(const std::string &name) const { 00883 const ESM::Pathgrid *ptr = search(name); 00884 if (ptr == 0) { 00885 std::ostringstream msg; 00886 msg << "Pathgrid in cell '" << name << "' not found"; 00887 throw std::runtime_error(msg.str()); 00888 } 00889 return ptr; 00890 } 00891 00892 const ESM::Pathgrid *search(const ESM::Cell &cell) const { 00893 if (cell.mData.mFlags & ESM::Cell::Interior) { 00894 return search(cell.mName); 00895 } 00896 return search(cell.mData.mX, cell.mData.mY); 00897 } 00898 00899 const ESM::Pathgrid *find(const ESM::Cell &cell) const { 00900 if (cell.mData.mFlags & ESM::Cell::Interior) { 00901 return find(cell.mName); 00902 } 00903 return find(cell.mData.mX, cell.mData.mY); 00904 } 00905 00906 iterator begin() const { 00907 return mStatic.begin(); 00908 } 00909 00910 iterator end() const { 00911 return mStatic.end(); 00912 } 00913 00914 iterator interiorPathsBegin() const { 00915 return mIntBegin; 00916 } 00917 00918 iterator interiorPathsEnd() const { 00919 return mIntEnd; 00920 } 00921 00922 iterator exteriorPathsBegin() const { 00923 return mExtBegin; 00924 } 00925 00926 iterator exteriorPathsEnd() const { 00927 return mExtEnd; 00928 } 00929 }; 00930 00931 template <class T> 00932 class IndexedStore 00933 { 00934 struct Compare 00935 { 00936 bool operator()(const T &x, const T &y) const { 00937 return x.mIndex < y.mIndex; 00938 } 00939 }; 00940 protected: 00941 std::vector<T> mStatic; 00942 00943 public: 00944 typedef typename std::vector<T>::const_iterator iterator; 00945 00946 IndexedStore() {} 00947 00948 IndexedStore(unsigned int size) { 00949 mStatic.reserve(size); 00950 } 00951 00952 iterator begin() const { 00953 return mStatic.begin(); 00954 } 00955 00956 iterator end() const { 00957 return mStatic.end(); 00958 } 00959 00961 void load(ESM::ESMReader &esm) { 00962 mStatic.push_back(T()); 00963 mStatic.back().load(esm); 00964 } 00965 00966 int getSize() const { 00967 return mStatic.size(); 00968 } 00969 00970 void setUp() { 00976 00977 Compare cmp; 00978 00979 std::stable_sort(mStatic.begin(), mStatic.end(), cmp); 00980 00981 typename std::vector<T>::iterator first, next; 00982 next = first = mStatic.begin(); 00983 00984 while (first != mStatic.end() && ++next != mStatic.end()) { 00985 while (next != mStatic.end() && !cmp(*first, *next)) { 00986 ++next; 00987 } 00988 if (first != --next) { 00989 std::swap(*first, *next); 00990 } 00991 first = ++next; 00992 } 00993 } 00994 00995 const T *search(int index) const { 00996 T item; 00997 item.mIndex = index; 00998 00999 iterator it = 01000 std::lower_bound(mStatic.begin(), mStatic.end(), item, Compare()); 01001 if (it != mStatic.end() && it->mIndex == index) { 01002 return &(*it); 01003 } 01004 return 0; 01005 } 01006 01007 const T *find(int index) const { 01008 const T *ptr = search(index); 01009 if (ptr == 0) { 01010 std::ostringstream msg; 01011 msg << "Object with index " << index << " not found"; 01012 throw std::runtime_error(msg.str()); 01013 } 01014 return ptr; 01015 } 01016 }; 01017 01018 template <> 01019 struct Store<ESM::Skill> : public IndexedStore<ESM::Skill> 01020 { 01021 Store() {} 01022 Store(unsigned int size) 01023 : IndexedStore<ESM::Skill>(size) 01024 {} 01025 }; 01026 01027 template <> 01028 struct Store<ESM::MagicEffect> : public IndexedStore<ESM::MagicEffect> 01029 { 01030 Store() {} 01031 Store(unsigned int size) 01032 : IndexedStore<ESM::MagicEffect>(size) 01033 {} 01034 }; 01035 01036 template <> 01037 class Store<ESM::Attribute> : public IndexedStore<ESM::Attribute> 01038 { 01039 std::vector<ESM::Attribute> mStatic; 01040 01041 public: 01042 typedef std::vector<ESM::Attribute>::const_iterator iterator; 01043 01044 Store() { 01045 mStatic.reserve(ESM::Attribute::Length); 01046 } 01047 01048 const ESM::Attribute *search(size_t index) const { 01049 if (index >= mStatic.size()) { 01050 return 0; 01051 } 01052 return &mStatic.at(index); 01053 } 01054 01055 const ESM::Attribute *find(size_t index) const { 01056 const ESM::Attribute *ptr = search(index); 01057 if (ptr == 0) { 01058 std::ostringstream msg; 01059 msg << "Attribute with index " << index << " not found"; 01060 throw std::runtime_error(msg.str()); 01061 } 01062 return ptr; 01063 } 01064 01065 void setUp() { 01066 for (int i = 0; i < ESM::Attribute::Length; ++i) { 01067 mStatic.push_back( 01068 ESM::Attribute( 01069 ESM::Attribute::sAttributeIds[i], 01070 ESM::Attribute::sGmstAttributeIds[i], 01071 ESM::Attribute::sGmstAttributeDescIds[i] 01072 ) 01073 ); 01074 } 01075 } 01076 01077 size_t getSize() const { 01078 return mStatic.size(); 01079 } 01080 01081 iterator begin() const { 01082 return mStatic.begin(); 01083 } 01084 01085 iterator end() const { 01086 return mStatic.end(); 01087 } 01088 }; 01089 01090 } //end namespace 01091 01092 #endif