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.
115 lines
3.1 KiB
C++
115 lines
3.1 KiB
C++
2 years ago
|
#ifndef OPENMW_COMPONENTS_ESM3_INFOORDER_H
|
||
|
#define OPENMW_COMPONENTS_ESM3_INFOORDER_H
|
||
|
|
||
|
#include "components/esm/refid.hpp"
|
||
|
|
||
|
#include <iterator>
|
||
|
#include <list>
|
||
|
#include <type_traits>
|
||
|
#include <unordered_map>
|
||
|
#include <utility>
|
||
|
|
||
|
namespace ESM
|
||
|
{
|
||
|
template <class T>
|
||
|
class InfoOrder
|
||
|
{
|
||
|
public:
|
||
|
const std::list<T>& getOrderedInfo() const { return mOrderedInfo; }
|
||
|
|
||
|
template <class V>
|
||
|
void insertInfo(V&& value, bool deleted)
|
||
|
{
|
||
|
static_assert(std::is_same_v<std::decay_t<V>, T>);
|
||
|
|
||
|
auto it = mInfoPositions.find(value.mId);
|
||
|
|
||
|
if (it != mInfoPositions.end() && it->second.mPosition->mPrev == value.mPrev)
|
||
|
{
|
||
|
*it->second.mPosition = std::forward<V>(value);
|
||
|
it->second.mDeleted = deleted;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (it == mInfoPositions.end())
|
||
|
it = mInfoPositions.emplace(value.mId, Item{ .mPosition = mOrderedInfo.end(), .mDeleted = deleted })
|
||
|
.first;
|
||
|
|
||
|
Item& item = it->second;
|
||
|
|
||
|
const auto insertOrSplice = [&](typename std::list<T>::const_iterator before) {
|
||
|
if (item.mPosition == mOrderedInfo.end())
|
||
|
item.mPosition = mOrderedInfo.insert(before, std::forward<V>(value));
|
||
|
else
|
||
|
mOrderedInfo.splice(before, mOrderedInfo, item.mPosition);
|
||
|
};
|
||
|
|
||
|
if (value.mPrev.empty())
|
||
|
{
|
||
|
insertOrSplice(mOrderedInfo.begin());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const auto prevIt = mInfoPositions.find(value.mPrev);
|
||
|
if (prevIt != mInfoPositions.end())
|
||
|
{
|
||
|
insertOrSplice(std::next(prevIt->second.mPosition));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const auto nextIt = mInfoPositions.find(value.mNext);
|
||
|
if (nextIt != mInfoPositions.end())
|
||
|
{
|
||
|
insertOrSplice(nextIt->second.mPosition);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
insertOrSplice(mOrderedInfo.end());
|
||
|
}
|
||
|
|
||
|
void removeInfo(const RefId& infoRefId)
|
||
|
{
|
||
|
const auto it = mInfoPositions.find(infoRefId);
|
||
|
|
||
|
if (it == mInfoPositions.end())
|
||
|
return;
|
||
|
|
||
|
mOrderedInfo.erase(it->second.mPosition);
|
||
|
mInfoPositions.erase(it);
|
||
|
}
|
||
|
|
||
|
void removeDeleted()
|
||
|
{
|
||
|
for (auto it = mInfoPositions.begin(); it != mInfoPositions.end();)
|
||
|
{
|
||
|
if (!it->second.mDeleted)
|
||
|
{
|
||
|
++it;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
mOrderedInfo.erase(it->second.mPosition);
|
||
|
it = mInfoPositions.erase(it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void extractOrderedInfo(std::list<T>& info)
|
||
|
{
|
||
|
info = mOrderedInfo;
|
||
|
mInfoPositions.clear();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
struct Item
|
||
|
{
|
||
|
typename std::list<T>::iterator mPosition;
|
||
|
bool mDeleted = false;
|
||
|
};
|
||
|
|
||
|
std::list<T> mOrderedInfo;
|
||
|
std::unordered_map<RefId, Item> mInfoPositions;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#endif
|