OpenMW
apps/openmw/mwworld/store.hpp
Go to the documentation of this file.
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 &ltexl = 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 &ltexl = mStatic[plugin];
00346 
00347             assert(index < ltexl.size());
00348             return &ltexl.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 &ltexl = 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