/*!@file \brief IR Memory Implementation \details Intermediary memory management \author Jordan Lavatai \date Aug 2016 ----------------------------------------------------------------------------*/ /* Standard */ #include //exit, malloc #include //print #include //va_args #include //uint64_t #include //memset, str* /* Unicode */ #include //u8_* functions #include //uint8_t as a char #include //u32_cpy /* Local */ #include "apc.h" #include "ir.h" /* Public */ int ir_init(void); void ir_quit(void); int ir_linker(void); int ir_condenser(void); /* Private */ struct pagenode_t; extern //apc.c long sys_pagesize; static inline struct ir_framebox_t* ir_set_add_framebox(struct ir_set_t*, uint8_t*); static void ir_free_pages(struct pagenode_t*); static inline int bytes_identical(uint8_t*,uint8_t*); static void* stack_alloc(size_t); /* Memory allocator */ struct pagenode_t { struct pagenode_t* next; char* head; char root[]; }* pagenode_root, * pagenode_head; #define PN_ALLOCSIZE (sys_pagesize) #define PN_HEADERSIZE() (sizeof(struct pagenode_t*) + sizeof(char*)) #define PN_MEMSIZE() (PN_ALLOCSIZE - PN_HEADERSIZE()) #define PN_HEADSIZE() (pagenode_head->head - pagenode_head->root) #define PN_HEADSPACE() (PN_MEMSIZE() - PN_HEADSIZE()) /* Enumerated types */ enum dtype { FSDAT, MSDAT, ADAT, LDAT, FBDAT }; enum ltype { OLINK, MLINK, VLINK, ALINK }; /* Set link data */ struct ir_namelist_t; struct ir_namelist_t { struct ir_namelist_t* nextsib; uint8_t* name; }; struct ir_classld_t { struct ir_class_t* root_class; struct ir_namelist_t* namelist; }; struct ir_setld_t { struct classld_t* classld; long long ref; struct ir_namelist_t* namelist; }; /* Set data mem */ struct ir_setdata_header_t { enum dtype type; uint8_t* src_filename, * data_name; union ir_setdata_t* nextsib; }; struct ir_frameinfo_t { int facing, w, h; }; struct ir_framedata_t { struct ir_setdata_header_t header; struct ir_frameinfo_t frameinfo; }; struct ir_framebox_t { struct ir_setdata_header_t header; struct ir_framedata_t framesheets[FACING_MAX]; struct ir_framedata_t mapsheets[FACING_MAX]; }; struct ir_simplex_t { struct ir_setdata_header_t header; }; struct ir_link_t { struct ir_setdata_header_t header; struct ir_classld_t* classld; struct ir_setld_t* setld; enum ltype type; }; union ir_setdata_t { struct ir_setdata_header_t header; struct ir_framebox_t framebox; struct ir_framedata_t framesheet; struct ir_framedata_t mapsheet; struct ir_simplex_t audio; struct ir_link_t link; }; struct ir_class_t { struct ir_class_t* nextchild, * nextsib; struct ir_set_t* root_set; uint8_t* name; }; struct ir_set_t { struct ir_set_t* nextchild, * nextsib; struct ir_class_t* class; long long ref; uint8_t* name; struct ir_framebox_t* frameboxes; struct ir_simplex_t* audio; struct ir_link_t* links; }; /* Function-Like Macros */ #define do_warn() do { \ } while (0) #define wprint(str) do { \ fprintf(stderr, str); \ do_warn(); \ } while (0) #define wprintf(fmt,...) do { \ fprintf(stderr, fmt, __VA_ARGS__); \ do_warn(); \ } while (0) #define do_error() do { \ exit(-1); \ } while (0) #define eprint(str) do { \ fprintf(stderr, str); \ do_error(); \ } while (0) #define eprintf(fmt,...) do { \ fprintf(stderr, fmt, __VA_ARGS__); \ do_error(); \ } while (0) #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T))) static struct ir_class_t root_class = { .name = (uint8_t*)"." }; /* Init */ int ir_init ( void ) { pagenode_root = (struct pagenode_t*) calloc((size_t)PN_ALLOCSIZE,1); if (pagenode_root == NULL) return -1; pagenode_root->head = pagenode_root->root; pagenode_head = pagenode_root; return 0; } /* Quit/Cleanup Recursively clean pagenode linked list */ void ir_quit ( void ) { ir_free_pages(pagenode_root); } static void ir_free_pages ( struct pagenode_t* pagenode ) { if (pagenode->next != NULL) ir_free_pages(pagenode->next); free(pagenode); } /* Link */ int ir_linker ( void ) { return 0; } /* Condense */ int ir_condenser ( void ) { return 0; } /* Return a pointer to the root class */ struct ir_class_t* ir_class_root ( void ) { return &root_class; } /* Add a subclass to a class Attempts to create a new subclass in the provided class, returning the class if it already exists */ struct ir_class_t* ir_class_addchild ( struct ir_class_t* class, uint8_t* name ) { struct ir_class_t* iter; if (class->nextchild == NULL) return class->nextchild = struct_alloc(ir_class_t); iter = class->nextchild; check: if (bytes_identical(iter->name, name)) return iter; if (iter->nextsib != NULL) { iter = iter->nextsib; goto check; } iter = struct_alloc(ir_class_t); iter->nextsib = class->nextchild; return class->nextchild = iter; } /* Add a set to a class Attempts to create a new root set in the specified class, returning the set if it already exists */ struct ir_set_t* ir_class_addset ( struct ir_class_t* class, uint8_t* name ) { struct ir_set_t* iter; if (class->root_set == NULL) return class->root_set = struct_alloc(ir_set_t); iter = class->root_set; check: if (bytes_identical(iter->name, name)) return iter; if (iter->nextsib != NULL) { iter = iter->nextsib; goto check; } iter = struct_alloc(ir_set_t); iter->nextsib = class->root_set; return class->root_set = iter; } /* Add a set to a set Attempts to create a new subset of the specified set, returning the child if it already exists */ struct ir_set_t* ir_set_addchild ( struct ir_set_t* set, uint8_t* name ) { struct ir_set_t* iter; if (set->nextchild == NULL) return set->nextchild = struct_alloc(ir_set_t); iter = set->nextchild; check: if (bytes_identical(iter->name, name)) return iter; if (iter->nextsib != NULL) { iter = iter->nextsib; goto check; } iter = struct_alloc(ir_set_t); iter->nextsib = set->nextchild; return set->nextchild = iter; } /* Add a framebox to a set Attempts to create a new framebox of the specified set, returning the framebox if it already exists */ static inline struct ir_framebox_t* ir_set_add_framebox ( struct ir_set_t* set, uint8_t* name ) { struct ir_framebox_t* iter; if (set->frameboxes == NULL) return set->frameboxes = struct_alloc(ir_framebox_t); iter = set->frameboxes; check: if (bytes_identical(iter->header.data_name, name)) return iter; if (iter->header.nextsib != NULL) { iter = (struct ir_framebox_t*) iter->header.nextsib; goto check; } iter = struct_alloc(ir_framebox_t); iter->header.nextsib = (union ir_setdata_t*) set->frameboxes; return set->frameboxes = iter; } /* Match two null-terminated bytestrings Return 1 if the two bytestrings are identical, else 0 */ static inline int bytes_identical ( uint8_t* stra, uint8_t* strb ) { int ca, cb; do { ca = *stra++; cb = *strb++; } while (ca && ca == cb); return (ca == cb); } /* Assign Setdata to Set */ void ir_set_assign_data ( struct ir_set_t* set, union ir_setdata_t* setdata ) { struct ir_framebox_t* framebox; struct ir_simplex_t* simplex; switch (setdata->header.type) { case FSDAT: framebox = ir_set_add_framebox(set, setdata->header.data_name); if (framebox->framesheets[setdata->framesheet.frameinfo.facing].header.data_name != NULL) wprintf("Duplicate framesheet [%i] %s\n", setdata->framesheet.frameinfo.facing, setdata->header.data_name); framebox->framesheets[setdata->framesheet.frameinfo.facing] = setdata->framesheet; break; case MSDAT: framebox = ir_set_add_framebox(set, setdata->header.data_name); if (framebox->mapsheets[setdata->mapsheet.frameinfo.facing].header.data_name != NULL) wprintf("Duplicate mapsheet [%i] %s\n", setdata->mapsheet.frameinfo.facing, setdata->header.data_name); framebox->mapsheets[setdata->mapsheet.frameinfo.facing] = setdata->mapsheet; break; case ADAT: if (set->audio == NULL) { set->audio = (struct ir_simplex_t*) setdata; return; } simplex = set->audio; while (simplex->header.nextsib != NULL) if (bytes_identical(simplex->header.data_name, setdata->header.data_name)) { wprintf("Duplicate audio %s\n", setdata->header.data_name); *simplex = setdata->audio; //setdata is now a pointer to redundant, unused memory. return; } else simplex = (struct ir_simplex_t*) simplex->header.nextsib; simplex->header.nextsib = setdata; break; case LDAT: setdata->link.header.nextsib = (union ir_setdata_t*) set->links; set->links = (struct ir_link_t*) setdata; break; default: fprintf(stderr, "Unknown setdata type %x\n", setdata->header.type); exit(-1); } } void ir_set_assign_ref ( struct ir_set_t* set, long long ref ) { if (set->ref != 0) wprintf("Ref override: 0x%lx -> 0x%lx for set %s\n", (long unsigned) set->ref, (long unsigned) ref, set->name); set->ref = ref; //TODO: reflist_add(set); } void ir_data_assign_path ( union ir_setdata_t* setdata, uint8_t* path ) { setdata->header.src_filename = path; //TODO: internal strdup, not assign (= path;) } //TODO: Macro ir_framsheet and mapsheet? union ir_setdata_t* ir_framesheet ( uint8_t* name, apc_facing d, int width, int height ) { struct ir_framedata_t* framesheet = struct_alloc(ir_framedata_t); framesheet->header.type = FSDAT; framesheet->header.data_name = name; framesheet->frameinfo.facing = d; framesheet->frameinfo.w = width; framesheet->frameinfo.h = height; return (union ir_setdata_t*) framesheet; } union ir_setdata_t* ir_mapsheet ( uint8_t* name, apc_facing d, int width, int height ) { struct ir_framedata_t* mapsheet = struct_alloc(ir_framedata_t); mapsheet->header.type = MSDAT; mapsheet->header.data_name = name; mapsheet->frameinfo.facing = d; mapsheet->frameinfo.w = width; mapsheet->frameinfo.h = height; return (union ir_setdata_t*) mapsheet; } union ir_setdata_t* ir_audio ( uint8_t* name ) { struct ir_simplex_t* audio = struct_alloc(ir_simplex_t); audio->header.type = ADAT; audio->header.data_name = name; return (union ir_setdata_t*) audio; } static void* stack_alloc(size_t bytes) { if (!bytes) { wprint("Attempting to allocate 0 bytes in stack_alloc"); return pagenode_head->head; } if (PN_HEADSPACE() < bytes) { pagenode_head->next = (struct pagenode_t*) calloc(PN_ALLOCSIZE,1); pagenode_head = pagenode_head->next; pagenode_head->head = pagenode_head->root; } pagenode_head->head += bytes; return (void*) pagenode_head->head - bytes; }