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*
15 #include <unistd.h> //u8_* functions
16 #include <unitypes.h> //uint8_t as a char
17 #include <unistr.h> //u32_cpy
18 #include <unistdio.h> //ulc_fprintf
25 #define do_error(...) exit(-1)
26 #define XXH_PRIVATE_API
27 #include "../xxHash/xxhash.h"
33 int ir_condenser(void);
35 enum dtype
{ FSDAT
, MSDAT
, ADAT
, LDAT
, FBDAT
};
38 { struct ir_namelist_t
* nextsib
;
42 { struct ir_class_t
* root_class
;
43 struct ir_namelist_t
* namelist
, * namelist_head
;
46 { struct ir_classld_t
* classld
;
48 struct ir_namelist_t
* namelist
, * namelist_head
;
50 struct ir_setdata_header_t
52 uint8_t* src_filename
, * data_name
;
53 union ir_setdata_t
* nextsib
;
57 { struct ir_setdata_header_t header
;
58 struct ir_frameinfo_t frameinfo
;
61 { struct ir_setdata_header_t header
;
62 struct ir_framedata_t framesheets
[FACING_MAX
];
63 struct ir_framedata_t mapsheets
[FACING_MAX
];
65 struct ir_simplex_t
{ struct ir_setdata_header_t header
; };
67 { struct ir_setdata_header_t header
;
68 struct ir_classld_t
* classld
;
69 struct ir_setld_t
* setld
;
73 { struct ir_setdata_header_t header
;
74 struct ir_framebox_t framebox
;
75 struct ir_framedata_t framesheet
;
76 struct ir_framedata_t mapsheet
;
77 struct ir_simplex_t audio
;
78 struct ir_link_t link
;
81 { struct ir_class_t
* nextchild
, * nextsib
;
82 struct ir_set_t
* root_set
;
87 { struct ir_set_t
* nextchild
, * nextsib
;
90 struct ir_framebox_t
* frameboxes
;
91 struct ir_simplex_t
* audio
;
92 struct ir_link_t
* links
;
97 struct ir_framebox_t
* ir_set_add_framebox(struct ir_set_t
*,uint8_t*);
99 union ir_setdata_t
* ir_framedata (enum dtype
,const uint8_t*,apc_facing
,int,int);
101 int bytes_identical(const uint8_t*,const uint8_t*);
103 int classnames_identical(const uint8_t*,const uint8_t*);
105 uint8_t* name_alloc(const uint8_t*);
107 uint8_t* classname_alloc(const uint8_t*);
108 #define struct_clear(_S) (memset((_S), 0, sizeof(*(_S))))
109 #define REFHASH(ref) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & 0xCFF)
110 #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
114 struct pagelist_t datapages
, namepages
, refhashpages
;
116 struct ir_class_t root_class
= { .name
= (uint8_t*)"." };
121 { pagelist_init(datapages
, (size_t)SYS_PAGESIZE
);
122 pagelist_init(namepages
, (size_t)NAME_PAGESIZE
);
123 pagelist_init(refhashpages
, (size_t)SYS_PAGESIZE
);
131 { pagenode_free(datapages
.root
);
132 pagenode_free(namepages
.root
);
133 pagenode_free(refhashpages
.root
);
149 /* Return the class's name string */
150 uint8_t* ir_class_name
151 ( struct ir_class_t
* class )
152 { return class->name
; }
154 /* Return a pointer to the root class */
155 struct ir_class_t
* ir_class_root
157 { return &root_class
; }
159 /* Add a subclass to a class
160 Attempts to create a new subclass in the provided class, returning
161 the class if it already exists
163 struct ir_class_t
* ir_class_addchild
164 ( struct ir_class_t
* class,
167 { struct ir_class_t
* iter
;
168 if (class->nextchild
== NULL
)
169 { class->nextchild
= struct_alloc(ir_class_t
);
170 struct_clear(class->nextchild
);
171 class->nextchild
->name
= classname_alloc(name
);
172 return class->nextchild
;
174 iter
= class->nextchild
;
175 if (iter
->name
== NULL
)
176 eprintf("Null name pointer in class %p\n", iter
);
178 eprintf("Null child added to class %s\n", iter
->name
);
180 if (classnames_identical(iter
->name
, name
))
182 if (iter
->nextsib
!= NULL
)
183 { iter
= iter
->nextsib
;
186 iter
->nextsib
= struct_alloc(ir_class_t
);
187 struct_clear(iter
->nextsib
);
188 iter
->nextsib
->name
= classname_alloc(name
);
189 return iter
->nextsib
;
192 /* Add a set to a class
193 Attempts to create a new root set in the specified class, returning
194 the set if it already exists
196 struct ir_set_t
* ir_class_addset
197 ( struct ir_class_t
* class,
200 { struct ir_set_t
* iter
;
201 if (class->root_set
== NULL
)
202 { class->root_set
= struct_alloc(ir_set_t
);
203 struct_clear(class->root_set
);
204 class->root_set
->name
= name_alloc(name
);
205 return class->root_set
;
207 iter
= class->root_set
;
208 if (iter
->name
== NULL
)
209 eprintf("Null name pointer in class %p\n", iter
);
211 eprintf("Null set added to class %U\n", iter
->name
);
213 if (bytes_identical(iter
->name
, name
))
215 if (iter
->nextsib
!= NULL
)
216 { iter
= iter
->nextsib
;
219 iter
->nextsib
= struct_alloc(ir_set_t
);
220 struct_clear(iter
->nextsib
);
221 iter
->nextsib
->name
= name_alloc(name
);
222 return iter
->nextsib
;
225 /* Get the root set of the class */
226 struct ir_set_t
* ir_class_rootset
227 ( struct ir_class_t
* class )
228 { return class->root_set
; }
230 struct ir_set_t
* ir_set_from_ref
233 struct ir_set_t
** iters
;
234 struct pagenode_t
* iterp
;
235 iterp
= refhashpages
.root
;
238 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
239 while (*iters
!= NULL
&& (*iters
)->ref
!= ref
&& (iterp
= iterp
->header
.next
) != NULL
);
244 /* Add a set to a set
245 Attempts to create a new subset of the specified set, returning the
246 child if it already exists
248 struct ir_set_t
* ir_set_addchild
249 ( struct ir_set_t
* set
,
252 { struct ir_set_t
* iter
;
253 if (set
->nextchild
== NULL
)
254 { set
->nextchild
= struct_alloc(ir_set_t
);
255 struct_clear(set
->nextchild
);
256 set
->nextchild
->name
= name_alloc(name
);
257 return set
->nextchild
;
259 iter
= set
->nextchild
;
261 eprintf("Null child added to set %s\n", iter
->name
);
262 if (iter
->name
== NULL
)
263 eprintf("Null name pointer in set %p\n", iter
);
265 if (bytes_identical(iter
->name
, name
))
267 if (iter
->nextsib
!= NULL
)
268 { iter
= iter
->nextsib
;
271 iter
->nextsib
= struct_alloc(ir_set_t
);
272 struct_clear(iter
->nextsib
);
273 iter
->nextsib
->name
= name_alloc(name
);
274 return iter
->nextsib
;
277 /* Add a framebox to a set
278 Attempts to create a new framebox of the specified set, returning
279 the framebox if it already exists
280 Name is not allocated, but assigned, unlike other "XXX_add" functions where
281 name is duplicated into IR's internal array.
284 struct ir_framebox_t
* ir_set_add_framebox
285 ( struct ir_set_t
* set
,
288 { struct ir_framebox_t
* iter
;
289 if (set
->frameboxes
== NULL
)
290 { set
->frameboxes
= struct_alloc(ir_framebox_t
);
291 struct_clear(set
->frameboxes
);
292 set
->frameboxes
->header
.data_name
= name
;
293 return set
->frameboxes
;
295 iter
= set
->frameboxes
;
297 if (bytes_identical(iter
->header
.data_name
, name
))
299 if (iter
->header
.nextsib
!= NULL
)
300 { iter
= (struct ir_framebox_t
*) iter
->header
.nextsib
;
303 iter
->header
.nextsib
= (union ir_setdata_t
*) struct_alloc(ir_framebox_t
);
304 struct_clear(iter
->header
.nextsib
);
305 iter
->header
.nextsib
->header
.data_name
= name
;
306 return (struct ir_framebox_t
*) (iter
->header
.nextsib
);
309 /* Match two null-terminated bytestrings
310 Return 1 if the two bytestrings are identical, else 0
314 ( const uint8_t* stra
,
321 } while (ca
&& ca
!= '_' && ca
== cb
);
326 int classnames_identical
327 ( const uint8_t* stra
,
334 } while (ca
&& ca
== cb
);
338 /* Return the name of the set */
340 ( struct ir_set_t
* set
)
341 { return set
->name
; }
343 /* Return the next sib of the class */
344 struct ir_class_t
* ir_class_nextsib
345 ( struct ir_class_t
* class )
346 { return class->nextsib
; }
348 /* Return the next sib of the class */
349 struct ir_class_t
* ir_class_nextchild
350 ( struct ir_class_t
* class )
351 { return class->nextchild
; }
353 /* Get the file position of the class */
355 ( struct ir_class_t
* class )
356 { return class->filepos
; }
358 /* Set the file position of the class */
359 void ir_class_assign_fpos
360 ( struct ir_class_t
* class,
363 { class->filepos
= newpos
; }
365 /* Get the next sibling of the provided set */
366 struct ir_set_t
* ir_set_nextsib
367 ( struct ir_set_t
* set
)
368 { return set
->nextsib
; }
370 /* Get the next child of the provided set */
371 struct ir_set_t
* ir_set_nextchild
372 ( struct ir_set_t
* set
)
373 { return set
->nextchild
; }
375 /* Get the file position of the class */
377 ( struct ir_set_t
* set
)
378 { return set
->filepos
; }
380 /* Set the file position of the class */
381 void ir_set_assign_fpos
382 ( struct ir_set_t
* set
,
385 { set
->filepos
= newpos
; }
387 /* Assign Setdata to Set */
388 void ir_set_assign_data
389 ( struct ir_set_t
* set
,
390 union ir_setdata_t
* setdata
392 { struct ir_framebox_t
* framebox
;
393 struct ir_simplex_t
* simplex
;
394 switch (setdata
->header
.type
)
396 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
397 if (framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
398 wprintf("Duplicate framesheet [%i] %s\n",
399 setdata
->framesheet
.frameinfo
.facing
, setdata
->header
.data_name
);
400 framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
] = setdata
->framesheet
;
403 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
404 if (framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
405 wprintf("Duplicate mapsheet [%i] %s\n",
406 setdata
->mapsheet
.frameinfo
.facing
, setdata
->header
.data_name
);
407 framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
] = setdata
->mapsheet
;
410 if (set
->audio
== NULL
)
411 { set
->audio
= (struct ir_simplex_t
*) setdata
;
414 simplex
= set
->audio
;
415 while (simplex
->header
.nextsib
!= NULL
)
416 if (bytes_identical(simplex
->header
.data_name
, setdata
->header
.data_name
))
417 { wprintf("Duplicate audio %s\n", setdata
->header
.data_name
);
418 *simplex
= setdata
->audio
;
419 //setdata is now a pointer to redundant, unused memory.
423 simplex
= (struct ir_simplex_t
*) simplex
->header
.nextsib
;
424 setdata
->audio
.header
.nextsib
= (union ir_setdata_t
*) set
->audio
;
425 set
->audio
= (struct ir_simplex_t
*) setdata
;
428 setdata
->link
.header
.nextsib
= (union ir_setdata_t
*) set
->links
;
429 set
->links
= (struct ir_link_t
*) setdata
;
432 fprintf(stderr
, "Unknown setdata type %x\n", setdata
->header
.type
);
437 void ir_set_assign_ref
438 ( struct ir_set_t
* set
,
441 { uint16_t hash
, oldhash
;
442 struct ir_set_t
** iters
;
443 struct pagenode_t
* iterp
;
448 iterp
= refhashpages
.root
;
450 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
451 if (*iters
== NULL
|| *iters
== set
)
454 { if (iterp
->header
.next
== NULL
)
455 pagelist_alloc(refhashpages
);
456 iterp
= iterp
->header
.next
;
460 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref
, ref
, set
->name
);
465 hash
= REFHASH(oldref
);
472 void ir_data_assign_path
473 ( union ir_setdata_t
* setdata
,
477 eprintf("Null path in data %s\n", setdata
->header
.data_name
);
478 if (setdata
->header
.src_filename
!= NULL
)
479 wprintf("Path override: %s -> %s for setdata %s\n",
480 setdata
->header
.src_filename
, path
, setdata
->header
.data_name
);
481 setdata
->header
.src_filename
= name_alloc(path
);
484 union ir_setdata_t
* ir_framesheet
485 ( const uint8_t* name
,
490 { return ir_framedata(FSDAT
, name
, d
, width
, height
); }
492 union ir_setdata_t
* ir_mapsheet
493 ( const uint8_t* name
,
498 { return ir_framedata(MSDAT
, name
, d
, width
, height
); }
501 union ir_setdata_t
* ir_framedata
508 { struct ir_framedata_t
* framedata
= struct_alloc(ir_framedata_t
);
509 struct_clear(framedata
);
511 eprintf("Null name in set allocation\n");
512 framedata
->header
.type
= type
;
513 framedata
->header
.data_name
= name_alloc(name
);
514 framedata
->frameinfo
.facing
= d
;
515 framedata
->frameinfo
.w
= width
;
516 framedata
->frameinfo
.h
= height
;
517 return (union ir_setdata_t
*) framedata
;
520 union ir_setdata_t
* ir_audio
521 ( const uint8_t* name
)
522 { struct ir_simplex_t
* audio
= struct_alloc(ir_simplex_t
);
525 eprintf("Null audio\n");
526 audio
->header
.type
= ADAT
;
527 audio
->header
.data_name
= name_alloc(name
);
528 return (union ir_setdata_t
*) audio
;
532 /* Create classld that points to a class */
533 struct ir_classld_t
* ir_classld_from_class
534 ( struct ir_class_t
* class )
535 { struct ir_classld_t
* classld
;
537 eprintf("Null class in classld\n");
538 classld
= struct_alloc(ir_classld_t
);
539 struct_clear(classld
);
540 classld
->root_class
= class;
544 struct ir_setld_t
* ir_setld_from_ref
546 { struct ir_setld_t
* setld
;
547 setld
= struct_alloc(ir_setld_t
);
553 struct ir_setld_t
* ir_setld_from_classld
554 ( struct ir_classld_t
* classld
,
557 { struct ir_setld_t
* setld
;
558 setld
= struct_alloc(ir_setld_t
);
560 setld
->namelist
= struct_alloc(ir_namelist_t
);
561 struct_clear(setld
->namelist
);
562 setld
->namelist_head
= setld
->namelist
;
563 setld
->namelist_head
->name
= name_alloc(name
);
564 setld
->classld
= classld
;
568 struct ir_setld_t
* ir_setld_addchild
569 ( struct ir_setld_t
* setld
,
572 { if (setld
->namelist
== NULL
)
573 { setld
->namelist
= struct_alloc(ir_namelist_t
);
574 struct_clear(setld
->namelist
);
575 setld
->namelist_head
= setld
->namelist
;
578 { setld
->namelist_head
->nextsib
= struct_alloc(ir_namelist_t
);
579 struct_clear(setld
->namelist_head
->nextsib
);
580 setld
->namelist_head
= setld
->namelist_head
->nextsib
;
582 setld
->namelist_head
->name
= name_alloc(name
);
586 union ir_setdata_t
* ir_link
587 ( enum ltype link_type
,
588 struct ir_setld_t
* setld
,
591 { struct ir_link_t
* link
;
592 link
= struct_alloc(ir_link_t
);
594 link
->header
.type
= LDAT
;
595 link
->type
= link_type
;
596 link
->classld
= setld
->classld
;
598 if (link_type
!= OLINK
&& name
!= NULL
)
599 link
->header
.data_name
= name_alloc(name
);
600 return (union ir_setdata_t
*) link
;
603 /* Return a set's root framebox */
604 union ir_setdata_t
* ir_set_framebox
605 ( struct ir_set_t
* set
)
606 { return (union ir_setdata_t
*) set
->frameboxes
; }
608 /* Return a set's root audio data */
609 union ir_setdata_t
* ir_set_audio
610 ( struct ir_set_t
* set
)
611 { return (union ir_setdata_t
*) set
->audio
; }
613 /* Return a set's root link data */
614 union ir_setdata_t
* ir_set_link
615 ( struct ir_set_t
* set
)
616 { return (union ir_setdata_t
*) set
->links
; }
618 /* Return the link type */
619 enum ltype ir_linkdata_type
620 ( union ir_setdata_t
* linkdata
)
621 { if (linkdata
->header
.type
!= LDAT
)
622 eprintf("Data %s is not a link\n", linkdata
->header
.data_name
);
623 return linkdata
->link
.type
;
626 /* Return the link type */
627 uint32_t ir_linkdata_ref
628 ( union ir_setdata_t
* linkdata
)
629 { if (linkdata
->header
.type
!= LDAT
)
630 eprintf("Data %s is not a link\n", linkdata
->header
.data_name
);
631 return linkdata
->link
.setld
->ref
;
634 /* Get a setdata's next sibling */
635 union ir_setdata_t
* ir_setdata_nextsib
636 ( union ir_setdata_t
* setdata
)
637 { return setdata
->header
.nextsib
; }
639 /* Get a setdata's name */
640 uint8_t* ir_setdata_name
641 ( union ir_setdata_t
* setdata
)
642 { return setdata
->header
.data_name
; }
644 /* Get a setdata's filename */
645 uint8_t* ir_setdata_filename
646 ( union ir_setdata_t
* setdata
)
647 { return setdata
->header
.src_filename
; }
649 /* Get a setdata's file position */
651 ( union ir_setdata_t
* setdata
)
652 { return setdata
->header
.filepos
; }
654 /* Set a setdata's file position */
655 void ir_setdata_assign_fpos
656 ( union ir_setdata_t
* setdata
,
659 { setdata
->header
.filepos
= newpos
; }
661 /* Return a framebox's specified framesheet */
662 union ir_setdata_t
* ir_framebox_framesheet
663 ( union ir_setdata_t
* fbox
,
666 { if (fbox
->header
.type
!= FBDAT
)
667 eprintf("Data %s is not a framebox\n", fbox
->header
.data_name
);
668 return (union ir_setdata_t
*) &fbox
->framebox
.framesheets
[facing
];
671 /* Return a framebox's specified mapsheet */
672 union ir_setdata_t
* ir_framebox_mapsheet
673 ( union ir_setdata_t
* fbox
,
676 { if (fbox
->header
.type
!= FBDAT
)
677 eprintf("Data %s is not a framebox\n", fbox
->header
.data_name
);
678 return (union ir_setdata_t
*) &fbox
->framebox
.mapsheets
[facing
];
681 /* Return a framedata's frame info */
682 struct ir_frameinfo_t
* ir_framedata_mapsheet
683 ( union ir_setdata_t
* framedata
)
684 { if (framedata
->header
.type
!= MSDAT
&& framedata
->header
.type
!= FSDAT
)
685 eprintf("Data %s is not a framedata\n", framedata
->header
.data_name
);
686 return &framedata
->mapsheet
.frameinfo
;
692 ( const uint8_t* name_src
)
693 { const uint8_t* iter
;
697 name
= (uint8_t*)namepages
.head
->header
.head
;
699 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& *iter
!= '_' && *iter
!= '.' && head_mem
; head_mem
--)
700 *(namepages
.head
->header
.head
)++ = *iter
++;
701 if (head_mem
< 1) //not enough room
702 { pagelist_alloc(namepages
);
705 *(namepages
.head
->header
.head
)++ = '\0';
710 uint8_t* classname_alloc
711 ( const uint8_t* name_src
)
712 { const uint8_t* iter
;
716 name
= (uint8_t*)namepages
.head
->header
.head
;
718 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& head_mem
; head_mem
--)
719 *(namepages
.head
->header
.head
)++ = *iter
++;
720 if (head_mem
< 1) //not enough room
721 { pagelist_alloc(namepages
);
724 *(namepages
.head
->header
.head
)++ = '\0';
728 static void crawl_class(struct ir_class_t
*);
729 static void crawl_set(struct ir_set_t
*,int);
732 int binout_init(ir_class
);
734 { uprintf("IR From Directory: %s\n",getcwd(NULL
,255));
735 crawl_class(&root_class
);
736 if (root_class
.root_set
!= NULL
)
737 crawl_set(root_class
.root_set
, 0);
738 uprintf("starting binaryout \n");
739 binout_init(&root_class
);
745 ( struct ir_class_t
* class )
746 { struct ir_class_t
* iter
;
747 for (iter
= class->nextchild
; iter
!= NULL
; iter
= iter
->nextsib
)
748 { wprintf("Crawling class %U/\n", iter
->name
);
749 if(chdir((char*)iter
->name
))
750 eprintf("CHDIR %U from %s\n",iter
->name
,getcwd(NULL
,255));
752 if (iter
->root_set
!= NULL
)
753 crawl_set(iter
->root_set
, 0);
754 uprintf("%U\\\n",iter
->name
);
756 eprintf("CHDIR ..\n");
757 wprintf("Finished crawling class %U/\n", iter
->name
);
761 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(&datapages, sizeof(struct ir_set_t*)) = setp)
762 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
765 ( struct ir_set_t
* set
,
768 { struct ir_set_t
* iter
;
775 for(iter
= set
; iter
!= NULL
; iter
= iter
->nextchild
)
776 { uprintf("[%10U]", iter
->name
);
783 if (((iter
= pop_setp())->nextsib
) != NULL
)
784 crawl_set(iter
->nextsib
,i
);