mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
2.5 KiB
C++
90 lines
2.5 KiB
C++
#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();
|
|
}
|
|
mBusyItems.splice(mBusyItems.end(), mClosedItems, it);
|
|
break;
|
|
}
|
|
it->mState = State::Busy;
|
|
}
|
|
|
|
return BusyItem(*this, it);
|
|
}
|
|
|
|
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->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;
|
|
}
|
|
}
|
|
}
|