4coder/test_data/lots_of_files/cd_asset_manifest.cpp

477 lines
13 KiB
C++

/*
Asset manifest operations
-Allen
06.06.2016
*/
// TOP
inline rptr32
to_rptr32(void *pos, void *base){
rptr32 result = (rptr32)((char*)pos - (char*)base);
return(result);
}
inline void*
to_ptr(rptr32 pos, void *base){
void *result = ((char*)base + pos);
return(result);
}
inline Asset_Node*
to_node_ptr(rptr32 pos, void *base){
Asset_Node *result = (Asset_Node *)((char*)base + pos);
return(result);
}
inline Asset_Node*
get_node(i32 image_id, Asset_Manifest *manifest){
Asset_Node *node = to_node_ptr(manifest->asset_nodes, manifest);
node += image_id - 1;
return(node);
}
inline i32
get_image_id(rptr32 pos, Asset_Manifest *manifest){
i32 dist = (pos - manifest->asset_nodes);
Assert(dist % sizeof(Asset_Node) == 0);
dist = 1 + (dist/sizeof(Asset_Node));
return(dist);
}
void
init_sentinel(Asset_Node *node, void *base){
rptr32 self = to_rptr32(node, base);
node->next_sibling = self;
node->prev_sibling = self;
}
void
insert_node(Asset_Node *node, Asset_Node *pos, void *base){
rptr32 node_self = to_rptr32(node, base);
rptr32 pos_self = to_rptr32(pos, base);
rptr32 next_self = pos->next_sibling;
Asset_Node *next = to_node_ptr(next_self, base);
node->prev_sibling = pos_self;
node->next_sibling = next_self;
pos->next_sibling = node_self;
next->prev_sibling = node_self;
}
void
remove_node(Asset_Node *node, void *base){
rptr32 next_self = node->next_sibling;
rptr32 prev_self = node->prev_sibling;
Asset_Node *next = to_node_ptr(next_self, base);
Asset_Node *prev = to_node_ptr(prev_self, base);
next->prev_sibling = prev_self;
prev->next_sibling = next_self;
}
void
sibling_insert_before(Asset_Node *node, Asset_Node *pos, void *base){
rptr32 node_self = to_rptr32(node, base);
rptr32 pos_self = to_rptr32(pos, base);
rptr32 prev_self = pos->prev_sibling;
Asset_Node *prev = to_node_ptr(prev_self, base);
node->parent = pos->parent;
node->next_sibling = pos_self;
node->prev_sibling = prev_self;
pos->prev_sibling = node_self;
prev->next_sibling = node_self;
}
void
sibling_insert_after(Asset_Node *node, Asset_Node *pos, void *base){
rptr32 node_self = to_rptr32(node, base);
rptr32 pos_self = to_rptr32(pos, base);
rptr32 next_self = pos->next_sibling;
Asset_Node *next = to_node_ptr(next_self, base);
node->parent = pos->parent;
node->prev_sibling = pos_self;
node->next_sibling = next_self;
pos->next_sibling = node_self;
next->prev_sibling = node_self;
}
void
tree_remove(Asset_Node *node, void *base){
rptr32 parent_self = node->parent;
rptr32 node_self = to_rptr32(node, base);
rptr32 next_self = node->next_sibling;
rptr32 prev_self = node->prev_sibling;
Asset_Node *parent = to_node_ptr(parent_self, base);
Asset_Node *next = to_node_ptr(next_self, base);
Asset_Node *prev = to_node_ptr(prev_self, base);
next->prev_sibling = prev_self;
prev->next_sibling = next_self;
if (parent->first_child == node_self){
if (next_self != node_self){
parent->first_child = next_self;
}
else{
parent->first_child = 0;
}
}
}
void
insert_under(Asset_Node *node, Asset_Node *parent, void *base, b32 insert_as_first){
if (parent->first_child == 0){
rptr32 node_self = to_rptr32(node, base);
rptr32 parent_self = to_rptr32(parent, base);
parent->first_child = node_self;
node->next_sibling = node_self;
node->prev_sibling = node_self;
node->parent = parent_self;
}
else{
Asset_Node *first = to_node_ptr(parent->first_child, base);
sibling_insert_before(node, first, base);
if (insert_as_first){
rptr32 node_self = to_rptr32(node, base);
parent->first_child = node_self;
}
}
}
void
add_free_nodes(Asset_Manifest *manifest, Wrapped_Partition *part){
i32 node_count = (manifest->part.max - manifest->part.pos) / sizeof(Asset_Node);
if (node_count > 0){
Asset_Node *nodes = push_array(part, Asset_Node, node_count);
i32 j = manifest->asset_node_count + 1;
if (manifest->asset_nodes == 0){
manifest->asset_nodes = to_rptr32(nodes, manifest);
}
manifest->asset_node_count += node_count;
manifest->asset_free_count += node_count;
Asset_Node *node = nodes;
for (i32 i = 0; i < node_count; ++i, ++j, ++node){
insert_node(node, &manifest->free_sentinel, manifest);
node->image_id = j;
node->name[0] = 0;
}
}
}
void
initialize_empty_manifest(void *manifest_memory, i32 size){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
manifest->version = ASSET_MANIFEST_VERSION;
manifest->part = make_relative_partition(size);
Wrapped_Partition part_ = make_wrapped_partition(&manifest->part, manifest_memory);
Wrapped_Partition *part = &part_;
push_type(part, Asset_Manifest);
init_sentinel(&manifest->free_sentinel, manifest_memory);
manifest->asset_node_count = 0;
manifest->asset_free_count = 0;
add_free_nodes(manifest, part);
}
#define MANIFEST_NAME "CDmanifest"
Asset_Manifest*
manifest_load(System_API *system, Partition *part){
void *result = 0;
Temp_Memory temp = begin_temp(part);
File_Dump dump = system->DBG_dump_begin(MANIFEST_NAME);
if (dump.size > 0){
result = push_block(part, dump.size);
if (result == 0){
#ifdef DEVELOPER
DBG_expand_partition(system, part, dump.size);
result = push_block(part, dump.size);
#else
InvalidCodePath;
#endif
}
if (!system->DBG_dump_end(dump, result)){
end_temp(temp);
result = 0;
}
}
return((Asset_Manifest*)result);
}
#ifdef DEVELOPER
void
manifest_dump(System_API *system, void *base){
Asset_Manifest *manifest = (Asset_Manifest*)base;
i32 memory_size = manifest->part.max;
system->DBG_dump_out(MANIFEST_NAME, base, memory_size);
}
#endif
void
allocate_node(Asset_Manifest *manifest,
Asset_Node *node,
char *filename, i32 len){
--manifest->asset_free_count;
remove_node(node, manifest);
cd_memcpy(node->name, filename, len+1);
node->first_child = 0;
node->next_sibling = 0;
node->prev_sibling = 0;
}
void
free_node(Asset_Manifest *manifest,
Asset_Node *node){
++manifest->asset_free_count;
insert_node(node, &manifest->free_sentinel, manifest);
cd_memcpy(node->name, "", 0);
}
rptr32
declare_image(void *manifest_memory, char *filename, i32 image_id, i32 expect_empty){
rptr32 result = 0;
i32 len = 0;
len = cd_strlen(filename);
if (len != 0 && len < ASSET_MAX_NAME){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
Asset_Node *nodes = (Asset_Node*)
to_ptr(manifest->asset_nodes, manifest_memory);
Asset_Node *node = nodes + (image_id - 1);
if (node->name[0] == 0 && expect_empty){
allocate_node(manifest, node, filename, len);
result = to_rptr32(node, manifest_memory);
}
else if (node->name[0] != 0 && !expect_empty){
cd_memcpy(node->name, filename, len+1);
result = to_rptr32(node, manifest_memory);
}
}
return(result);
}
rptr32
bind_image(void *manifest_memory, Manifest_Setup *setup, char *filename, i32 image_id){
rptr32 result = declare_image(manifest_memory, filename, image_id, true);
if (setup->count > 0){
Asset_Node *node = to_node_ptr(result, manifest_memory);
Asset_Node *parent = to_node_ptr(setup->parents[setup->count-1], manifest_memory);
insert_under(node, parent, manifest_memory, false);
node->type = AssetType_Image;
}
return(result);
}
rptr32
replace_image(void *manifest_memory, char *filename, i32 image_id){
return(declare_image(manifest_memory, filename, image_id, false));
}
void
begin_folder(void *manifest_memory, Manifest_Setup *setup, char *name, i32 image_id){
Assert(setup->count < ArrayCount(setup->parents));
rptr32 node_self = bind_image(manifest_memory, setup, name, image_id);
setup->parents[setup->count++] = node_self;
Asset_Node *node = to_node_ptr(node_self, manifest_memory);
node->type = AssetType_GenericFolder;
}
void
end_folder(void *manifest_memory, Manifest_Setup *setup){
Assert(setup->count > 0);
--setup->count;
}
int
new_image(void *manifest_memory, char *filename){
i32 result = 0;
i32 len = cd_strlen(filename);
if (len != 0 && len < ASSET_MAX_NAME){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
Asset_Node *node =
to_node_ptr(manifest->free_sentinel.next_sibling, manifest_memory);
if (node != &manifest->free_sentinel){
Assert(node->name[0] == 0);
allocate_node(manifest, node, filename, len);
result = 1;
}
}
return(result);
}
void
delete_image(void *manifest_memory, i32 image_id){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
Asset_Node *nodes = to_node_ptr(manifest->asset_nodes, manifest_memory);
Asset_Node *node = nodes + (image_id - 1);
if (node->name[0] != 0){
free_node(manifest, node);
}
}
void
move_manifest_to_bigger_block(void *manifest_memory, void *new_memory, i32 size){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
Assert(manifest->part.max < size);
if (new_memory != manifest_memory){
cd_memcpy(new_memory, manifest_memory, manifest->part.max);
}
manifest = (Asset_Manifest*)new_memory;
manifest->part.max = size;
Wrapped_Partition part = make_wrapped_partition(&manifest->part, manifest_memory);
add_free_nodes(manifest, &part);
}
#ifdef DEVELOPER
Asset_Node*
get_available_node(System_API *system, Partition *manifest_part, Asset_Manifest **manifest_memory_ptr){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_part->base;
rptr32 node_self = manifest->free_sentinel.next_sibling;
Asset_Node *result = to_node_ptr(node_self, manifest);
if (result == &manifest->free_sentinel){
i32 pos = manifest_part->rel_part.pos;
Asset_Manifest *new_manifest = (Asset_Manifest*)push_block(manifest_part, pos);
if (new_manifest == 0){
DBG_expand_partition(system, manifest_part, pos);
new_manifest = (Asset_Manifest*)push_block(manifest_part, pos);
Assert(new_manifest);
manifest = (Asset_Manifest*)manifest_part->base;
*manifest_memory_ptr = (Asset_Manifest*)manifest_part->base;
}
move_manifest_to_bigger_block(manifest, manifest, manifest_part->rel_part.pos);
node_self = manifest->free_sentinel.next_sibling;
result = to_node_ptr(node_self, manifest);
Assert(result != &manifest->free_sentinel);
}
allocate_node(manifest, result, "New", 3);
return(result);
}
#endif
Asset_Walker_Entry
new_walker_entry(rptr32 first, i32 level){
Asset_Walker_Entry result;
result.first = first;
result.current = first;
result.level = level;
return(result);
}
Asset_Node*
walk_first_asset_node(void *manifest_memory, Asset_Walker *walker){
Asset_Manifest *manifest = (Asset_Manifest*)manifest_memory;
Asset_Node *nodes = to_node_ptr(manifest->asset_nodes, manifest_memory);
Asset_Node *node = nodes + (ROOT - 1);
walker->current_level = 0;
if (node->first_child){
walker->stack[walker->top++] = new_walker_entry(node->first_child, 1);
}
return(node);
}
Asset_Node*
walk_next_asset_node(void *manifest_memory, Asset_Walker *walker){
Asset_Node *node = 0;
if (walker->top != 0){
walker->current_level = walker->stack[walker->top-1].level;
}
if (walker->top > 0){
Asset_Walker_Entry *top = walker->stack + (walker->top - 1);
node = to_node_ptr(top->current, manifest_memory);
top->current = node->next_sibling;
if (top->current == top->first){
--walker->top;
}
if (node->first_child){
walker->stack[walker->top++] =
new_walker_entry(node->first_child, top->level + 1);
}
}
return(node);
}
Asset_Node*
walk_skip_children_asset_node(void *manifest_memory, Asset_Walker *walker){
Asset_Node *node = 0;
if (walker->top > 0){
Asset_Walker_Entry *top = walker->stack + (walker->top - 1);
while (top->level > walker->current_level){
--walker->top;
if (walker->top > 0){
top = walker->stack + (walker->top - 1);
}
else{
break;
}
}
node = walk_next_asset_node(manifest_memory, walker);
}
return(node);
}
// BOTTOM