SaveSizeCounter is introduced and used for calculating the save size of objects. The previous method of calculating save size directly in each class was replaced with a call to the SaveSizeCounter's calc method. This results in a cleaner, more maintainable code as the size calculation logic is now centralized in one class. It is more efficient and scalable as any changes to the calculation can be made in one place and will be reflected everywhere.
417 lines
No EOL
9.5 KiB
C++
417 lines
No EOL
9.5 KiB
C++
|
|
|
|
#include "NewPlacement.hpp"
|
|
#include "core/object.h"
|
|
|
|
#include "HeapAllocatorGlobal.hpp"
|
|
|
|
#include <malloc.h>
|
|
|
|
namespace obj {
|
|
|
|
ObjectMemHead* bottom = nullptr;
|
|
|
|
struct ObjectsFileHeader {
|
|
char name[10] = {0};
|
|
char version[10] = {0};
|
|
|
|
ObjectsFileHeader(bool default_val = true) {
|
|
if (default_val) {
|
|
tp::memCopy(&name, "objects", tp::String::Logic::calcLength("objects") + 1);
|
|
tp::memCopy(&version, "0", tp::String::Logic::calcLength("0") + 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
Object* ObjectMemAllocate(const ObjectType* type) {
|
|
ObjectMemHead* memh = (ObjectMemHead*) tp::HeapAllocGlobal::allocate(type->size + sizeof(ObjectMemHead));
|
|
if (!memh) {
|
|
return NULL;
|
|
}
|
|
|
|
memh->down = NULL;
|
|
memh->flags = 0;
|
|
|
|
#ifdef OBJECT_REF_COUNT
|
|
memh->refc = (tp::alni) 1;
|
|
#endif
|
|
|
|
if (bottom) {
|
|
bottom->down = memh;
|
|
}
|
|
memh->up = bottom;
|
|
bottom = memh;
|
|
|
|
NDO_FROM_MEMH(memh)->type = type;
|
|
return NDO_FROM_MEMH(memh);
|
|
}
|
|
|
|
void ObjectMemDeallocate(Object* in) {
|
|
ObjectMemHead* memh = ((ObjectMemHead*) in) - 1;
|
|
|
|
if (memh->up) {
|
|
memh->up->down = memh->down;
|
|
}
|
|
|
|
if (memh->down) {
|
|
memh->down->up = memh->up;
|
|
} else {
|
|
bottom = memh->up;
|
|
}
|
|
|
|
tp::HeapAllocGlobal::deallocate(memh);
|
|
}
|
|
|
|
struct ObjectFileHead {
|
|
Object* load_head_adress = 0;
|
|
tp::halni refc = 0;
|
|
};
|
|
|
|
tp::int1* loaded_file = nullptr;
|
|
|
|
|
|
void objects_api::clear_object_flags() {
|
|
// clear all object flags
|
|
for (ObjectMemHead* iter = bottom; iter; iter = iter->up) {
|
|
iter->flags = -1;
|
|
}
|
|
}
|
|
|
|
tp::alni& getObjectFlags(Object* in) {
|
|
return NDO_MEMH_FROM_NDO(in)->flags;
|
|
}
|
|
|
|
tp::alni objsize_ram_util(Object* self, const ObjectType* type) {
|
|
tp::alni out = 0;
|
|
|
|
if (type->allocated_size) {
|
|
out += type->allocated_size(self);
|
|
} else {
|
|
out += type->size - sizeof(ObjectType*);
|
|
}
|
|
|
|
if (type->base) {
|
|
out += objsize_ram_util(self, type->base);
|
|
} else {
|
|
out += sizeof(ObjectType*);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
tp::alni objects_api::objsize_ram(Object* self) {
|
|
return objsize_ram_util(self, self->type);
|
|
}
|
|
|
|
tp::alni objects_api::objsize_ram_recursive_util(Object* self, const ObjectType* type, bool different_object) {
|
|
tp::alni out = 0;
|
|
|
|
if (different_object) {
|
|
if (getObjectFlags(self) == 1) {
|
|
return 0;
|
|
}
|
|
|
|
getObjectFlags(self) = 1;
|
|
}
|
|
|
|
if (type->allocated_size_recursive) {
|
|
out += type->allocated_size_recursive(self);
|
|
} else {
|
|
if (type->allocated_size) {
|
|
out += type->allocated_size(self);
|
|
} else {
|
|
out += type->size - sizeof(ObjectType*);
|
|
}
|
|
}
|
|
|
|
if (type->base) {
|
|
out += objsize_ram_recursive_util(self, type->base, false);
|
|
} else {
|
|
out += sizeof(ObjectType*);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
tp::alni objects_api::objsize_ram_recursive(Object* self) {
|
|
clear_object_flags();
|
|
return objsize_ram_recursive_util(self, self->type);
|
|
}
|
|
|
|
tp::alni objsize_file_util(Object* self, const ObjectType* type) {
|
|
tp::alni out = 0;
|
|
|
|
if (type->save_size) {
|
|
out += type->save_size(self);
|
|
}
|
|
|
|
if (type->base) {
|
|
out += objsize_file_util(self, type->base);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
tp::alni objects_api::objsize_file(Object* self) {
|
|
return objsize_file_util(self, self->type);
|
|
}
|
|
|
|
tp::alni objsize_file_recursive_util(Object* self, const ObjectType* type) {
|
|
tp::alni out = 0;
|
|
|
|
getObjectFlags(self) = 1;
|
|
|
|
if (type->save_size) {
|
|
out += type->save_size(self);
|
|
}
|
|
|
|
if (type->childs_retrival) {
|
|
tp::Buffer<Object*> childs = type->childs_retrival(self);
|
|
for (auto child : childs) {
|
|
if (getObjectFlags(child.data()) != 1) {
|
|
out += objsize_file_recursive_util(child.data(), child.data()->type);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type->base) {
|
|
out += objsize_file_recursive_util(self, type->base);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
tp::alni objects_api::objsize_file_recursive(Object* self) {
|
|
clear_object_flags();
|
|
return objsize_file_recursive_util(self, self->type);
|
|
}
|
|
|
|
void object_recursive_save(ArchiverOut& ndf, Object* self, const ObjectType* type) {
|
|
if (type->base) {
|
|
object_recursive_save(ndf, self, type->base);
|
|
}
|
|
|
|
// automatically offsets for parent type to write
|
|
if (type->save) {
|
|
type->save(self, ndf);
|
|
}
|
|
}
|
|
|
|
tp::alni objects_api::save(ArchiverOut& ndf, Object* in) {
|
|
// if already saved return file_adress
|
|
if (NDO_MEMH_FROM_NDO(in)->flags != -1) {
|
|
return NDO_MEMH_FROM_NDO(in)->flags;
|
|
}
|
|
|
|
// save write adress for parent save function call
|
|
tp::alni tmp_adress = ndf.getAddress();
|
|
|
|
// save requested object to first available adress
|
|
tp::alni save_adress = ndf.getFreeAddress();
|
|
|
|
// save file_adress in memhead
|
|
NDO_MEMH_FROM_NDO(in)->flags = save_adress;
|
|
|
|
// update write adress
|
|
ndf.setAddress(save_adress);
|
|
|
|
// save file object header
|
|
ObjectFileHead ofh = { 0, getrefc(in) };
|
|
ndf << ofh;
|
|
ndf << tp::String(in->type->name);
|
|
|
|
// allocate for object file header
|
|
ndf.setFreeAddress(ndf.getFreeAddress() + sizeof(ObjectFileHead) + tp::SaveSizeCounter::calc(tp::String(in->type->name)));
|
|
|
|
// calc max size needed for saving all hierarchy of types
|
|
tp::alni file_alloc_size = objsize_file_util(in, in->type);
|
|
|
|
// offes first available adress
|
|
ndf.setFreeAddress(ndf.getFreeAddress() + file_alloc_size);
|
|
|
|
object_recursive_save(ndf, in, in->type);
|
|
|
|
// restore adress for parent save function
|
|
ndf.setAddress(tmp_adress);
|
|
|
|
// return addres of saved object in file space
|
|
return save_adress;
|
|
}
|
|
|
|
void object_recursive_load(ArchiverIn& ndf, Object* out, const ObjectType* type) {
|
|
if (type->base) {
|
|
object_recursive_load(ndf, out, type->base);
|
|
}
|
|
|
|
// automatically offsets for parent type to read
|
|
if (type->load) {
|
|
type->load(ndf, out);
|
|
}
|
|
}
|
|
|
|
Object* objects_api::load(ArchiverIn& ndf, tp::alni file_adress) {
|
|
// check if already saved
|
|
if (((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress) {
|
|
return ((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress;
|
|
}
|
|
|
|
// save read address
|
|
tp::alni parent_file_adress = ndf.getAddress();
|
|
|
|
// set read address
|
|
ndf.setAddress(file_adress);
|
|
|
|
ObjectFileHead ofh;
|
|
ndf >> ofh;
|
|
|
|
tp::String type_name;
|
|
ndf >> type_name;
|
|
|
|
const ObjectType* object_type = NDO->types.get(type_name);
|
|
Object* out = ObjectMemAllocate(object_type);
|
|
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
setrefc(out, ofh.refc);
|
|
|
|
// save heap adress in "loaded_file"
|
|
((ObjectFileHead*) (loaded_file + file_adress))->load_head_adress = out;
|
|
|
|
// loads recursively
|
|
object_recursive_load(ndf, out, object_type);
|
|
|
|
// restore read address for parent call to continue
|
|
ndf.setAddress(parent_file_adress);
|
|
|
|
// return heap memory adress
|
|
return out;
|
|
}
|
|
|
|
bool objects_api::save(Object* in, tp::String path, bool compressed) {
|
|
ArchiverOut ndf(path.read());
|
|
|
|
if (!ndf.isOpened()) {
|
|
return false;
|
|
}
|
|
|
|
clear_object_flags();
|
|
|
|
// save version info
|
|
ObjectsFileHeader header;
|
|
ndf << header;
|
|
|
|
ndf.setFreeAddress(ndf.getAddress());
|
|
|
|
// pre allocate
|
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
|
if (sl_callbacks[i]) {
|
|
DEBUG_ASSERT(sl_callbacks[i]->size);
|
|
ndf.setFreeAddress(ndf.getFreeAddress() + sl_callbacks[i]->size(sl_callbacks[i]->self, ndf));
|
|
}
|
|
}
|
|
|
|
// pre-save
|
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
|
if (sl_callbacks[i] && sl_callbacks[i]->pre_save) {
|
|
sl_callbacks[i]->pre_save(sl_callbacks[i]->self, ndf);
|
|
}
|
|
}
|
|
|
|
save(ndf, in);
|
|
|
|
// post-save
|
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
|
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
|
sl_callbacks[i]->post_save(sl_callbacks[i]->self, ndf);
|
|
}
|
|
}
|
|
|
|
// TODO : add compression
|
|
/*
|
|
if (compressed) {
|
|
auto temp = path + ".bz2";
|
|
tp::compressF2F(path.read(), temp.cstr());
|
|
|
|
File::remove(path.read());
|
|
File::rename(temp.cstr(), path.read());
|
|
}
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
Object* objects_api::load(tp::String path) {
|
|
/*
|
|
auto temp_file_name = path + ".unz";
|
|
bool unz_res = tp::decompressF2F(path.cstr(), temp_file_name.cstr());
|
|
|
|
if (!unz_res) {
|
|
return NULL;
|
|
}
|
|
|
|
File ndf(temp_file_name.cstr(), tp::osfile_openflags::LOAD);
|
|
*/
|
|
|
|
ArchiverIn ndf(path.read());
|
|
|
|
if (!ndf.isOpened()) {
|
|
return NULL;
|
|
}
|
|
|
|
// check for compatibility
|
|
ObjectsFileHeader current_header;
|
|
ObjectsFileHeader loaded_header(false);
|
|
|
|
ndf >> loaded_header;
|
|
|
|
if (!tp::memEqual(¤t_header, &loaded_header, sizeof(ObjectsFileHeader))) {
|
|
return NULL;
|
|
}
|
|
|
|
ndf.setAddress(0);
|
|
|
|
const auto fileSize = ndf.getSize();
|
|
loaded_file = (tp::int1*) malloc(fileSize);
|
|
tp::memSetVal(loaded_file, fileSize, 0);
|
|
ndf.readBytes(loaded_file, fileSize);
|
|
|
|
ndf.setAddress(sizeof(ObjectsFileHeader));
|
|
|
|
// preload
|
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
|
if (sl_callbacks[i] && sl_callbacks[i]->pre_load) {
|
|
sl_callbacks[i]->pre_load(sl_callbacks[i]->self, ndf);
|
|
}
|
|
}
|
|
|
|
Object* out = load(ndf, ndf.getAddress());
|
|
|
|
// post
|
|
for (tp::alni i = 0; i < SAVE_LOAD_MAX_CALLBACK_SLOTS; i++) {
|
|
if (sl_callbacks[i] && sl_callbacks[i]->post_save) {
|
|
sl_callbacks[i]->post_load(sl_callbacks[i]->self, ndf);
|
|
}
|
|
}
|
|
|
|
free(loaded_file);
|
|
|
|
/*
|
|
ndf.close();
|
|
|
|
if (unz_res == NULL) {
|
|
File::remove(temp_file_name.cstr());
|
|
}
|
|
*/
|
|
|
|
setrefc(out, 0);
|
|
|
|
return out;
|
|
}
|
|
|
|
void objects_api::add_sl_callbacks(save_load_callbacks* in) {
|
|
sl_callbacks[sl_callbacks_load_idx] = in;
|
|
sl_callbacks_load_idx++;
|
|
}
|
|
}; |