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 { int facing
, w
, h
; };
58 { struct ir_setdata_header_t header
;
59 struct ir_frameinfo_t frameinfo
;
62 { struct ir_setdata_header_t header
;
63 struct ir_framedata_t framesheets
[FACING_MAX
];
64 struct ir_framedata_t mapsheets
[FACING_MAX
];
66 struct ir_simplex_t
{ struct ir_setdata_header_t header
; };
68 { struct ir_setdata_header_t header
;
69 struct ir_classld_t
* classld
;
70 struct ir_setld_t
* setld
;
74 { struct ir_setdata_header_t header
;
75 struct ir_framebox_t framebox
;
76 struct ir_framedata_t framesheet
;
77 struct ir_framedata_t mapsheet
;
78 struct ir_simplex_t audio
;
79 struct ir_link_t link
;
82 { struct ir_class_t
* nextchild
, * nextsib
;
83 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 struct ir_set_t
* ir_set_from_ref
228 struct ir_set_t
** iters
;
229 struct pagenode_t
* iterp
;
230 iterp
= refhashpages
.root
;
233 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
234 while (*iters
!= NULL
&& (*iters
)->ref
!= ref
&& (iterp
= iterp
->header
.next
) != NULL
);
239 /* Add a set to a set
240 Attempts to create a new subset of the specified set, returning the
241 child if it already exists
243 struct ir_set_t
* ir_set_addchild
244 ( struct ir_set_t
* set
,
247 { struct ir_set_t
* iter
;
248 if (set
->nextchild
== NULL
)
249 { set
->nextchild
= struct_alloc(ir_set_t
);
250 struct_clear(set
->nextchild
);
251 set
->nextchild
->name
= name_alloc(name
);
252 return set
->nextchild
;
254 iter
= set
->nextchild
;
256 eprintf("Null child added to set %s\n", iter
->name
);
257 if (iter
->name
== NULL
)
258 eprintf("Null name pointer in set %p\n", iter
);
260 if (bytes_identical(iter
->name
, name
))
262 if (iter
->nextsib
!= NULL
)
263 { iter
= iter
->nextsib
;
266 iter
->nextsib
= struct_alloc(ir_set_t
);
267 struct_clear(iter
->nextsib
);
268 iter
->nextsib
->name
= name_alloc(name
);
269 return iter
->nextsib
;
272 /* Add a framebox to a set
273 Attempts to create a new framebox of the specified set, returning
274 the framebox if it already exists
275 Name is not allocated, but assigned, unlike other "XXX_add" functions where
276 name is duplicated into IR's internal array.
279 struct ir_framebox_t
* ir_set_add_framebox
280 ( struct ir_set_t
* set
,
283 { struct ir_framebox_t
* iter
;
284 if (set
->frameboxes
== NULL
)
285 { set
->frameboxes
= struct_alloc(ir_framebox_t
);
286 struct_clear(set
->frameboxes
);
287 set
->frameboxes
->header
.data_name
= name
;
288 return set
->frameboxes
;
290 iter
= set
->frameboxes
;
292 if (bytes_identical(iter
->header
.data_name
, name
))
294 if (iter
->header
.nextsib
!= NULL
)
295 { iter
= (struct ir_framebox_t
*) iter
->header
.nextsib
;
298 iter
->header
.nextsib
= (union ir_setdata_t
*) struct_alloc(ir_framebox_t
);
299 struct_clear(iter
->header
.nextsib
);
300 iter
->header
.nextsib
->header
.data_name
= name
;
301 return (struct ir_framebox_t
*) (iter
->header
.nextsib
);
304 /* Match two null-terminated bytestrings
305 Return 1 if the two bytestrings are identical, else 0
309 ( const uint8_t* stra
,
316 } while (ca
&& ca
!= '_' && ca
== cb
);
321 int classnames_identical
322 ( const uint8_t* stra
,
329 } while (ca
&& ca
== cb
);
333 /* Assign Setdata to Set */
334 void ir_set_assign_data
335 ( struct ir_set_t
* set
,
336 union ir_setdata_t
* setdata
338 { struct ir_framebox_t
* framebox
;
339 struct ir_simplex_t
* simplex
;
340 switch (setdata
->header
.type
)
342 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
343 if (framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
344 wprintf("Duplicate framesheet [%i] %s\n",
345 setdata
->framesheet
.frameinfo
.facing
, setdata
->header
.data_name
);
346 framebox
->framesheets
[setdata
->framesheet
.frameinfo
.facing
] = setdata
->framesheet
;
349 framebox
= ir_set_add_framebox(set
, setdata
->header
.data_name
);
350 if (framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
].header
.data_name
!= NULL
)
351 wprintf("Duplicate mapsheet [%i] %s\n",
352 setdata
->mapsheet
.frameinfo
.facing
, setdata
->header
.data_name
);
353 framebox
->mapsheets
[setdata
->mapsheet
.frameinfo
.facing
] = setdata
->mapsheet
;
356 if (set
->audio
== NULL
)
357 { set
->audio
= (struct ir_simplex_t
*) setdata
;
360 simplex
= set
->audio
;
361 while (simplex
->header
.nextsib
!= NULL
)
362 if (bytes_identical(simplex
->header
.data_name
, setdata
->header
.data_name
))
363 { wprintf("Duplicate audio %s\n", setdata
->header
.data_name
);
364 *simplex
= setdata
->audio
;
365 //setdata is now a pointer to redundant, unused memory.
369 simplex
= (struct ir_simplex_t
*) simplex
->header
.nextsib
;
370 setdata
->audio
.header
.nextsib
= (union ir_setdata_t
*) set
->audio
;
371 set
->audio
= (struct ir_simplex_t
*) setdata
;
374 setdata
->link
.header
.nextsib
= (union ir_setdata_t
*) set
->links
;
375 set
->links
= (struct ir_link_t
*) setdata
;
378 fprintf(stderr
, "Unknown setdata type %x\n", setdata
->header
.type
);
383 void ir_set_assign_ref
384 ( struct ir_set_t
* set
,
387 { uint16_t hash
, oldhash
;
388 struct ir_set_t
** iters
;
389 struct pagenode_t
* iterp
;
394 iterp
= refhashpages
.root
;
396 iters
= ((struct ir_set_t
**) iterp
->root
) + hash
;
397 if (*iters
== NULL
|| *iters
== set
)
400 { if (iterp
->header
.next
== NULL
)
401 pagelist_alloc(refhashpages
);
402 iterp
= iterp
->header
.next
;
406 { wprintf("Ref override: 0x%x -> 0x%x for set %s\n", oldref
, ref
, set
->name
);
411 hash
= REFHASH(oldref
);
418 void ir_data_assign_path
419 ( union ir_setdata_t
* setdata
,
423 eprintf("Null path in data %s\n", setdata
->header
.data_name
);
424 if (setdata
->header
.src_filename
!= NULL
)
425 wprintf("Path override: %s -> %s for setdata %s\n",
426 setdata
->header
.src_filename
, path
, setdata
->header
.data_name
);
427 setdata
->header
.src_filename
= name_alloc(path
);
430 union ir_setdata_t
* ir_framesheet
431 ( const uint8_t* name
,
436 { return ir_framedata(FSDAT
, name
, d
, width
, height
); }
438 union ir_setdata_t
* ir_mapsheet
439 ( const uint8_t* name
,
444 { return ir_framedata(MSDAT
, name
, d
, width
, height
); }
447 union ir_setdata_t
* ir_framedata
454 { struct ir_framedata_t
* framedata
= struct_alloc(ir_framedata_t
);
455 struct_clear(framedata
);
457 eprintf("Null name in set allocation\n");
458 framedata
->header
.type
= type
;
459 framedata
->header
.data_name
= name_alloc(name
);
460 framedata
->frameinfo
.facing
= d
;
461 framedata
->frameinfo
.w
= width
;
462 framedata
->frameinfo
.h
= height
;
463 return (union ir_setdata_t
*) framedata
;
466 union ir_setdata_t
* ir_audio
467 ( const uint8_t* name
)
468 { struct ir_simplex_t
* audio
= struct_alloc(ir_simplex_t
);
471 eprintf("Null audio\n");
472 audio
->header
.type
= ADAT
;
473 audio
->header
.data_name
= name_alloc(name
);
474 return (union ir_setdata_t
*) audio
;
478 /* Create classld that points to a class */
479 struct ir_classld_t
* ir_classld_from_class
480 ( struct ir_class_t
* class )
481 { struct ir_classld_t
* classld
;
483 eprintf("Null class in classld\n");
484 classld
= struct_alloc(ir_classld_t
);
485 struct_clear(classld
);
486 classld
->root_class
= class;
490 struct ir_setld_t
* ir_setld_from_ref
492 { struct ir_setld_t
* setld
;
493 setld
= struct_alloc(ir_setld_t
);
499 struct ir_setld_t
* ir_setld_from_classld
500 ( struct ir_classld_t
* classld
,
503 { struct ir_setld_t
* setld
;
504 setld
= struct_alloc(ir_setld_t
);
506 setld
->namelist
= struct_alloc(ir_namelist_t
);
507 struct_clear(setld
->namelist
);
508 setld
->namelist_head
= setld
->namelist
;
509 setld
->namelist_head
->name
= name_alloc(name
);
510 setld
->classld
= classld
;
514 struct ir_setld_t
* ir_setld_addchild
515 ( struct ir_setld_t
* setld
,
518 { if (setld
->namelist
== NULL
)
519 { setld
->namelist
= struct_alloc(ir_namelist_t
);
520 struct_clear(setld
->namelist
);
521 setld
->namelist_head
= setld
->namelist
;
524 { setld
->namelist_head
->nextsib
= struct_alloc(ir_namelist_t
);
525 struct_clear(setld
->namelist_head
->nextsib
);
526 setld
->namelist_head
= setld
->namelist_head
->nextsib
;
528 setld
->namelist_head
->name
= name_alloc(name
);
532 union ir_setdata_t
* ir_link
533 ( enum ltype link_type
,
534 struct ir_setld_t
* setld
,
537 { struct ir_link_t
* link
;
538 link
= struct_alloc(ir_link_t
);
540 link
->header
.type
= LDAT
;
541 link
->type
= link_type
;
542 link
->classld
= setld
->classld
;
544 if (link_type
!= OLINK
&& name
!= NULL
)
545 link
->header
.data_name
= name_alloc(name
);
546 return (union ir_setdata_t
*) link
;
552 ( const uint8_t* name_src
)
553 { const uint8_t* iter
;
557 name
= (uint8_t*)namepages
.head
->header
.head
;
559 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& *iter
!= '_' && *iter
!= '.' && head_mem
; head_mem
--)
560 *(namepages
.head
->header
.head
)++ = *iter
++;
561 if (head_mem
< 1) //not enough room
562 { pagelist_alloc(namepages
);
565 *(namepages
.head
->header
.head
)++ = '\0';
570 uint8_t* classname_alloc
571 ( const uint8_t* name_src
)
572 { const uint8_t* iter
;
576 name
= (uint8_t*)namepages
.head
->header
.head
;
578 for (head_mem
= PL_HEADMEM(namepages
); *iter
&& head_mem
; head_mem
--)
579 *(namepages
.head
->header
.head
)++ = *iter
++;
580 if (head_mem
< 1) //not enough room
581 { pagelist_alloc(namepages
);
584 *(namepages
.head
->header
.head
)++ = '\0';
588 static void crawl_class(struct ir_class_t
*);
589 static void crawl_set(struct ir_set_t
*,int);
592 { uprintf("IR From Directory: %s\n",getcwd(NULL
,255));
593 crawl_class(&root_class
);
594 if (root_class
.root_set
!= NULL
)
595 crawl_set(root_class
.root_set
, 0);
596 uprintf("starting binaryout \n");
597 ir_binout_init(&root_class
);
603 ( struct ir_class_t
* class )
604 { struct ir_class_t
* iter
;
605 for (iter
= class->nextchild
; iter
!= NULL
; iter
= iter
->nextsib
)
606 { wprintf("Crawling class %U/\n", iter
->name
);
607 if(chdir((char*)iter
->name
))
608 eprintf("CHDIR %U from %s\n",iter
->name
,getcwd(NULL
,255));
610 if (iter
->root_set
!= NULL
)
611 crawl_set(iter
->root_set
, 0);
612 uprintf("%U\\\n",iter
->name
);
614 eprintf("CHDIR ..\n");
615 wprintf("Finished crawling class %U/\n", iter
->name
);
619 #define push_setp(setp) (*(struct ir_set_t**)stack_alloc(&datapages, sizeof(struct ir_set_t*)) = setp)
620 #define pop_setp() (*(struct ir_set_t**)pagelist_pop(&datapages, sizeof(struct ir_set_t*)))
623 ( struct ir_set_t
* set
,
626 { struct ir_set_t
* iter
;
633 for(iter
= set
; iter
!= NULL
; iter
= iter
->nextchild
)
634 { uprintf("[%10U]", iter
->name
);
641 if (((iter
= pop_setp())->nextsib
) != NULL
)
642 crawl_set(iter
->nextsib
,i
);