continue refactor project

This commit is contained in:
yyc12345 2023-09-16 22:38:21 +08:00
parent 1ddeeb3b68
commit 3c8266e7dd
8 changed files with 215 additions and 60 deletions

View File

@ -41,6 +41,9 @@ namespace LibCmo::CK2::MgrImpls {
m_ObjectsList[decided_off] = obj;
++m_ObjectCount;
// add into classid indexed object list
m_ObjectsListByClass[static_cast<size_t>(cls)].push_back(Offset2Id(decided_off));
// set out variable
return obj;
}
@ -76,9 +79,12 @@ namespace LibCmo::CK2::MgrImpls {
CKDWORD off = Id2Offset(ids[i]);
if (off >= m_ObjectsList.size()) continue;
// get object and free it
// get object and its classid for future use
ObjImpls::CKObject* obj = m_ObjectsList[off];
if (obj == nullptr) continue;
CK_CLASSID cls = obj->GetClassID();
// free it
InternalDestroy(obj);
// return its allocated id.
@ -87,6 +93,9 @@ namespace LibCmo::CK2::MgrImpls {
m_ReturnedObjectOffsets.emplace_back(off);
--m_ObjectCount;
// remove from classid indexed list
std::erase(m_ObjectsListByClass[static_cast<size_t>(cls)], ids[i]);
}
// notice post
@ -147,61 +156,59 @@ namespace LibCmo::CK2::MgrImpls {
return result;
}
CKDWORD CKObjectManager::AllocateGroupGlobalIndex(ObjImpls::CKObject* group) {
// try find first nullptr position
CKDWORD index = 0;
for (const auto& ptr : m_GroupGlobalIndex) {
if (ptr == nullptr) break;
++index;
bool CKObjectManager::IsObjectSafe(CK_ID objid) {
CKDWORD off = Id2Offset(objid);
if (off >= m_ObjectsList.size()) return false;
return m_ObjectsList[off] != nullptr;
}
bool CKObjectManager::IsObjectPointerSafe(const ObjImpls::CKObject* objptr) {
if (objptr == nullptr) return false;
// iterate all object list to check
for (const auto& ptr : m_ObjectsList) {
if (ptr == objptr) return true;
}
// resize array for new position
if (index == m_GroupGlobalIndex.size()) {
return false;
}
CKDWORD CKObjectManager::AllocateGroupGlobalIndex() {
// try find first non-true position
CKDWORD index;
if (!XContainer::NSXBitArray::GetUnsetBitPosition(m_GroupGlobalIndex, 0, index)) {
// failed. distribute new one
index = static_cast<CKDWORD>(m_GroupGlobalIndex.size());
m_GroupGlobalIndex.resize(m_GroupGlobalIndex.size() + 1);
}
// set to occupy
m_GroupGlobalIndex[index] = group;
m_GroupGlobalIndex[index] = true;
return index;
}
CKDWORD CKObjectManager::AllocateSceneGlobalIndex(ObjImpls::CKObject* scene) {
CKDWORD CKObjectManager::AllocateSceneGlobalIndex() {
// same as group
CKDWORD index = 0;
for (const auto& ptr : m_SceneGlobalIndex) {
if (ptr == nullptr) break;
++index;
}
// resize array for new position
if (index == m_SceneGlobalIndex.size()) {
CKDWORD index;
if (!XContainer::NSXBitArray::GetUnsetBitPosition(m_SceneGlobalIndex, 0, index)) {
index = static_cast<CKDWORD>(m_SceneGlobalIndex.size());
m_SceneGlobalIndex.resize(m_SceneGlobalIndex.size() + 1);
}
// set to occupy
m_SceneGlobalIndex[index] = scene;
m_SceneGlobalIndex[index] = true;
return index;
}
ObjImpls::CKObject* CKObjectManager::GetGroupByGlobalIndex(CKDWORD index) {
if (index >= m_GroupGlobalIndex.size()) return nullptr;
else return m_GroupGlobalIndex[index];
}
ObjImpls::CKObject* CKObjectManager::GetSceneByGlobalIndex(CKDWORD index) {
if (index >= m_SceneGlobalIndex.size()) return nullptr;
else return m_SceneGlobalIndex[index];
}
void CKObjectManager::FreeGroupGlobalIndex(CKDWORD id) {
// check position
if (id >= m_GroupGlobalIndex.size()) return;
// set value
m_GroupGlobalIndex[id] = nullptr;
m_GroupGlobalIndex[id] = false;
}
void CKObjectManager::FreeSceneGlobalIndex(CKDWORD id) {
// same as group
if (id >= m_SceneGlobalIndex.size()) return;
m_SceneGlobalIndex[id] = nullptr;
m_SceneGlobalIndex[id] = false;
}
}

View File

@ -50,12 +50,14 @@ namespace LibCmo::CK2::MgrImpls {
XContainer::XObjectPointerArray GetObjectByNameAndClass(
CKSTRING name, CK_CLASSID cid, bool derived);
// ========== Object Check ==========
bool IsObjectSafe(CK_ID objid);
bool IsObjectPointerSafe(const ObjImpls::CKObject* objptr);
// ========== Special Functions ==========
CKDWORD AllocateGroupGlobalIndex(ObjImpls::CKObject* group);
CKDWORD AllocateSceneGlobalIndex(ObjImpls::CKObject* scene);
ObjImpls::CKObject* GetGroupByGlobalIndex(CKDWORD index);
ObjImpls::CKObject* GetSceneByGlobalIndex(CKDWORD index);
CKDWORD AllocateGroupGlobalIndex();
CKDWORD AllocateSceneGlobalIndex();
void FreeGroupGlobalIndex(CKDWORD id);
void FreeSceneGlobalIndex(CKDWORD id);
@ -77,11 +79,11 @@ namespace LibCmo::CK2::MgrImpls {
CKDWORD m_ObjectCount;
XContainer::XObjectPointerArray m_ObjectsList;
XContainer::XArray<XContainer::XArray<CKDWORD>> m_ObjectsListByClass;
XContainer::XArray<XContainer::XList<CKDWORD>> m_ObjectsListByClass;
std::deque<CKDWORD> m_ReturnedObjectOffsets;
XContainer::XObjectPointerArray m_GroupGlobalIndex;
XContainer::XObjectPointerArray m_SceneGlobalIndex;
XContainer::XBitArray m_GroupGlobalIndex;
XContainer::XBitArray m_SceneGlobalIndex;
};

View File

@ -8,16 +8,16 @@
namespace LibCmo::CK2::ObjImpls {
CKBeObject::CKBeObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
CKSceneObject(ctx, ckid, name) {}
CKSceneObject(ctx, ckid, name), m_Groups() {}
CKBeObject::~CKBeObject() {
// remove self from all group
for (size_t i = 0; i < m_Groups.size(); ++i) {
if (m_Groups[i]) {
CKGroup* group = static_cast<CKGroup*>(m_Context->GetObjectManager()->GetGroupByGlobalIndex(static_cast<CKDWORD>(i)));
group->RemoveObject(this);
}
}
//for (size_t i = 0; i < m_Groups.size(); ++i) {
// if (m_Groups[i]) {
// CKGroup* group = static_cast<CKGroup*>(m_Context->GetObjectManager()->GetGroupByGlobalIndex(static_cast<CKDWORD>(i)));
// group->RemoveObject(this);
// }
//}
}
bool CKBeObject::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
@ -36,12 +36,12 @@ namespace LibCmo::CK2::ObjImpls {
bool CKBeObject::IsInGroup(CKGroup* group) {
if (group == nullptr) return false;
CKDWORD idx = group->CKBeObject_GetGroupIndex();
CKDWORD idx = group->GetGroupIndex();
if (idx >= m_Groups.size()) return false;
return m_Groups[idx];
}
void CKBeObject::CKGroup_SetGroups(CKDWORD pos, bool val) {
void CKBeObject::ExplicitSetGroup(CKDWORD pos, bool val) {
if (pos >= m_Groups.size()) m_Groups.resize(pos + 1);
m_Groups[pos] = val;
}

View File

@ -20,7 +20,13 @@ namespace LibCmo::CK2::ObjImpls {
//virtual void PostLoad() override;
bool IsInGroup(CKGroup* group);
void CKGroup_SetGroups(CKDWORD pos, bool val);
/**
* @brief Directly set group data.
* @param pos
* @param val
* @warning This function only should be called by CKGroup. Any other classes should not call this.
*/
void ExplicitSetGroup(CKDWORD pos, bool val);
protected:
XContainer::XBitArray m_Groups;

View File

@ -9,7 +9,7 @@ namespace LibCmo::CK2::ObjImpls {
CKGroup::CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name) :
CKBeObject(ctx, ckid, name),
m_ObjectArray(),
m_GroupIndex(m_Context->GetObjectManager()->AllocateGroupGlobalIndex(this)) {}
m_GroupIndex(m_Context->GetObjectManager()->AllocateGroupGlobalIndex()) {}
CKGroup::~CKGroup() {
m_Context->GetObjectManager()->FreeGroupGlobalIndex(m_GroupIndex);
@ -45,7 +45,7 @@ namespace LibCmo::CK2::ObjImpls {
if (beobj->IsInGroup(this)) continue;
// add good one
beobj->CKGroup_SetGroups(m_GroupIndex, true);
beobj->ExplicitSetGroup(m_GroupIndex, true);
m_ObjectArray.emplace_back(beobj);
}
@ -54,7 +54,7 @@ namespace LibCmo::CK2::ObjImpls {
return true;
}
CKDWORD CKGroup::CKBeObject_GetGroupIndex() {
CKDWORD CKGroup::GetGroupIndex() {
return m_GroupIndex;
}
@ -67,7 +67,7 @@ namespace LibCmo::CK2::ObjImpls {
}
// set object
o->CKGroup_SetGroups(m_GroupIndex, true);
o->ExplicitSetGroup(m_GroupIndex, true);
// set self
m_ObjectArray.emplace_back(o);
return CKERROR::CKERR_OK;
@ -80,7 +80,7 @@ namespace LibCmo::CK2::ObjImpls {
auto it = m_ObjectArray.begin() + pos;
CKBeObject* obj = static_cast<CKBeObject*>(*it);
// set object
obj->CKGroup_SetGroups(m_GroupIndex, false);
obj->ExplicitSetGroup(m_GroupIndex, false);
// remove self
m_ObjectArray.erase(it);
return obj;
@ -91,7 +91,7 @@ namespace LibCmo::CK2::ObjImpls {
auto finder = std::find(m_ObjectArray.begin(), m_ObjectArray.end(), static_cast<CKObject*>(obj));
if (finder != m_ObjectArray.end()) {
// set object
static_cast<CKBeObject*>(*finder)->CKGroup_SetGroups(m_GroupIndex, false);
static_cast<CKBeObject*>(*finder)->ExplicitSetGroup(m_GroupIndex, false);
// remove self
m_ObjectArray.erase(finder);
}
@ -100,7 +100,7 @@ namespace LibCmo::CK2::ObjImpls {
void CKGroup::Clear() {
for (auto& beobj : m_ObjectArray) {
// set object
static_cast<CKBeObject*>(beobj)->CKGroup_SetGroups(m_GroupIndex, false);
static_cast<CKBeObject*>(beobj)->ExplicitSetGroup(m_GroupIndex, false);
}
m_ObjectArray.clear();

View File

@ -19,7 +19,7 @@ namespace LibCmo::CK2::ObjImpls {
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
//virtual void PostLoad() override;
CKDWORD CKBeObject_GetGroupIndex();
CKDWORD GetGroupIndex();
// ===== Insert =====
CKERROR AddObject(CKBeObject *o);

View File

@ -1,5 +1,8 @@
#pragma once
#include "XTypes.hpp"
#include "../CK2/CKContext.hpp"
#include "../CK2/MgrImpls/CKObjectManager.hpp"
#include "../CK2/ObjImpls/CKObject.hpp"
#include <type_traits>
namespace LibCmo::XContainer {
@ -46,4 +49,84 @@ namespace LibCmo::XContainer {
}
template<class _Ty>
constexpr bool GeneralXArrayCheck_TypeCheck() {
return std::is_same_v<_Ty, CK2::CK_ID> || std::is_same_v<_Ty, CK2::ObjImpls::CKObject*>;
}
template<class _Ty, bool _IsPre>
bool GeneralXArrayCheck_ItemCheck(const _Ty& item, CK2::CKContext* ctx) {
static_assert(GeneralXArrayCheck_TypeCheck<_Ty>());
if (ctx == nullptr) return false;
if constexpr (_IsPre) {
CK2::ObjImpls::CKObject* obj = nullptr;
if constexpr (std::is_same_v<_Ty, CK2::CK_ID>) {
obj = ctx->GetObject(item);
if (obj == nullptr) return false;
} else {
obj = item;
}
if (EnumsHelper::Has(obj->GetObjectFlags(), CK2::CK_OBJECT_FLAGS::CK_OBJECT_TOBEDELETED)) return false;
} else {
CK2::MgrImpls::CKObjectManager* objmgr = ctx->GetObjectManager();
if constexpr (std::is_same_v<_Ty, CK2::CK_ID>) {
if (!objmgr->IsObjectSafe(item)) return false;
} else {
if (!objmgr->IsObjectPointerSafe(item)) return false;
}
}
return true;
}
namespace NSXObjectArray {
void PreDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](const CK2::CK_ID& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, true>(item, ctx);
});
}
void PostDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](const CK2::CK_ID& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, false>(item, ctx);
});
}
}
namespace NSXObjectPointerArray {
void PreDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::ObjImpls::CKObject*, true>(item, ctx);
});
}
void PostDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::ObjImpls::CKObject*, false>(item, ctx);
});
}
void PreDeletedCheck(XList<CK2::ObjImpls::CKObject*>& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::ObjImpls::CKObject*, true>(item, ctx);
});
}
void PostDeletedCheck(XList<CK2::ObjImpls::CKObject*>& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool {
return GeneralXArrayCheck_ItemCheck<CK2::ObjImpls::CKObject*, false>(item, ctx);
});
}
}
}

View File

@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include <unordered_map>
#include <list>
/**
* @brief The X container part of LibCmo.
@ -34,6 +35,13 @@ namespace LibCmo::XContainer {
*/
template<typename T>
using XArray = std::vector<T>;
/**
* @brief Double-linked list.
* @tparam T Element Type.
*/
template<typename T>
using XList = std::list<T>;
/**
@brief Container class for CKObject Id's.
@ -105,5 +113,54 @@ namespace LibCmo::XContainer {
}
namespace NSXObjectArray {
/**
* @brief Check Object ID validation and remove invalid IDs before deletion.
* @param objarray
* @param ctx
*/
void PreDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx);
/**
* @brief Check Object ID validation and remove invalid IDs after deletion.
* @param objarray
* @param ctx
*/
void PostDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx);
}
namespace NSXObjectPointerArray {
/**
* @brief Check Object pointer validation and remove invalid pointers before deletion.
* @param objarray
* @param ctx
*/
void PreDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx);
/**
* @brief Check Object pointer validation and remove invalid pointers after deletion.
* @param objarray
* @param ctx
* @remark The performance of this function is extremely low. Use it carefully.
*/
void PostDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx);
/**
* @brief Check Object pointer validation and remove invalid pointers before deletion.
* @param objarray
* @param ctx
*/
void PreDeletedCheck(XList<CK2::ObjImpls::CKObject*>& objarray, CK2::CKContext* ctx);
/**
* @brief Check Object pointer validation and remove invalid pointers after deletion.
* @param objarray
* @param ctx
* @remark The performance of this function is extremely low. Use it carefully.
*/
void PostDeletedCheck(XList<CK2::ObjImpls::CKObject*>& objarray, CK2::CKContext* ctx);
}
}