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.
openmw/components/esm3/readerscache.cpp

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;
}
}
}