2 \brief IR Memory Implementation
3 \details Intermediary memory management
6 ----------------------------------------------------------------------------*/
8 #include <stdlib.h> //exit, malloc
9 #include <stdio.h> //print
10 #include <stdarg.h> //va_args
11 #include <stdint.h> //uint64_t
12 #include <string.h> //memset, str*
14 #include <unistd.h> //u8_* functions
15 #include <unitypes.h> //uint8_t as a char
16 #include <unistr.h> //u32_cpy
17 #include <unistdio.h> //ulc_fprintf
23 #define do_error(...) exit(-1)
24 #define XXH_PRIVATE_API
25 #include "../xxHash/xxhash.h"
31 int ir_condenser(void);
32 /* Memory allocation structures */
34 struct pagenode_header_t
{
35 struct pagenode_t
* next
;
39 struct pagenode_header_t header
;
43 struct pagenode_t
* root
, * head
;
46 #define SYS_PAGESIZE (sys_pagesize)
47 #define NAME_PAGESIZE (APC_NAME_MAX * 1024)
48 #define PL_HEADERSIZE (sizeof(struct pagenode_header_t))
49 #define PL_HEADSIZE(_PL) (_PL.head->header.head - _PL.head->root)
50 #define PL_HEADMEM(_PL) (_PL.pagesize - PL_HEADERSIZE - PL_HEADSIZE(_PL))
52 enum dtype
{ FSDAT
, MSDAT
, ADAT
, LDAT
, FBDAT
};
55 { struct ir_namelist_t
* nextsib
;
59 { struct ir_class_t
* root_class
;
60 struct ir_namelist_t
* namelist
, * namelist_head
;
63 { struct ir_classld_t
* classld
;
65 struct ir_namelist_t
* namelist
, * namelist_head
;
67 struct ir_setdata_header_t
69 uint8_t* src_filename
, * data_name
;
70 union ir_setdata_t
* nextsib
;
73 { int facing
, w
, h
; };
75 { struct ir_setdata_header_t header
;
76 struct ir_frameinfo_t frameinfo
;
79 { struct ir_setdata_header_t header
;
80 struct ir_framedata_t framesheets
[FACING_MAX
];
81 struct ir_framedata_t mapsheets
[FACING_MAX
];
83 struct ir_simplex_t
{ struct ir_setdata_header_t header
; };
85 { struct ir_setdata_header_t header
;
86 struct ir_classld_t
* classld
;
87 struct ir_setld_t
* setld
;
91 { struct ir_setdata_header_t header
;
92 struct ir_framebox_t framebox
;
93 struct ir_framedata_t framesheet
;
94 struct ir_framedata_t mapsheet
;
95 struct ir_simplex_t audio
;
96 struct ir_link_t link
;
99 { struct ir_class_t
* nextchild
, * nextsib
;
100 struct ir_set_t
* root_set
;
104 { struct ir_set_t
* nextchild
, * nextsib
;
107 struct ir_framebox_t
* frameboxes
;
108 struct ir_simplex_t
* audio
;
109 struct ir_link_t
* links
;
113 struct ir_framebox_t
* ir_set_add_framebox(struct ir_set_t
*,uint8_t*);
115 union ir_setdata_t
* ir_framedata (enum dtype
,const uint8_t*,apc_facing
,int,int);
117 int bytes_identical(const uint8_t*,const uint8_t*);
119 int classnames_identical(const uint8_t*,const uint8_t*);
121 void* stack_alloc(size_t);
122 #define struct_alloc(_T) ((struct _T*) stack_alloc(sizeof(struct _T)))
123 #define struct_clear(_S) (memset((_S), 0, sizeof(*(_S))))
125 uint8_t* name_alloc(const uint8_t*);
127 uint8_t* classname_alloc(const uint8_t*);
129 void* pagelist_pop(struct pagelist_t
*,size_t);
131 #define pagelist_alloc(pagelist) do { \
132 pagelist.head->header.next = (struct pagenode_t*) malloc(pagelist.pagesize); \
133 if (pagelist.head->header.next == NULL) \
134 eprintf("Memory allocation error\n"); \
135 struct_clear(pagelist.head->header.next); \
136 pagelist.head = pagelist.head->header.next; \
137 pagelist.head->header.head = pagelist.head->root; \
139 #define pagelist_init(pagelist,size) do { \
140 pagelist.pagesize = size; \
141 pagelist.root = (struct pagenode_t*) malloc(size); \
142 if (pagelist.root == NULL) \
143 eprintf("Memory allocation error\n"); \
144 struct_clear(pagelist.root); \
145 pagelist.head = pagelist.root; \
146 pagelist.head->header.head = pagelist.head->root; \
149 void pagenode_free(struct pagenode_t
*);
150 #define REFHASH(ref) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & 0xCFF)
155 struct pagelist_t datapages
, namepages
, refhashpages
;
157 struct ir_class_t root_class
= { .name
= (uint8_t*)"." };
162 { pagelist_init(datapages
, (size_t)SYS_PAGESIZE
);
163 pagelist_init(namepages
, (size_t)NAME_PAGESIZE
);
164 pagelist_init(refhashpages
, (size_t)SYS_PAGESIZE
);
171 { pagenode_free(datapages
.root
);
172 pagenode_free(namepages
.root
);
173 pagenode_free(refhashpages
.root
);
176 /* Recursively clean pagenode linked list, freeing last first */
179 ( struct pagenode_t
* pagenode
)
180 { if (pagenode
->header
.next
!= NULL
)
181 pagenode_free(pagenode
->header
.next
);
197 /* Return the class's name string */
198 uint8_t* ir_class_name
199 ( struct ir_class_t
* class )
200 { return class->name
; }
202 /* Return a pointer to the root class */
203 struct ir_class_t
* ir_class_root
205 { return &root_class
; }
207 /* Add a subclass to a class
208 Attempts to create a new subclass in the provided class, returning
209 the class if it already exists
211 struct ir_class_t
* ir_class_addchild
212 ( struct ir_class_t
* class,
215 { struct ir_class_t
* iter
;
216 if (class->nextchild
== NULL
)
217 { class->nextchild
= struct_alloc(ir_class_t
);
218 struct_clear(class->nextchild
);
219 class->nextchild
->name
= classname_alloc(name
);
220 return class->nextchild
;
222 iter
= class->nextchild
;
223 if (iter
->name
== NULL
)
224 eprintf("Null name pointer in class %p\n", iter
);
226 eprintf("Null child added to class %s\n", iter
->name
);
228 if (classnames_identical(iter
->name
, name
))
230 if (iter
->nextsib
!= NULL
)
231 { iter
= iter
->nextsib
;
234 iter
->nextsib
= struct_alloc(ir_class_t
);
235 struct_clear(iter
->nextsib
);
236 iter
->nextsib
->name
= classname_alloc(name
);
237 return iter
->nextsib
;
240 /* Add a set to a class
241 Attempts to create a new root set in the specified class, returning
242 the set if it already exists
244 struct ir_set_t
* ir_class_addset
245 ( struct ir_class_t
* class,
248 { struct ir_set_t
* iter
;
249 if (class->root_set
== NULL
)
250 { class->root_set
= struct_alloc(ir_set_t
);
251 struct_clear(class->root_set
);
252 class->root_set
->name
= name_alloc(name
);
253 return class->root_set
;
255 iter
= class->root_set
;
256 if (iter
->name
== NULL
)
257 eprintf("Null name pointer in class %p\n", iter
);
259 eprintf("Null set added to class %U\n", iter
->name
);
261 if (bytes_identical(iter
->name
, name
))
263 if (iter
->nextsib
!= NULL
)
264 { iter
= iter
->nextsib
;
267 iter
->nextsib
= struct_alloc(ir_set_t
);
268 struct_clear(iter
->nextsib
);
269 iter
->nextsib
->name
= name_alloc(name
);
270 return iter
->nextsib
;
273 struct ir_set_t
* ir_set_from_ref
276 struct ir_set_t
** iters
;
277 struct pagenode_t
* iterp
;
278 iterp
= refhashpages
.root
;
281 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
282 while (*iters
!= NULL
&& (*iters
)->ref
!= ref
&& (iterp
= iterp
->header
.next
) != NULL
);
287 /* Add a set to a set
288 Attempts to create a new subset of the specified set, returning the
289 child if it already exists
291 struct ir_set_t
* ir_set_addchild
292 ( struct ir_set_t
* set
,
295 { struct ir_set_t
* iter
;
296 if (set
->nextchild
== NULL
)
297 { set
->nextchild
= struct_alloc(ir_set_t
);
298 struct_clear(set
->nextchild
);
299 set
->nextchild
->name
= name_alloc(name
);
300 return set
->nextchild
;
302 iter
= set
->nextchild
;
304 eprintf("Null child added to set %s\n", iter
->name
);
305 if (iter
->name
== NULL
)
306 eprintf("Null name pointer in set %p\n", iter
);
308 if (bytes_identical(iter
->name
, name
))
310 if (iter
->nextsib
!= NULL
)
311 { iter
= iter
->nextsib
;
314 iter
->nextsib
= struct_alloc(ir_set_t
);
315 struct_clear(iter
->nextsib
);
316 iter
->nextsib
->name
= name_alloc(name
);
317 return iter
->nextsib
;
320 /* Add a framebox to a set
321 Attempts to create a new framebox of the specified set, returning
322 the framebox if it already exists
323 Name is not allocated, but assigned, unlike other "XXX_add" functions where
324 name is duplicated into IR's internal array.
327 struct ir_framebox_t
* ir_set_add_framebox
328 ( struct ir_set_t
* set
,
331 { struct ir_framebox_t
* iter
;
332 if (set
->frameboxes
== NULL
)
333 { set
->frameboxes
= struct_alloc(ir_framebox_t
);
334 struct_clear(set
->frameboxes
);
335 set
->frameboxes
->header
.data_name
= name
;
336 return set
->frameboxes
;
338 iter
= set
->frameboxes
;
340 if (bytes_identical(iter
->header
.data_name
, name
))
342 if (iter
->header
.nextsib
!= NULL
)
343 { iter
= (struct ir_framebox_t
*) iter
->header
.nextsib
;
346 iter
->header
.nextsib
= (union ir_setdata_t
*) struct_alloc(ir_framebox_t
);
347 struct_clear(iter
->header
.nextsib
);
348 iter
->header
.nextsib
->header
.data_name
= name
;
349 return (struct ir_framebox_t
*) (iter
->header
.nextsib
);
352 /* Match two null-terminated bytestrings
353 Return 1 if the two bytestrings are identical, else 0
357 ( const uint8_t* stra
,
364 } while (ca
&& ca
!= '_' && ca
== cb
);
369 int classnames_identical
370 ( const uint8_t* stra
,
377 } while (ca
&& ca
== cb
);
381 /* Assign Setdata to Set */
382 void ir_set_assign_data
383 ( struct ir_set_t
* set
,
384 union ir_setdata_t
* setdata
386 { struct ir_framebox_t
* framebox
;
387 struct ir_simplex_t
* simplex
;
388 switch (setdata
->header
.type
)
390 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
391 if (framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
392 wprintf("Duplicate framesheet [%i] %s\n",
393 setdata
->framesheet
.frameinfo
.facing
, setdata
->header
.data_name
);
394 framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
] = setdata
->framesheet
;
397 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
398 if (framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
399 wprintf("Duplicate mapsheet [%i] %s\n",
400 setdata
->mapsheet
.frameinfo
.facing
, setdata
->header
.data_name
);
401 framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
] = setdata
->mapsheet
;
404 if (set
->audio
== NULL
)
405 { set
->audio
= (struct ir_simplex_t
*) setdata
;
408 simplex
= set
->audio
;
409 while (simplex
->header
.nextsib
!= NULL
)
410 if (bytes_identical(simplex
->header
.data_name
, setdata
->header
.data_name
))
411 { wprintf("Duplicate audio %s\n", setdata
->header
.data_name
);
412 *simplex
= setdata
->audio
;
413 //setdata is now a pointer to redundant, unused memory.
417 simplex
= (struct ir_simplex_t
*) simplex
->header
.nextsib
;
418 setdata
->audio
.header
.nextsib
= (union ir_setdata_t
*) set
->audio
;
419 set
->audio
= (struct ir_simplex_t
*) setdata
;
422 setdata
->link
.header
.nextsib
= (union ir_setdata_t
*) set
->links
;
423 set
->links
= (struct ir_link_t
*) setdata
;
426 fprintf(stderr
, "Unknown setdata type %x\n", setdata
->header
.type
);
431 void ir_set_assign_ref
432 ( struct ir_set_t
* set
,
435 { uint16_t hash
, oldhash
;
436 struct ir_set_t
** iters
;
437 struct pagenode_t
* iterp
;
442 iterp
= refhashpages
.root
;
444 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
445 if (*iters
== NULL
|| *iters
== set
)
448 { if (iterp
->header
.next
== NULL
)
449 pagelist_alloc(refhashpages
);
450 iterp
= iterp
->header
.next
;
454 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref
, ref
, set
->name
);
459 hash
= REFHASH(oldref
);
466 void ir_data_assign_path
467 ( union ir_setdata_t
* setdata
,
471 eprintf("Null path in data %s\n", setdata
->header
.data_name
);
472 if (setdata
->header
.src_filename
!= NULL
)
473 wprintf("Path override: %s -> %s for setdata %s\n",
474 setdata
->header
.src_filename
, path
, setdata
->header
.data_name
);
475 setdata
->header
.src_filename
= name_alloc(path
);
478 union ir_setdata_t
* ir_framesheet
479 ( const uint8_t* name
,
484 { return ir_framedata(FSDAT
, name
, d
, width
, height
); }
486 union ir_setdata_t
* ir_mapsheet
487 ( const uint8_t* name
,
492 { return ir_framedata(MSDAT
, name
, d
, width
, height
); }
495 union ir_setdata_t
* ir_framedata
502 { struct ir_framedata_t
* framedata
= struct_alloc(ir_framedata_t
);
503 struct_clear(framedata
);
505 eprintf("Null name in set allocation\n");
506 framedata
->header
.type
= type
;
507 framedata
->header
.data_name
= name_alloc(name
);
508 framedata
->frameinfo
.facing
= d
;
509 framedata
->frameinfo
.w
= width
;
510 framedata
->frameinfo
.h
= height
;
511 return (union ir_setdata_t
*) framedata
;
514 union ir_setdata_t
* ir_audio
515 ( const uint8_t* name
)
516 { struct ir_simplex_t
* audio
= struct_alloc(ir_simplex_t
);
519 eprintf("Null audio\n");
520 audio
->header
.type
= ADAT
;
521 audio
->header
.data_name
= name_alloc(name
);
522 return (union ir_setdata_t
*) audio
;
526 /* Create classld that points to a class */
527 struct ir_classld_t
* ir_classld_from_class
528 ( struct ir_class_t
* class )
529 { struct ir_classld_t
* classld
;
531 eprintf("Null class in classld\n");
532 classld
= struct_alloc(ir_classld_t
);
533 struct_clear(classld
);
534 classld
->root_class
= class;
538 struct ir_setld_t
* ir_setld_from_ref
540 { struct ir_setld_t
* setld
;
541 setld
= struct_alloc(ir_setld_t
);
547 struct ir_setld_t
* ir_setld_from_classld
548 ( struct ir_classld_t
* classld
,
551 { struct ir_setld_t
* setld
;
552 setld
= struct_alloc(ir_setld_t
);
554 setld
->namelist
= struct_alloc(ir_namelist_t
);
555 struct_clear(setld
->namelist
);
556 setld
->namelist_head
= setld
->namelist
;
557 setld
->namelist_head
->name
= name_alloc(name
);
558 setld
->classld
= classld
;
562 struct ir_setld_t
* ir_setld_addchild
563 ( struct ir_setld_t
* setld
,
566 { if (setld
->namelist
== NULL
)
567 { setld
->namelist
= struct_alloc(ir_namelist_t
);
568 struct_clear(setld
->namelist
);
569 setld
->namelist_head
= setld
->namelist
;
572 { setld
->namelist_head
->nextsib
= struct_alloc(ir_namelist_t
);
573 struct_clear(setld
->namelist_head
->nextsib
);
574 setld
->namelist_head
= setld
->namelist_head
->nextsib
;
576 setld
->namelist_head
->name
= name_alloc(name
);
580 union ir_setdata_t
* ir_link
581 ( enum ltype link_type
,
582 struct ir_setld_t
* setld
,
585 { struct ir_link_t
* link
;
586 link
= struct_alloc(ir_link_t
);
588 link
->header
.type
= LDAT
;
589 link
->type
= link_type
;
590 link
->classld
= setld
->classld
;
592 if (link_type
!= OLINK
&& name
!= NULL
)
593 link
->header
.data_name
= name_alloc(name
);
594 return (union ir_setdata_t
*) link
;
599 ( struct pagelist_t
* pagelist
,
602 { size_t headsize
= PL_HEADSIZE((*pagelist
));
604 { free(pagelist
->head
);
605 pagelist
->head
= pagelist
->root
;
606 while (pagelist
->head
->header
.next
!= NULL
)
607 pagelist
->head
= pagelist
->head
->header
.next
;
610 eprintf("Attempted to pop unaligned value from pagelist\n");
611 pagelist
->head
->header
.head
-= size
;
612 return pagelist
->head
->header
.head
;
619 if (PL_HEADMEM(datapages
) < bytes
)
620 pagelist_alloc(datapages
);
621 p
= datapages
.head
->header
.head
;
622 datapages
.head
->header
.head
+= bytes
;
628 ( const uint8_t* name_src
)
629 { const uint8_t* iter
;
633 name
= (uint8_t*)namepages
.head
->header
.head
;
635 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& *iter
!= '_' && *iter
!= '.' && head_mem
; head_mem
--)
636 *(namepages
.head
->header
.head
)++ = *iter
++;
637 if (head_mem
< 1) //not enough room
638 { pagelist_alloc(namepages
);
641 *(namepages
.head
->header
.head
)++ = '\0';
646 uint8_t* classname_alloc
647 ( const uint8_t* name_src
)
648 { const uint8_t* iter
;
652 name
= (uint8_t*)namepages
.head
->header
.head
;
654 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& head_mem
; head_mem
--)
655 *(namepages
.head
->header
.head
)++ = *iter
++;
656 if (head_mem
< 1) //not enough room
657 { pagelist_alloc(namepages
);
660 *(namepages
.head
->header
.head
)++ = '\0';
664 static void crawl_class(struct ir_class_t
*);
665 static void crawl_set(struct ir_set_t
*,int);
667 { uprintf("IR From Directory: %s\n",getcwd(NULL
,255));
668 crawl_class(&root_class
);
669 if (root_class
.root_set
!= NULL
)
670 crawl_set(root_class
.root_set
, 0);
675 ( struct ir_class_t
* class )
676 { struct ir_class_t
* iter
;
677 for (iter
= class->nextchild
; iter
!= NULL
; iter
= iter
->nextsib
)
678 { wprintf("%U/\n", iter
->name
);
679 if(chdir((char*)iter
->name
))
680 eprintf("CHDIR %U from %s\n",iter
->name
,getcwd(NULL
,255));
682 if (iter
->root_set
!= NULL
)
683 crawl_set(iter
->root_set
, 0);
684 uprintf("%U\\\n",iter
->name
);
686 eprintf("CHDIR ..\n");
690 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(sizeof(struct ir_set_t*)) = setp)
691 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
694 ( struct ir_set_t
* set
,
697 { struct ir_set_t
* iter
;
703 for(iter
= set
; iter
!= NULL
; iter
= iter
->nextchild
)
704 { uprintf("[%10U]", iter
->name
);
710 if (((iter
= pop_setp())->nextsib
) != NULL
)
711 crawl_set(iter
->nextsib
,i
);