basically finish register. still have bug

This commit is contained in:
yyc12345 2023-09-17 12:39:21 +08:00
parent 230b18c0ba
commit c6608dec57
10 changed files with 396 additions and 101 deletions

View File

@ -162,7 +162,7 @@ namespace LibCmo::CK2 {
for (CKDWORD i = 0; i < slotcount; ++i) {
CreateImage(width, height, i);
if (ReadSpecificFormatBitmap(chunk, GetImageDesc(i))) {
hasReadSlot[i] = true;
XContainer::NSXBitArray::Set(hasReadSlot, i);
} else {
ReleaseImage(i);
}
@ -183,7 +183,7 @@ namespace LibCmo::CK2 {
for (CKDWORD i = 0; i < slotcount; ++i) {
VxMath::VxImageDescEx rawcache;
if (ReadRawBitmap(chunk, &rawcache)) {
hasReadSlot[i] = true;
XContainer::NSXBitArray::Set(hasReadSlot, i);
// do upside down blit
CreateImage(rawcache.GetWidth(), rawcache.GetHeight(), i);
@ -202,7 +202,7 @@ namespace LibCmo::CK2 {
// MARK: a rough implement because we do not support this identifier
for (CKDWORD i = 0; i < slotcount; ++i) {
if (ReadOldRawBitmap(chunk, GetImageDesc(i))) {
hasReadSlot[i] = true;
XContainer::NSXBitArray::Set(hasReadSlot, i);
} else {
ReleaseImage(i);
}
@ -224,7 +224,7 @@ namespace LibCmo::CK2 {
chunk->ReadString(filename);
if (filename.empty()) continue;
bool isNotLoaded = (i >= hasReadSlot.size()) || (!hasReadSlot[i]);
bool isNotLoaded = (i >= hasReadSlot.size()) || (!XContainer::NSXBitArray::IsSet(hasReadSlot, i));
if (isNotLoaded) {
// if this image is not loaded.
// try resolve its file name and load it.

View File

@ -8,6 +8,7 @@
#include "CKGlobals.hpp"
#include <algorithm>
#include <initializer_list>
#include "ObjImpls/CKObject.hpp"
#include "ObjImpls/CKSceneObject.hpp"
@ -110,6 +111,20 @@ namespace LibCmo::CK2 {
#pragma region CKClass Registration
static XContainer::XArray<CKClassDesc> g_CKClassInfo;
static bool GetClassIdIndex(CK_CLASSID cid, size_t& intcid) {
intcid = static_cast<size_t>(cid);
if (intcid >= g_CKClassInfo.size()) return false;
if (!g_CKClassInfo[intcid].IsValid) return false;
return true;
}
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo) {
size_t idxListener, idxListenTo;
if (!GetClassIdIndex(listener, idxListener) || !GetClassIdIndex(listenTo, idxListenTo)) return;
XContainer::NSXBitArray::Set(g_CKClassInfo[idxListener].ToBeNotify, static_cast<CKDWORD>(idxListenTo));
}
CK_CLASSID CKClassGetNewIdentifier() {
size_t classsize = g_CKClassInfo.size();
@ -120,64 +135,8 @@ namespace LibCmo::CK2 {
}
}
static void ComputeParentsTable(CKClassDesc& desc) {
// if it has done, do not process it again.
if (desc.Done) return;
// find direct parent
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
// if it is not self inheritance, call recursively
if (desc.Self != desc.Parent) {
ComputeParentsTable(parent);
}
// copy parent's parents
desc.Parents = parent.Parents;
// and set self as its parent
desc.Parents[static_cast<size_t>(desc.Self)] = true;
// set derivation level
desc.DerivationLevel = parent.DerivationLevel + 1;
// set done
desc.Done = true;
}
static void CKBuildClassHierarchyTable() {
// set Done to false and resize all XBitArray
size_t classCount = g_CKClassInfo.size();
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
item.Done = false;
item.Parents.resize(classCount, false);
item.Children.resize(classCount, false);
}
// compute parents
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
ComputeParentsTable(item);
}
// compute children by parents table
// iterate CKClassDesc::Parents and register it self to gotten parents
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
for (size_t idx = 0; idx < classCount; ++idx) {
if (!g_CKClassInfo[idx].IsValid) continue;
// if this idx is its parent,
// add self to parent.
if (item.Parents[idx]) {
g_CKClassInfo[idx].Children[static_cast<size_t>(item.Self)] = true;
}
}
}
}
void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid,
CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct) {
CKClassRegisterFct regFct, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct) {
// resize class desc array
size_t intcid = static_cast<size_t>(cid);
@ -190,6 +149,7 @@ namespace LibCmo::CK2 {
desc.IsValid = true;
desc.Self = cid;
desc.Parent = parentCid;
desc.RegisterFct = regFct;
desc.CreationFct = createFct;
desc.ReleaseFct = relFct;
desc.NameFct = nameFct;
@ -200,13 +160,6 @@ namespace LibCmo::CK2 {
#pragma region Class Hierarchy Management
static bool GetClassIdIndex(CK_CLASSID cid, size_t& intcid) {
intcid = static_cast<size_t>(cid);
if (intcid >= g_CKClassInfo.size()) return false;
if (!g_CKClassInfo[intcid].IsValid) return false;
return true;
}
CKDWORD CKGetClassCount() {
return static_cast<CKDWORD>(g_CKClassInfo.size());
}
@ -248,18 +201,172 @@ namespace LibCmo::CK2 {
return cid1;
}
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid) {
const CKClassDesc* desc = CKGetClassDesc(listener);
if (desc == nullptr) return false;
return XContainer::NSXBitArray::IsSet(desc->CommonToBeNotify, static_cast<CKDWORD>(deletedObjCid));
}
XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids) {
XContainer::XBitArray result;
for (size_t i = 0; i < delObjCids.size(); ++i) {
if (!XContainer::NSXBitArray::IsSet(delObjCids, static_cast<CKDWORD>(i))) continue;
const CKClassDesc* desc = CKGetClassDesc(static_cast<CK_CLASSID>(i));
if (desc == nullptr) continue;
XContainer::NSXBitArray::Or(result, desc->ToNotify);
}
return result;
}
#pragma endregion
#pragma region Initializations functions
CKERROR CKStartUp() {
static void ComputeParentsTable(CKClassDesc& desc) {
// if it has done, do not process it again.
if (desc.Done) return;
// find direct parent
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
// if it is not self inheritance, call recursively
if (desc.Self != desc.Parent) {
ComputeParentsTable(parent);
}
// copy parent's parents
desc.Parents = parent.Parents;
// and set self as its parent
XContainer::NSXBitArray::Set(desc.Parents, static_cast<CKDWORD>(desc.Self));
// set derivation level
desc.DerivationLevel = parent.DerivationLevel + 1;
// set done
desc.Done = true;
}
static void ComputeParentsNotifyTable(CKClassDesc& desc) {
// if it has done, do not process it again.
if (desc.Done) return;
// find direct parent
CKClassDesc& parent = g_CKClassInfo[static_cast<size_t>(desc.Parent)];
if (!parent.IsValid) LIBPANIC("No such CK_CLASSID.");
// if it is not self inheritance, call recursively
if (desc.Self != desc.Parent) {
ComputeParentsNotifyTable(parent);
}
// copy self notify first
desc.CommonToBeNotify = desc.ToBeNotify;
// and merge parent notify list
XContainer::NSXBitArray::Or(desc.CommonToBeNotify, parent.CommonToBeNotify);
// set done
desc.Done = true;
}
static void CKBuildClassHierarchyTable() {
size_t classCount = g_CKClassInfo.size();
// ===== Build Inhertance Hierarchy =====
// set Done to false and resize inhertance XBitArray
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
item.Done = false;
XContainer::NSXBitArray::Resize(item.Parents, static_cast<CKDWORD>(classCount));
XContainer::NSXBitArray::Resize(item.Children, static_cast<CKDWORD>(classCount));
}
// compute parents
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
ComputeParentsTable(item);
}
// compute children by parents table
// iterate CKClassDesc::Parents and register it self to gotten parents
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
for (size_t idx = 0; idx < classCount; ++idx) {
if (!g_CKClassInfo[idx].IsValid) continue;
// if this idx is its parent,
// add self to parent.
if (XContainer::NSXBitArray::IsSet(item.Parents, static_cast<CKDWORD>(idx))) {
XContainer::NSXBitArray::Set(g_CKClassInfo[idx].Children, static_cast<CKDWORD>(item.Self));
}
}
}
// ===== Register =====
// run register
for (auto& item : g_CKClassInfo) {
if (!item.IsValid || item.RegisterFct == nullptr) continue;
item.RegisterFct();
}
// ===== Build Notify Hierarchy =====
// set Done to false and resize notify XBitArray
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
item.Done = false;
XContainer::NSXBitArray::Resize(item.ToBeNotify, static_cast<CKDWORD>(classCount));
XContainer::NSXBitArray::Resize(item.CommonToBeNotify, static_cast<CKDWORD>(classCount));
XContainer::NSXBitArray::Resize(item.ToNotify, static_cast<CKDWORD>(classCount));
}
// compute notify
for (auto& item : g_CKClassInfo) {
if (!item.IsValid) continue;
ComputeParentsNotifyTable(item);
}
// compute ToNotify table
// for each desc(represented as outter 'for'), iterate all desc(represented as inner 'for'), and check whether its
// CommonToBeNotify contain this desc. If true, add checking desc into this desc's ToNotify.
for (size_t idx = 0; idx < classCount; ++idx) {
if (!g_CKClassInfo[idx].IsValid) continue;
for (const auto& checkingDesc : g_CKClassInfo) {
if(!checkingDesc.IsValid) continue;
// if checkingDesc's CommonToBeNotify order this desc,
// add checking desc to ToNofity
if (XContainer::NSXBitArray::IsSet(checkingDesc.CommonToBeNotify, static_cast<CKDWORD>(idx))) {
XContainer::NSXBitArray::Set(g_CKClassInfo[idx].ToNotify, static_cast<CKDWORD>(checkingDesc.Self));
}
}
}
}
static void NeedNotificationWrapper(CK_CLASSID thiscid, std::initializer_list<CK_CLASSID> il) {
for (auto it = il.begin(); it != il.end(); ++it) {
CKClassNeedNotificationFrom(thiscid, *it);
}
}
CKERROR CKStartUp() {
// reserve class info array.
g_CKClassInfo.reserve(static_cast<size_t>(CK_CLASSID::CKCID_MAXCLASSID));
// todo: add class type registrations
#define EasyClassReg(clsname, cid, parentCid, strName) \
CKClassRegister(cid, parentCid, \
nullptr, \
[](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new clsname(ctx, id, name); }, \
[](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, \
[]() -> CKSTRING { return strName; });
#define EasyClassRegWithNotify(clsname, cid, parentCid, strName, notifyCids) \
CKClassRegister(cid, parentCid, \
[]() -> void { NeedNotificationWrapper(cid, notifyCids); }, \
[](CKContext* ctx, CK_ID id, CKSTRING name) -> ObjImpls::CKObject* { return new clsname(ctx, id, name); }, \
[](CKContext* ctx, ObjImpls::CKObject* obj) -> void { delete obj; }, \
[]() -> CKSTRING { return strName; });
@ -267,7 +374,7 @@ CKClassRegister(cid, parentCid, \
EasyClassReg(ObjImpls::CKObject, CK_CLASSID::CKCID_OBJECT, CK_CLASSID::CKCID_OBJECT, "Basic Object");
EasyClassReg(ObjImpls::CKSceneObject, CK_CLASSID::CKCID_SCENEOBJECT, CK_CLASSID::CKCID_OBJECT, "Scene Object");
EasyClassReg(ObjImpls::CKBeObject, CK_CLASSID::CKCID_BEOBJECT, CK_CLASSID::CKCID_SCENEOBJECT, "Behavioral Object");
EasyClassReg(ObjImpls::CKGroup, CK_CLASSID::CKCID_GROUP, CK_CLASSID::CKCID_BEOBJECT, "Group");
EasyClassRegWithNotify(ObjImpls::CKGroup, CK_CLASSID::CKCID_GROUP, CK_CLASSID::CKCID_BEOBJECT, "Group", { CK_CLASSID::CKCID_BEOBJECT });
EasyClassReg(ObjImpls::CKRenderObject, CK_CLASSID::CKCID_RENDEROBJECT, CK_CLASSID::CKCID_BEOBJECT, "Render Object");
EasyClassReg(ObjImpls::CK3dEntity, CK_CLASSID::CKCID_3DENTITY, CK_CLASSID::CKCID_RENDEROBJECT, "3D Entity");
EasyClassReg(ObjImpls::CK3dObject, CK_CLASSID::CKCID_3DOBJECT, CK_CLASSID::CKCID_3DENTITY, "3D Object");
@ -275,6 +382,7 @@ CKClassRegister(cid, parentCid, \
EasyClassReg(ObjImpls::CKMaterial, CK_CLASSID::CKCID_MATERIAL, CK_CLASSID::CKCID_BEOBJECT, "Material");
#undef EasyClassReg
#undef EasyClassRegWithNotify
CKBuildClassHierarchyTable();

View File

@ -74,7 +74,7 @@ namespace LibCmo::CK2 {
// ========== Class registration utilities ==========
//using CKClassRegisterFct = std::function<void()>;
using CKClassRegisterFct = std::function<void()>;
using CKClassCreationFct = std::function<ObjImpls::CKObject* (CKContext*, CK_ID, CKSTRING)>;
using CKClassReleaseFct = std::function<void(CKContext*, ObjImpls::CKObject*)>;
using CKClassNameFct = std::function<CKSTRING()>;
@ -87,7 +87,7 @@ namespace LibCmo::CK2 {
// Initialized upon class registration
CK_CLASSID Self;
CK_CLASSID Parent; // Class Identifier of parent class
//CKClassRegisterFct RegisterFct; // Pointer to Class Specific Registration function
CKClassRegisterFct RegisterFct; // Pointer to Class Specific Registration function
CKClassCreationFct CreationFct; // Pointer to Class instance creation function
CKClassReleaseFct ReleaseFct; // Pointer to Class instance release function
CKClassNameFct NameFct; // Pointer to Class name function
@ -106,26 +106,27 @@ namespace LibCmo::CK2 {
CKINT DerivationLevel; // O => CKObject , etc..
XContainer::XBitArray Parents; // Bit Mask of parents classes
XContainer::XBitArray Children; // Bit Mask of children classes
//XContainer::XBitArray ToBeNotify; // Mask for Classes that should warn the objects of this class when they are deleted
//XContainer::XBitArray CommonToBeNotify; // idem but merged with sub classes masks
//XContainer::XSArray<CK_CLASSID> ToNotify; // List of ClassID to notify when an object of this class is deleted (inverse of ToBeNotify)
XContainer::XBitArray ToBeNotify; // User specified notify list, only for current class.
XContainer::XBitArray CommonToBeNotify; // Same as ToBeNotify, but merging all parents' notify list.
XContainer::XBitArray ToNotify; // The ClassID to notify when an object of this class is deleted (inverse of ToBeNotify)
CKClassDesc() :
IsValid(false),
Done(false),
Self(CK_CLASSID::CKCID_OBJECT), Parent(CK_CLASSID::CKCID_OBJECT),
CreationFct(nullptr), ReleaseFct(nullptr), NameFct(nullptr),
RegisterFct(nullptr), CreationFct(nullptr), ReleaseFct(nullptr), NameFct(nullptr),
DerivationLevel(0),
Parents(), Children()
Parents(), Children(), ToBeNotify(), CommonToBeNotify()
{}
LIBCMO_DEFAULT_COPY_MOVE(CKClassDesc);
};
// ========== CKClass Registration ==========
void CKClassNeedNotificationFrom(CK_CLASSID listener, CK_CLASSID listenTo);
CK_CLASSID CKClassGetNewIdentifier();
void CKClassRegister(CK_CLASSID cid, CK_CLASSID parentCid,
CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct);
CKClassRegisterFct regFct, CKClassCreationFct createFct, CKClassReleaseFct relFct, CKClassNameFct nameFct);
// ========== Class Hierarchy Management ==========
@ -137,6 +138,21 @@ namespace LibCmo::CK2 {
CK_CLASSID CKGetParentClassID(CK_CLASSID child);
CK_CLASSID CKGetCommonParent(CK_CLASSID cid1, CK_CLASSID cid2);
/**
* @brief Check whether 'listener' need notified by the deletion of 'deletedObjCid'
* @param listener
* @param deletedObjCid
* @return true if need notify
*/
bool CKIsNeedNotify(CK_CLASSID listener, CK_CLASSID deletedObjCid);
/**
* @brief Get all object cid need to be notified when 'delObjCids' matched objects are deleting.
* @param delObjCids
* @param cidCount
* @return
*/
XContainer::XBitArray CKGetAllNotifyClassID(const XContainer::XBitArray& delObjCids);
// ========== Initializations functions ==========
CKERROR CKStartUp();
CKERROR CKShutdown();

View File

@ -72,30 +72,73 @@ namespace LibCmo::CK2::MgrImpls {
}
void CKObjectManager::DestroyObjects(CK_ID* ids, CKDWORD count) {
// notice pre
// pre notice manager
m_Context->ExecuteManagersOnSequenceToBeDeleted(ids, count);
// collect object data
// remove invalid object first, set them to be deleted
// collection deleted object class ids
XContainer::XObjectArray validObjIds;
XContainer::XBitArray cids;
for (CKDWORD i = 0; i < count; ++i) {
CKDWORD off = Id2Offset(ids[i]);
if (off >= m_ObjectsList.size()) continue;
// get object and its classid for future use
ObjImpls::CKObject* obj = m_ObjectsList[off];
if (obj == nullptr) continue;
CK_CLASSID cls = obj->GetClassID();
// set to be deleted
CK_OBJECT_FLAGS objflag = obj->GetObjectFlags();
EnumsHelper::Add(objflag, CK_OBJECT_FLAGS::CK_OBJECT_TOBEDELETED);
obj->SetObjectFlags(objflag);
// collect class id
XContainer::NSXBitArray::Set(cids, static_cast<CKDWORD>(obj->GetClassID()));
// add into list
validObjIds.emplace_back(ids[i]);
}
// then remove deleted object from m_ObjectListByClass
// because we have set to be deleted flag.
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
if (!XContainer::NSXBitArray::IsSet(cids, static_cast<CKDWORD>(i)))
continue;
XContainer::NSXObjectArray::PreDeletedCheck(m_ObjectsListByClass[i], m_Context);
}
// use collected cid to get all class ids which need receive notify
// and use m_ObjectListByClass to notify them
XContainer::XBitArray notifyCids = CKGetAllNotifyClassID(cids);
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
if (!XContainer::NSXBitArray::IsSet(notifyCids, static_cast<CKDWORD>(i)))
continue;
for (auto& objid : m_ObjectsListByClass[i]) {
m_ObjectsList[Id2Offset(objid)]->CheckPreDeletion();
}
}
// then free all valid object
for (const auto& objid : validObjIds) {
CKDWORD off = Id2Offset(objid);
ObjImpls::CKObject* obj = m_ObjectsList[off];
// free it
InternalDestroy(obj);
// return its allocated id.
// and dec count
m_ObjectsList[off] = nullptr;
m_ReturnedObjectOffsets.emplace_back(off);
--m_ObjectCount;
}
// remove from classid indexed list
std::erase(m_ObjectsListByClass[static_cast<size_t>(cls)], ids[i]);
// run post deletion for notify object
for (size_t i = 0; i < m_ObjectsListByClass.size(); ++i) {
if (!XContainer::NSXBitArray::IsSet(notifyCids, static_cast<CKDWORD>(i)))
continue;
for (auto& objid : m_ObjectsListByClass[i]) {
m_ObjectsList[Id2Offset(objid)]->CheckPostDeletion();
}
}
// notice post
@ -156,6 +199,8 @@ namespace LibCmo::CK2::MgrImpls {
return result;
}
#pragma region Object Check
bool CKObjectManager::IsObjectSafe(CK_ID objid) {
CKDWORD off = Id2Offset(objid);
if (off >= m_ObjectsList.size()) return false;
@ -171,6 +216,10 @@ namespace LibCmo::CK2::MgrImpls {
}
return false;
}
#pragma endregion
#pragma region Special Functions
CKDWORD CKObjectManager::AllocateGroupGlobalIndex() {
// try find first non-true position
@ -182,7 +231,7 @@ namespace LibCmo::CK2::MgrImpls {
}
// set to occupy
m_GroupGlobalIndex[index] = true;
XContainer::NSXBitArray::Set(m_GroupGlobalIndex, index);
return index;
}
@ -194,7 +243,7 @@ namespace LibCmo::CK2::MgrImpls {
m_SceneGlobalIndex.resize(m_SceneGlobalIndex.size() + 1);
}
m_SceneGlobalIndex[index] = true;
XContainer::NSXBitArray::Set(m_SceneGlobalIndex, index);
return index;
}
@ -202,13 +251,15 @@ namespace LibCmo::CK2::MgrImpls {
// check position
if (id >= m_GroupGlobalIndex.size()) return;
// set value
m_GroupGlobalIndex[id] = false;
XContainer::NSXBitArray::Unset(m_GroupGlobalIndex, id);
}
void CKObjectManager::FreeSceneGlobalIndex(CKDWORD id) {
// same as group
if (id >= m_SceneGlobalIndex.size()) return;
m_SceneGlobalIndex[id] = false;
XContainer::NSXBitArray::Unset(m_SceneGlobalIndex, id);
}
#pragma endregion
}

View File

@ -37,13 +37,15 @@ namespace LibCmo::CK2::ObjImpls {
bool CKBeObject::IsInGroup(CKGroup* group) {
if (group == nullptr) return false;
CKDWORD idx = group->GetGroupIndex();
if (idx >= m_Groups.size()) return false;
return m_Groups[idx];
return XContainer::NSXBitArray::IsSet(m_Groups, idx);
}
void CKBeObject::ExplicitSetGroup(CKDWORD pos, bool val) {
if (pos >= m_Groups.size()) m_Groups.resize(pos + 1);
m_Groups[pos] = val;
if (val) {
XContainer::NSXBitArray::Set(m_Groups, pos);
} else {
XContainer::NSXBitArray::Unset(m_Groups, pos);
}
}
}

View File

@ -3,6 +3,8 @@
namespace LibCmo::CK2::ObjImpls {
void CKObject::CheckPreDeletion() {}
void CKObject::CheckPostDeletion() {}
void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {}

View File

@ -68,6 +68,8 @@ namespace LibCmo::CK2::ObjImpls {
virtual CK_CLASSID GetClassID(void) {
return CK_CLASSID::CKCID_OBJECT;
}
virtual void CheckPreDeletion();
virtual void CheckPostDeletion();
virtual void PreSave(CKFileVisitor* file, CKDWORD flags);
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags);
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file);

View File

@ -75,6 +75,10 @@ namespace LibCmo {
#define LIBPANIC(msg) LibCmo::LibPanic(__LINE__, __FILE__, msg);
namespace EnumsHelper {
/**
* @brief Return 'e1 | e2 | ... | en'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Merge(std::initializer_list<TEnum> il) {
std::underlying_type_t<TEnum> result = 0;
@ -84,26 +88,41 @@ namespace LibCmo {
return static_cast<TEnum>(result);
}
/**
* @brief Return '~(e)'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Inv(TEnum e) {
return static_cast<TEnum>(~(static_cast<std::underlying_type_t<TEnum>>(e)));
}
/**
* @brief Operate e1 &= (~e2)
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline void Rm(TEnum& e1, TEnum e2) {
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(Inv(e2)));
}
/**
* @brief Operate e1 &= e2
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline void Mask(TEnum& e1, TEnum e2) {
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) & static_cast<std::underlying_type_t<TEnum>>(e2));
}
/**
* @brief Operate e1 |= e2
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline void Add(TEnum& e1, TEnum e2) {
e1 = static_cast<TEnum>(static_cast<std::underlying_type_t<TEnum>>(e1) | static_cast<std::underlying_type_t<TEnum>>(e2));
}
/**
* @brief Return 'bool(e1 & e2)'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline bool Has(TEnum e, TEnum probe) {
return static_cast<bool>(static_cast<std::underlying_type_t<TEnum>>(e) & static_cast<std::underlying_type_t<TEnum>>(probe));

View File

@ -8,6 +8,37 @@ namespace LibCmo::XContainer {
namespace NSXBitArray {
void Resize(XBitArray& ba, CKDWORD newsize) {
ba.resize(newsize, false);
}
void Or(XBitArray& thisba, const XBitArray& thatba) {
if (thisba.size() < thatba.size()) {
Resize(thisba, static_cast<CKDWORD>(thatba.size()));
}
for (size_t i = 0; i < thisba.size(); ++i) {
thisba[i] = thisba[i] || thatba[i];
}
}
bool IsSet(const XBitArray& ba, CKDWORD n) {
if (n >= ba.size()) return false;
return ba[n];
}
void Set(XBitArray& ba, CKDWORD n) {
if (n >= ba.size()) {
ba.resize(n + 1);
}
ba[n] = true;
}
void Unset(XBitArray& ba, CKDWORD n) {
if (n >= ba.size()) return;
ba[n] = false;
}
template<bool _Cond>
bool GeneralGetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got) {
CKDWORD counter = 0;
@ -93,6 +124,21 @@ namespace LibCmo::XContainer {
return GeneralXArrayCheck_ItemCheck<CK2::CK_ID, false>(item, ctx);
});
}
void PreDeletedCheck(XList<CK2::CK_ID>& 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(XList<CK2::CK_ID>& 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 {

View File

@ -80,15 +80,50 @@ namespace LibCmo::XContainer {
// ========== Patch Section ==========
namespace NSXBitArray {
/**
* @brief Resize XBitArray to the new size. Initial value is false.
* @param ba The XBitArray
* @param newsize New Size
*/
void Resize(XBitArray& ba, CKDWORD newsize);
/**
* @brief Returns the position of the n-th set(1) bit
* @return false if not found.
* @brief Merge other XBitArray to this XBitArray with OR condition.
* This XBitArray will be resized at least equal with merged XBitArray if its size is lower than merged XBitArray
* @param thisba This XBitArray
* @param thatba Other XBitArray will be merged.
*/
void Or(XBitArray& thisba, const XBitArray& thatba);
/**
* @brief Check whether bit flag is set.
* @param ba The XBitArray
* @param n The check position.
* @return True if set. False if not set or out of range.
*/
bool IsSet(const XBitArray& ba, CKDWORD n);
/**
* @brief Set specified position to true in XBitArray. Auto resize if no space to set.
* @param ba The XBitArray
* @param n The set position.
*/
void Set(XBitArray& ba, CKDWORD n);
/**
* @brief Unset specified position to true in XBitArray. If out of range, simply return.
* @param ba The XBitArray
* @param n The unset position.
*/
void Unset(XBitArray& ba, CKDWORD n);
/**
* @brief Returns the position of the n-th set(1) bit
* @return false if not found.
*/
bool GetSetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got);
/**
* @brief Returns the position of the n-th unset(0) bit
* @return false if not found.
* @brief Returns the position of the n-th unset(0) bit
* @return false if not found.
*/
bool GetUnsetBitPosition(const XBitArray& ba, CKDWORD n, CKDWORD& got);
@ -126,6 +161,20 @@ namespace LibCmo::XContainer {
* @param ctx
*/
void PostDeletedCheck(XObjectArray& objarray, CK2::CKContext* ctx);
/**
* @brief Check Object pointer validation and remove invalid pointers before deletion.
* @param objarray
* @param ctx
*/
void PreDeletedCheck(XList<CK2::CK_ID>& 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::CK_ID>& objarray, CK2::CKContext* ctx);
}