mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 01:56:44 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			139 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
	
		
			4.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();
 | 
						|
                        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();
 | 
						|
    }
 | 
						|
}
 |