Files

217 lines
6.1 KiB
C++

#include "gamelib/class.h"
#include "idlib/lib_print.h"
#include "idlib/text/str.h"
namespace {
idTypeInfo *typeList = nullptr;
idHierarchy<idTypeInfo> classHierarchy;
int NumberTypeHierarchy(idHierarchy<idTypeInfo> *node, int nextType) {
for (idHierarchy<idTypeInfo> *current = node; current != nullptr;
current = current->sibling) {
idTypeInfo *type = current->owner;
if (type == nullptr) {
continue;
}
type->typeNum = nextType++;
nextType = NumberTypeHierarchy(current->child, nextType);
type->lastChild = nextType - 1;
}
return nextType;
}
} // namespace
bool idClass::initialized = false;
int idClass::typeNumBits = 0;
int idClass::memused = 0;
int idClass::numobjects = 0;
idList<idTypeInfo *, 51> idClass::types(16);
idList<idTypeInfo *, 51> idClass::typenums(16);
idClass::~idClass() = default;
idTypeInfo::idTypeInfo(const char *classname_, const char *superclass_,
const int size_, const bool abstract_,
const createInstance_t createInstance_, const spawn_t spawn_)
: classname(classname_)
, superclass(superclass_)
, CreateInstance(createInstance_)
, Spawn(spawn_)
, initialized(false)
, super(idClass::GetClass(superclass_))
, next(nullptr)
, isAbstract(abstract_)
, size(size_)
, typeNum(0)
, lastChild(0)
, node(nullptr) {
for (idTypeInfo *type = typeList; type != nullptr; type = type->next) {
if (type->super == nullptr && type->superclass != nullptr
&& idStr::Cmp(type->superclass, classname) == 0
&& idStr::Cmp(type->classname, "idClass") != 0) {
type->super = this;
}
}
idTypeInfo **link = &typeList;
while (*link != nullptr && idStr::Cmp(classname, (*link)->classname) >= 0) {
link = &(*link)->next;
}
next = *link;
*link = this;
}
idTypeInfo::~idTypeInfo() {
node.RemoveFromHierarchy();
}
void idTypeInfo::Init() {
if (initialized) {
return;
}
if (super != nullptr && !super->initialized) {
super->Init();
}
node.ParentTo(super != nullptr ? super->node : classHierarchy);
node.SetOwner(this);
for (idTypeInfo *ancestor = super; ancestor != nullptr;
ancestor = ancestor->super) {
++ancestor->lastChild;
}
initialized = true;
}
idClass::spawn_t idClass::CallSpawnFunc(idTypeInfo *type) {
if (type == nullptr) {
return nullptr;
}
const spawn_t inherited = type->super != nullptr
? CallSpawnFunc(type->super)
: nullptr;
if (type->Spawn != nullptr && inherited != type->Spawn) {
type->Spawn(this);
return type->Spawn;
}
return inherited;
}
void idClass::CallSpawn() {
idTypeInfo *type = GetType();
if (type == nullptr) {
return;
}
const spawn_t inherited = type->super != nullptr
? CallSpawnFunc(type->super)
: nullptr;
if (type->Spawn != nullptr && inherited != type->Spawn) {
type->Spawn(this);
}
}
const char *idClass::GetClassname() const {
idTypeInfo *type = const_cast<idClass*>(this)->GetType();
return type != nullptr ? type->classname : nullptr;
}
bool idClass::IsType(const idTypeInfo& superclass) const {
idTypeInfo *type = const_cast<idClass*>(this)->GetType();
return type != nullptr && type->typeNum >= superclass.typeNum
&& type->typeNum <= superclass.lastChild;
}
idTypeInfo *idClass::GetClass(const char *name) {
if (name == nullptr) {
return nullptr;
}
if (!initialized) {
for (idTypeInfo *type = typeList; type != nullptr; type = type->next) {
if (idStr::Cmp(type->classname, name) == 0) {
return type;
}
}
return nullptr;
}
int lower = 0;
int upper = types.Num() - 1;
while (lower <= upper) {
const int middle = (lower + upper) / 2;
idTypeInfo *type = types[middle];
const int comparison = idStr::Cmp(type->classname, name);
if (comparison == 0) {
return type;
}
if (comparison < 0) {
lower = middle + 1;
} else {
upper = middle - 1;
}
}
return nullptr;
}
idClass *idClass::CreateInstance(const char *name) {
idTypeInfo *type = GetClass(name);
return type != nullptr && type->CreateInstance != nullptr
? type->CreateInstance()
: nullptr;
}
void idClass::DisplayInfo_f(const idCmdArgs&) {
idLibPrint::Printf("Class memory status: %i bytes allocated in %i objects\n",
memused, numobjects);
}
void idClass::ListClasses_f(const idCmdArgs&) {
idLibPrint::Printf("%-24s %-24s %-6s %-6s\n",
"Classname", "Superclass", "Type", "Subclasses");
idLibPrint::Printf(
"----------------------------------------------------------------------\n");
for (int index = 0; index < types.Num(); ++index) {
const idTypeInfo *type = types[index];
idLibPrint::Printf("%-24s %-24s %6d %6d\n", type->classname,
type->superclass, type->typeNum, type->lastChild - type->typeNum);
}
idLibPrint::Printf("...%d classes", types.Num());
}
void idClass::Init() {
idLibPrint::Printf("Initializing class hierarchy\n");
if (initialized) {
idLibPrint::Printf("...already initialized\n");
return;
}
for (idTypeInfo *type = typeList; type != nullptr; type = type->next) {
type->Init();
}
const int count = NumberTypeHierarchy(classHierarchy.child, 0);
typeNumBits = 0;
while ((1u << typeNumBits) < static_cast<unsigned int>(count)
&& typeNumBits < 31) {
++typeNumBits;
}
types.SetNum(count);
typenums.SetNum(count);
int sortedIndex = 0;
for (idTypeInfo *type = typeList; type != nullptr; type = type->next) {
if (sortedIndex < count) {
types[sortedIndex++] = type;
}
if (type->typeNum >= 0 && type->typeNum < count) {
typenums[type->typeNum] = type;
}
}
initialized = true;
}
void idClass::Shutdown() {
types.ClearFree();
typenums.ClearFree();
initialized = false;
}