Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
4.6 kB · 139 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140#include "readerscache.hpp"
#include <stdexcept>
namespace ESM{ ReadersCache::BusyItem::BusyItem(ReadersCache& owner, std::list<Item>::iterator item) noexcept : mOwner(owner) , mItem(item) { }
ReadersCache::BusyItem::~BusyItem() noexcept { mOwner.releaseItem(mItem); }
ReadersCache::ReadersCache(std::size_t capacity) : mCapacity(capacity) { }
ReadersCache::BusyItem ReadersCache::get(std::size_t index) { const auto indexIt = mIndex.find(index); std::list<Item>::iterator it; if (indexIt == mIndex.end()) { closeExtraReaders(); it = mBusyItems.emplace(mBusyItems.end()); mIndex.emplace(index, it); } else { switch (indexIt->second->mState) { case State::Busy: throw std::logic_error("ESMReader at index " + std::to_string(index) + " is busy"); case State::Free: it = indexIt->second; mBusyItems.splice(mBusyItems.end(), mFreeItems, it); break; case State::Closed: closeExtraReaders(); it = indexIt->second; if (it->mName.has_value()) { it->mReader.open(*it->mName); it->mName.reset(); it->mFileSize.reset(); } mBusyItems.splice(mBusyItems.end(), mClosedItems, it); break; } it->mState = State::Busy; }
return BusyItem(*this, it); }
const std::filesystem::path& ReadersCache::getName(std::size_t index) const { const auto indexIt = mIndex.find(index); if (indexIt == mIndex.end()) throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been created yet"); switch (indexIt->second->mState) { case State::Busy: case State::Free: return indexIt->second->mReader.getName(); case State::Closed: if (indexIt->second->mName) return *indexIt->second->mName; throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its filename"); default: throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state"); } }
std::size_t ReadersCache::getFileSize(std::size_t index) { const auto indexIt = mIndex.find(index); if (indexIt == mIndex.end()) return 0; switch (indexIt->second->mState) { case State::Busy: case State::Free: if (!indexIt->second->mReader.getName().empty()) return indexIt->second->mReader.getFileSize(); throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been opened yet"); case State::Closed: if (indexIt->second->mFileSize) return *indexIt->second->mFileSize; throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its file size"); default: throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state"); } }
void ReadersCache::closeExtraReaders() { while (!mFreeItems.empty() && mBusyItems.size() + mFreeItems.size() + 1 > mCapacity) { const auto it = mFreeItems.begin(); if (it->mReader.isOpen()) { it->mName = it->mReader.getName(); it->mFileSize = it->mReader.getFileSize(); it->mReader.close(); } mClosedItems.splice(mClosedItems.end(), mFreeItems, it); it->mState = State::Closed; } }
void ReadersCache::releaseItem(std::list<Item>::iterator it) noexcept { assert(it->mState == State::Busy); if (it->mReader.isOpen()) { mFreeItems.splice(mFreeItems.end(), mBusyItems, it); it->mState = State::Free; } else { mClosedItems.splice(mClosedItems.end(), mBusyItems, it); it->mState = State::Closed; } }
void ReadersCache::clear() { mIndex.clear(); mBusyItems.clear(); mFreeItems.clear(); mClosedItems.clear(); }}