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
;
56 { struct ir_setdata_header_t header
;
57 struct ir_frameinfo_t frameinfo
;
60 { struct ir_setdata_header_t header
;
61 struct ir_framedata_t framesheets
[FACING_MAX
];
62 struct ir_framedata_t mapsheets
[FACING_MAX
];
64 struct ir_simplex_t
{ struct ir_setdata_header_t header
; };
66 { struct ir_setdata_header_t header
;
67 struct ir_classld_t
* classld
;
68 struct ir_setld_t
* setld
;
72 { struct ir_setdata_header_t header
;
73 struct ir_framebox_t framebox
;
74 struct ir_framedata_t framesheet
;
75 struct ir_framedata_t mapsheet
;
76 struct ir_simplex_t audio
;
77 struct ir_link_t link
;
80 { struct ir_class_t
* nextchild
, * nextsib
;
81 struct ir_set_t
* root_set
;
85 { struct ir_set_t
* nextchild
, * nextsib
;
88 struct ir_framebox_t
* frameboxes
;
89 struct ir_simplex_t
* audio
;
90 struct ir_link_t
* links
;
95 struct ir_framebox_t
* ir_set_add_framebox(struct ir_set_t
*,uint8_t*);
97 union ir_setdata_t
* ir_framedata (enum dtype
,const uint8_t*,apc_facing
,int,int);
99 int bytes_identical(const uint8_t*,const uint8_t*);
101 int classnames_identical(const uint8_t*,const uint8_t*);
103 uint8_t* name_alloc(const uint8_t*);
105 uint8_t* classname_alloc(const uint8_t*);
106 #define struct_clear(_S) (memset((_S), 0, sizeof(*(_S))))
107 #define REFHASH(ref) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & 0xCFF)
108 #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
112 struct pagelist_t datapages
, namepages
, refhashpages
;
114 struct ir_class_t root_class
= { .name
= (uint8_t*)"." };
119 { pagelist_init(datapages
, (size_t)SYS_PAGESIZE
);
120 pagelist_init(namepages
, (size_t)NAME_PAGESIZE
);
121 pagelist_init(refhashpages
, (size_t)SYS_PAGESIZE
);
129 { pagenode_free(datapages
.root
);
130 pagenode_free(namepages
.root
);
131 pagenode_free(refhashpages
.root
);
147 /* Return the class's name string */
148 uint8_t* ir_class_name
149 ( struct ir_class_t
* class )
150 { return class->name
; }
152 /* Return a pointer to the root class */
153 struct ir_class_t
* ir_class_root
155 { return &root_class
; }
157 /* Add a subclass to a class
158 Attempts to create a new subclass in the provided class, returning
159 the class if it already exists
161 struct ir_class_t
* ir_class_addchild
162 ( struct ir_class_t
* class,
165 { struct ir_class_t
* iter
;
166 if (class->nextchild
== NULL
)
167 { class->nextchild
= struct_alloc(ir_class_t
);
168 struct_clear(class->nextchild
);
169 class->nextchild
->name
= classname_alloc(name
);
170 return class->nextchild
;
172 iter
= class->nextchild
;
173 if (iter
->name
== NULL
)
174 eprintf("Null name pointer in class %p\n", iter
);
176 eprintf("Null child added to class %s\n", iter
->name
);
178 if (classnames_identical(iter
->name
, name
))
180 if (iter
->nextsib
!= NULL
)
181 { iter
= iter
->nextsib
;
184 iter
->nextsib
= struct_alloc(ir_class_t
);
185 struct_clear(iter
->nextsib
);
186 iter
->nextsib
->name
= classname_alloc(name
);
187 return iter
->nextsib
;
190 /* Add a set to a class
191 Attempts to create a new root set in the specified class, returning
192 the set if it already exists
194 struct ir_set_t
* ir_class_addset
195 ( struct ir_class_t
* class,
198 { struct ir_set_t
* iter
;
199 if (class->root_set
== NULL
)
200 { class->root_set
= struct_alloc(ir_set_t
);
201 struct_clear(class->root_set
);
202 class->root_set
->name
= name_alloc(name
);
203 return class->root_set
;
205 iter
= class->root_set
;
206 if (iter
->name
== NULL
)
207 eprintf("Null name pointer in class %p\n", iter
);
209 eprintf("Null set added to class %U\n", iter
->name
);
211 if (bytes_identical(iter
->name
, name
))
213 if (iter
->nextsib
!= NULL
)
214 { iter
= iter
->nextsib
;
217 iter
->nextsib
= struct_alloc(ir_set_t
);
218 struct_clear(iter
->nextsib
);
219 iter
->nextsib
->name
= name_alloc(name
);
220 return iter
->nextsib
;
223 struct ir_set_t
* ir_set_from_ref
226 struct ir_set_t
** iters
;
227 struct pagenode_t
* iterp
;
228 iterp
= refhashpages
.root
;
231 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
232 while (*iters
!= NULL
&& (*iters
)->ref
!= ref
&& (iterp
= iterp
->header
.next
) != NULL
);
237 /* Add a set to a set
238 Attempts to create a new subset of the specified set, returning the
239 child if it already exists
241 struct ir_set_t
* ir_set_addchild
242 ( struct ir_set_t
* set
,
245 { struct ir_set_t
* iter
;
246 if (set
->nextchild
== NULL
)
247 { set
->nextchild
= struct_alloc(ir_set_t
);
248 struct_clear(set
->nextchild
);
249 set
->nextchild
->name
= name_alloc(name
);
250 return set
->nextchild
;
252 iter
= set
->nextchild
;
254 eprintf("Null child added to set %s\n", iter
->name
);
255 if (iter
->name
== NULL
)
256 eprintf("Null name pointer in set %p\n", iter
);
258 if (bytes_identical(iter
->name
, name
))
260 if (iter
->nextsib
!= NULL
)
261 { iter
= iter
->nextsib
;
264 iter
->nextsib
= struct_alloc(ir_set_t
);
265 struct_clear(iter
->nextsib
);
266 iter
->nextsib
->name
= name_alloc(name
);
267 return iter
->nextsib
;
270 /* Add a framebox to a set
271 Attempts to create a new framebox of the specified set, returning
272 the framebox if it already exists
273 Name is not allocated, but assigned, unlike other "XXX_add" functions where
274 name is duplicated into IR's internal array.
277 struct ir_framebox_t
* ir_set_add_framebox
278 ( struct ir_set_t
* set
,
281 { struct ir_framebox_t
* iter
;
282 if (set
->frameboxes
== NULL
)
283 { set
->frameboxes
= struct_alloc(ir_framebox_t
);
284 struct_clear(set
->frameboxes
);
285 set
->frameboxes
->header
.data_name
= name
;
286 return set
->frameboxes
;
288 iter
= set
->frameboxes
;
290 if (bytes_identical(iter
->header
.data_name
, name
))
292 if (iter
->header
.nextsib
!= NULL
)
293 { iter
= (struct ir_framebox_t
*) iter
->header
.nextsib
;
296 iter
->header
.nextsib
= (union ir_setdata_t
*) struct_alloc(ir_framebox_t
);
297 struct_clear(iter
->header
.nextsib
);
298 iter
->header
.nextsib
->header
.data_name
= name
;
299 return (struct ir_framebox_t
*) (iter
->header
.nextsib
);
302 /* Match two null-terminated bytestrings
303 Return 1 if the two bytestrings are identical, else 0
307 ( const uint8_t* stra
,
314 } while (ca
&& ca
!= '_' && ca
== cb
);
319 int classnames_identical
320 ( const uint8_t* stra
,
327 } while (ca
&& ca
== cb
);
331 /* Assign Setdata to Set */
332 void ir_set_assign_data
333 ( struct ir_set_t
* set
,
334 union ir_setdata_t
* setdata
336 { struct ir_framebox_t
* framebox
;
337 struct ir_simplex_t
* simplex
;
338 switch (setdata
->header
.type
)
340 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
341 if (framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
342 wprintf("Duplicate framesheet [%i] %s\n",
343 setdata
->framesheet
.frameinfo
.facing
, setdata
->header
.data_name
);
344 framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
] = setdata
->framesheet
;
347 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
348 if (framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
349 wprintf("Duplicate mapsheet [%i] %s\n",
350 setdata
->mapsheet
.frameinfo
.facing
, setdata
->header
.data_name
);
351 framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
] = setdata
->mapsheet
;
354 if (set
->audio
== NULL
)
355 { set
->audio
= (struct ir_simplex_t
*) setdata
;
358 simplex
= set
->audio
;
359 while (simplex
->header
.nextsib
!= NULL
)
360 if (bytes_identical(simplex
->header
.data_name
, setdata
->header
.data_name
))
361 { wprintf("Duplicate audio %s\n", setdata
->header
.data_name
);
362 *simplex
= setdata
->audio
;
363 //setdata is now a pointer to redundant, unused memory.
367 simplex
= (struct ir_simplex_t
*) simplex
->header
.nextsib
;
368 setdata
->audio
.header
.nextsib
= (union ir_setdata_t
*) set
->audio
;
369 set
->audio
= (struct ir_simplex_t
*) setdata
;
372 setdata
->link
.header
.nextsib
= (union ir_setdata_t
*) set
->links
;
373 set
->links
= (struct ir_link_t
*) setdata
;
376 fprintf(stderr
, "Unknown setdata type %x\n", setdata
->header
.type
);
381 void ir_set_assign_ref
382 ( struct ir_set_t
* set
,
385 { uint16_t hash
, oldhash
;
386 struct ir_set_t
** iters
;
387 struct pagenode_t
* iterp
;
392 iterp
= refhashpages
.root
;
394 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
395 if (*iters
== NULL
|| *iters
== set
)
398 { if (iterp
->header
.next
== NULL
)
399 pagelist_alloc(refhashpages
);
400 iterp
= iterp
->header
.next
;
404 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref
, ref
, set
->name
);
409 hash
= REFHASH(oldref
);
416 void ir_data_assign_path
417 ( union ir_setdata_t
* setdata
,
421 eprintf("Null path in data %s\n", setdata
->header
.data_name
);
422 if (setdata
->header
.src_filename
!= NULL
)
423 wprintf("Path override: %s -> %s for setdata %s\n",
424 setdata
->header
.src_filename
, path
, setdata
->header
.data_name
);
425 setdata
->header
.src_filename
= name_alloc(path
);
428 union ir_setdata_t
* ir_framesheet
429 ( const uint8_t* name
,
434 { return ir_framedata(FSDAT
, name
, d
, width
, height
); }
436 union ir_setdata_t
* ir_mapsheet
437 ( const uint8_t* name
,
442 { return ir_framedata(MSDAT
, name
, d
, width
, height
); }
445 union ir_setdata_t
* ir_framedata
452 { struct ir_framedata_t
* framedata
= struct_alloc(ir_framedata_t
);
453 struct_clear(framedata
);
455 eprintf("Null name in set allocation\n");
456 framedata
->header
.type
= type
;
457 framedata
->header
.data_name
= name_alloc(name
);
458 framedata
->frameinfo
.facing
= d
;
459 framedata
->frameinfo
.w
= width
;
460 framedata
->frameinfo
.h
= height
;
461 return (union ir_setdata_t
*) framedata
;
464 union ir_setdata_t
* ir_audio
465 ( const uint8_t* name
)
466 { struct ir_simplex_t
* audio
= struct_alloc(ir_simplex_t
);
469 eprintf("Null audio\n");
470 audio
->header
.type
= ADAT
;
471 audio
->header
.data_name
= name_alloc(name
);
472 return (union ir_setdata_t
*) audio
;
476 /* Create classld that points to a class */
477 struct ir_classld_t
* ir_classld_from_class
478 ( struct ir_class_t
* class )
479 { struct ir_classld_t
* classld
;
481 eprintf("Null class in classld\n");
482 classld
= struct_alloc(ir_classld_t
);
483 struct_clear(classld
);
484 classld
->root_class
= class;
488 struct ir_setld_t
* ir_setld_from_ref
490 { struct ir_setld_t
* setld
;
491 setld
= struct_alloc(ir_setld_t
);
497 struct ir_setld_t
* ir_setld_from_classld
498 ( struct ir_classld_t
* classld
,
501 { struct ir_setld_t
* setld
;
502 setld
= struct_alloc(ir_setld_t
);
504 setld
->namelist
= struct_alloc(ir_namelist_t
);
505 struct_clear(setld
->namelist
);
506 setld
->namelist_head
= setld
->namelist
;
507 setld
->namelist_head
->name
= name_alloc(name
);
508 setld
->classld
= classld
;
512 struct ir_setld_t
* ir_setld_addchild
513 ( struct ir_setld_t
* setld
,
516 { if (setld
->namelist
== NULL
)
517 { setld
->namelist
= struct_alloc(ir_namelist_t
);
518 struct_clear(setld
->namelist
);
519 setld
->namelist_head
= setld
->namelist
;
522 { setld
->namelist_head
->nextsib
= struct_alloc(ir_namelist_t
);
523 struct_clear(setld
->namelist_head
->nextsib
);
524 setld
->namelist_head
= setld
->namelist_head
->nextsib
;
526 setld
->namelist_head
->name
= name_alloc(name
);
530 union ir_setdata_t
* ir_link
531 ( enum ltype link_type
,
532 struct ir_setld_t
* setld
,
535 { struct ir_link_t
* link
;
536 link
= struct_alloc(ir_link_t
);
538 link
->header
.type
= LDAT
;
539 link
->type
= link_type
;
540 link
->classld
= setld
->classld
;
542 if (link_type
!= OLINK
&& name
!= NULL
)
543 link
->header
.data_name
= name_alloc(name
);
544 return (union ir_setdata_t
*) link
;
550 ( const uint8_t* name_src
)
551 { const uint8_t* iter
;
555 name
= (uint8_t*)namepages
.head
->header
.head
;
557 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& *iter
!= '_' && *iter
!= '.' && head_mem
; head_mem
--)
558 *(namepages
.head
->header
.head
)++ = *iter
++;
559 if (head_mem
< 1) //not enough room
560 { pagelist_alloc(namepages
);
563 *(namepages
.head
->header
.head
)++ = '\0';
568 uint8_t* classname_alloc
569 ( const uint8_t* name_src
)
570 { const uint8_t* iter
;
574 name
= (uint8_t*)namepages
.head
->header
.head
;
576 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& head_mem
; head_mem
--)
577 *(namepages
.head
->header
.head
)++ = *iter
++;
578 if (head_mem
< 1) //not enough room
579 { pagelist_alloc(namepages
);
582 *(namepages
.head
->header
.head
)++ = '\0';
586 static void crawl_class(struct ir_class_t
*);
587 static void crawl_set(struct ir_set_t
*,int);
590 { uprintf("IR From Directory: %s\n",getcwd(NULL
,255));
591 crawl_class(&root_class
);
592 if (root_class
.root_set
!= NULL
)
593 crawl_set(root_class
.root_set
, 0);
594 uprintf("starting binaryout \n");
595 ir_binout_init(&root_class
);
601 ( struct ir_class_t
* class )
602 { struct ir_class_t
* iter
;
603 for (iter
= class->nextchild
; iter
!= NULL
; iter
= iter
->nextsib
)
604 { wprintf("Crawling class %U/\n", iter
->name
);
605 if(chdir((char*)iter
->name
))
606 eprintf("CHDIR %U from %s\n",iter
->name
,getcwd(NULL
,255));
608 if (iter
->root_set
!= NULL
)
609 crawl_set(iter
->root_set
, 0);
610 uprintf("%U\\\n",iter
->name
);
612 eprintf("CHDIR ..\n");
613 wprintf("Finished crawling class %U/\n", iter
->name
);
617 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(&datapages, sizeof(struct ir_set_t*)) = setp)
618 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
621 ( struct ir_set_t
* set
,
624 { struct ir_set_t
* iter
;
631 for(iter
= set
; iter
!= NULL
; iter
= iter
->nextchild
)
632 { uprintf("[%10U]", iter
->name
);
639 if (((iter
= pop_setp())->nextsib
) != NULL
)
640 crawl_set(iter
->nextsib
,i
);