2 \brief IR Memory Implementation
3 \details Intermediary memory management
6 ----------------------------------------------------------------------------*/
9 #include <unitypes.h> //uint8_t as a char
10 #include <unistr.h> //u32_cpy
11 #include <stdint.h> //uint64_t
12 #include <string.h> //memset
13 #include <unistd.h> //u8_* functions
19 name_u8_cpy(struct name
*, struct name
*);
23 name_u8_cmp(struct name
*, struct name
*);
27 name_u8_set(struct name
*, ucs4_t
);
64 push_cdat(struct name
*);
70 insert_link_name(struct name
*);
72 insert_link_namelist(struct name
*);
74 insert_ss_name(struct name
*);
76 insert_ss_namelist(struct name
*);
78 insert_mlink(struct name
*, int);
80 insert_vlink(struct name
*, int);
82 insert_ref(struct odat
*, int);
88 insert_map(struct name
*, int, int, int, int, uint8_t*);
90 insert_framesheet(struct name
*, int, int, int, int, uint8_t*);
94 //type safety handled by macro expansion (do not call these directly from code, make dependent macros for access to these)
95 #define CHUNKS_LEN(STACK) ((STACK).csp - (STACK).chunks)
96 #define CURRENT_CHUNK(STACK) ((STACK).chunks[CHUNKS_LEN(STACK) - 1])
97 #define CHUNKS_FULL(STACK) ( (STACK).csp >= \
98 (STACK).chunks + MAX_CHUNKS * (STACK).chunk_size)
99 #define CURRENT_DSP(STACK,TYPE) ((TYPE*) ((STACK).dsp[CHUNKS_LEN(STACK) - 1]))
100 #define DATA_FULL(STACK,TYPE) ((void*) CURRENT_DSP(STACK,TYPE) >= \
101 (CURRENT_CHUNK(STACK) + (STACK).chunk_size))
102 #define CSP_PUSH(STACK) (*(++(STACK).csp) = malloc((STACK).chunk_size))
103 #define CURRENT_DATP(STACK,TYPE) (((TYPE**)(STACK).dsp)[CHUNKS_LEN(STACK) - 1])
104 #define PREVIOUS_DATP(STACK,TYPE) (((TYPE**)(STACK).dsp)[CHUNKS_LEN(STACK) - 2])
105 #define ALLOC_DAT(STACK,TYPE) (++CURRENT_DATP(STACK,TYPE))
106 #define INIT_STACK(STACK,TYPE) \
108 (STACK).chunk_size = PAGES_PER_CHUNK * pagesize; \
109 (STACK).max_dats = (STACK).chunk_size / sizeof (TYPE); \
111 for( i = 0; i < MAX_CHUNKS; i++){ \
112 (STACK).dsp[i] += pagesize; \
115 //Stack-specific macros (called directly from code (safety enforcement)
116 #define INIT_ODAT() (INIT_STACK(ocs, struct odat))
117 #define CURRENT_ODAT() (CURRENT_DATP(ocs,struct odat))
118 #define ODAT_FULL() (DATA_FULL(ocs,struct odat))
119 #define ODAT_ALLOC() (ALLOC_DAT(ocs,struct odat))
120 #define OCS_FULL() (CHUNKS_FULL(ocs))
121 #define INIT_VDAT() (INIT_STACK(vcs, struct vdat))
122 #define CURRENT_VDAT() (CURRENT_DATP(vcs,struct vdat))
123 #define VDAT_FULL() (DATA_FULL(vcs,struct vdat))
124 #define VDAT_ALLOC() (ALLOC_DAT(vcs,struct vdat))
125 #define VCS_FULL() (CHUNKS_FULL(vcs))
126 #define INIT_CDAT() (INIT_STACK(ccs, struct cdat))
127 #define CURRENT_CDAT() (CURRENT_DATP(ccs,struct cdat))
128 #define CDAT_FULL() (DATA_FULL(ccs, struct cdat))
129 #define CDAT_ALLOC() (ALLOC_DAT(ccs, struct cdat))
130 #define CCS_FULL() (CHUNKS_FULL(ccs))
131 #define INIT_SET() (INIT_STACK(scs, struct set))
132 #define CURRENT_SET() (CURRENT_DATP(scs, struct set))
133 #define SET_FULL() (DATA_FULL(scs, struct set))
134 #define SET_ALLOC() (ALLOC_DAT(scs, struct set))
135 #define SCS_FULL() (CHUNKS_FULL(scs))
136 #define INIT_LINK() (INIT_STACK(lcs, struct link))
137 #define CURRENT_LINK() (CURRENT_DATP(lcs,struct link))
138 #define LDAT_FULL() (DATA_FULL(lcs, struct link))
139 #define LDAT_ALLOC() (ALLOC_DAT(lcs, struct link))
140 #define LCS_FULL() (CHUNKS_FULL(lcs))
141 #define INIT_POST() (INIT_STACK(rcs, struct ref))
142 #define CURRENT_POST() (CURRENT_DATP(pcs,struct ref))
143 #define POST_FULL() (DATA_FULL(pcs,struct ref))
144 #define POST_ALLOC() (ALLOC_DAT(pcs,struct ref))
145 #define PCS_FULL() (CHUNKS_FULL(pcs))
146 #define INIT_REF() (INIT_STACK(rcs, struct ref))
147 #define CURRENT_REF() (CURRENT_DATP(rcs,struct ref))
148 #define PREVIOUS_REF() (PREVIOUS_DATP(rcs, struct ref))
149 #define REF_FULL() (DATA_FULL(rcs,struct ref))
150 #define REF_ALLOC() (ALLOC_DAT(rcs,struct ref))
151 #define RCS_FULL() (CHUNKS_FULL(rcs))
153 #define CURRENT_MODEL() (CURRENT_VDAT()->model_list[CURRENT_VDAT()->num_models])
158 /* Cdats: A cdat is a class data structure. Cdats serve as the central */
159 /* data types of the IR. Cdats contain pointers to their subclasses so that the relationship between */
160 /* classes can be determined, but the subclasses are not represented inside */
161 /* of the cdat itself but rather in subsequent cdats in cdat_buf. We */
162 /* can determine the number of subclasses (the last index into cdat_buf */
163 /* that represents a subclass of some arbitrary cdat) each cdat has by */
164 /* incrementing num_classes during parse time. */
165 /* TODO: Should classes point to their parent class? */
166 /* TODO: Talk more about cdat set structure */
173 struct cdat
* class_list
[MAX_CLASSES
];
174 struct set
* set_list
[MAX_SETS
];
181 struct set
* set_list
[MAX_SETS
];
188 int refid
; //0xFFFFFF->digit
197 struct name src_animname
;
198 struct name src_namelist
[MAX_DEPTH
];
203 struct name src_mapname
;
204 struct name src_namelist
[MAX_DEPTH
];
215 /* Links are a mechanism for designers to indicate in the grammar that a odat, vdat, or map
216 is defined elsewhere and that the link should be replaced with the specified odat/vdat/map */
218 int type
; //1 = olink, 2 = vlink, 3 = mlink
220 int dest_refid
; //if it exists
221 struct odat
* dest_odatp
;
229 uint8_t filepath
[FPATH_MAX
];
232 /* Odats: Odats consist of the object data necessary for
233 each object. Odats are sometimes referred to as archetypes
234 at compile-time, in order to distinguish the difference from
235 a runtime object and a compile-time object.
236 TODO: Need more info about objects at runtime, to described
237 the reasoning behind odat structure at compile-time*/
245 struct odat
* parent_odatp
; /* null if parent is a cdat */
246 struct ref
* refp
; /* pointer to it's ref on ref_list */
247 struct map map
; /* only valid if odat ismap */
251 /* A framesheet is a grouping of animation frames in a single direction (N,W,S,E, etc.). Framesheets
252 also hold the framesheet dimensions and the filepath to the png of the framesheet so the file can be opened
253 and the png data can be extracted. */
257 uint8_t filepath
[FPATH_MAX
];
262 /* A model is a collection of framesheets for every
263 direction (N,W,S,E,NW,NE,SW,SE). Currently, users can only define
264 framesheets in the APC grammar, which are inserted into the current model*/
267 struct framesheet spritesheet
[8]; //one for each
270 /* Vdat: Vdats are the video data of each object. Vdats have a list of models for every
271 animation that the vdats odat can do for that vdat. */
273 struct odat
* creator
; //pointer to odat that made this vdat
275 struct model model_list
[MAX_MODELS
];
278 /* An entry on the set_stack that describes the namelist and relevant information for
279 the current set that is being processed in the parser. For each set name,
280 there is a corresponding set/odat that is created when set names are encountered. */
283 { struct name namelist
[MAX_DEPTH
];
289 /* Stores the last defined set at every depth */
291 { struct set_frame set_frames
[MAX_DEPTH
];
292 int curr_depth
; //used to get most recently created set/odat + to check for undefined parents of namelists
296 //"type free" chunk stacking
298 { void* chunks
[MAX_CHUNKS
];
299 void* *csp
; //chunk stack pointer
300 void* dsp
[MAX_CHUNKS
]; //dat stack pointer (per chunk)
301 int chunk_size
; //size of a chunk (including its forfeited page)
302 int max_dats
; //number of dats per chunk for this stack
303 } ocs
, vcs
, ccs
, rcs
, lcs
, pcs
, scs
; //odat, vdat, cdat, ref, link, post stacks
305 /* The cdat_stack is a stack pointers to cdat pointers, the top of which is
306 the cdat that is currently being parsed. Whenever a new cdat is recognized
307 by the grammar (CLOPEN), a cdat is pushed onto the cdat_stack, and we refer
308 to this cdat through the macro CURR_CDAT. By keeping a cdat_stack, we have
309 access to the current cdat so that the elements and sets can populate themselves
310 in the cdat accordingly. */
312 struct cdat
* cdat_stack
[MAX_CLASSES
];
313 struct cdat
** cdat_stackp
;
318 struct name set_namelist
[MAX_DEPTH
];
319 int set_numnames
= 0;
321 struct name link_namelist
[MAX_DEPTH
];
322 int link_numnames
= 0;
329 int ss_refid
= 0x0FFFFFFF; /* system space for refids */
336 /* The initalization function of the IR. */
342 uint8_t root
[4] = "root";
344 u8_stpncpy(name
.name
, root
, 4);
346 pagesize
= sysconf(_SC_PAGESIZE
);
349 *cdat_stackp
= CURRENT_CDAT();
350 name_u8_cpy(&(*cdat_stackp
)->name
, &name
);
354 VDAT_ALLOC(); //NULL vdat
355 VDAT_ALLOC(); //First vdat req. because alloc_vdat happens after vdat is reduced
371 for(i
= 0; i
< CHUNKS_LEN(ccs
) ; i
++)
375 for(i
= 0; i
< CHUNKS_LEN(ocs
); i
++)
379 for(i
= 0; i
< CHUNKS_LEN(vcs
) ; i
++)
383 for(i
= 0; i
< CHUNKS_LEN(rcs
); i
++)
387 for(i
= 0; i
< CHUNKS_LEN(lcs
); i
++)
391 for(i
= 0; i
< CHUNKS_LEN(pcs
); i
++)
404 { fprintf(stderr
, "You have allocated to many (%d) cdats ", num_cdats
);
413 return CURRENT_CDAT();
416 //these should probably be inline
424 { fprintf(stderr
, "You have allocated to many (%d) odats ", num_odats
);
433 return CURRENT_ODAT();
442 { fprintf(stderr
, "You have allocated to many (%d) vdats ", num_vdats
);
460 { fprintf(stderr
, "You have allocated to many (%d) sets ", num_sets
);
469 return CURRENT_SET();
479 { fprintf(stderr
, "You have allocated to many (%d) links ", num_links
);
488 return CURRENT_LINK();
498 { fprintf(stderr
, "You have allocated to many (%d) refs ", num_refs
);
508 if(num_refs
% 16 == 0)
509 { CURRENT_POST() = CURRENT_REF();
513 return CURRENT_REF();
521 { fprintf(stderr
, "You have allocated to many (%d) refs ", num_posts
);
536 return (*cdat_stackp
);
543 return CURRENT_ODAT();
550 return CURRENT_VDAT();
556 return CURRENT_SET();
563 return CURRENT_REF();
569 return PREVIOUS_REF();
575 return &CURRENT_MODEL();
581 ( struct name
* name
)
583 struct cdat
* curr_cdatp
;
585 curr_cdatp
= alloc_cdat();
587 name_u8_cpy(&curr_cdatp
->name
, name
);
588 curr_cdatp
->idx
= num_cdats
;
590 /* Set the cdat as a subclass of the previous cdat */
591 (*cdat_stackp
)->class_list
[(*cdat_stackp
)->num_classes
++] = curr_cdatp
;
592 /* Push the cdat onto the cdat_stack */
593 *++cdat_stackp
= curr_cdatp
;
608 ( struct name
* name
)
610 //Push name onto current namelist, set the set_namelist.
611 name_u8_cpy(&set_namelist
[set_numnames
++], name
);
616 /* Called at the last name of a sets namelist. Inserts the set namelist
617 onto the set_stack at the appropriate depth i.e. the number of names in
618 the namelist. If each name in the namelist at every depth matches, nothing happens. For every
619 name on the namelist that doesnt match what is currently on the set_stack,
620 a new set/odat is created at the depth that it describes. E.g. a set name
621 of A_B_C is a depth of 3 and is represented in the set_stack as A, A_B and A_B_C.
622 If a new set namelist is defined, X_Y, the new set_stack will become X, X_Y. */
626 ( struct name
* name
)
627 { int depth
, nameidx
, i
;
629 insert_set_name(name
);
632 for( depth
= 0; depth
< set_numnames
; depth
++ )
633 { for (nameidx
= 0; nameidx
<= depth
; nameidx
++)
634 { if( name_u8_cmp(&set_namelist
[nameidx
], &ss
.set_frames
[depth
].namelist
[nameidx
]) != 0 )
635 { /* Populate the namelist of the set at the current depth */
636 for(i
= 0; i
<= depth
; i
++)
637 name_u8_cpy(&ss
.set_frames
[depth
].namelist
[i
], &set_namelist
[i
]);
639 /* Alloc set and odat */
640 ss
.set_frames
[depth
].odatp
= alloc_odat();
641 ss
.set_frames
[depth
].setp
= alloc_set();
643 /* populate set/odat name and cdat_idx */
644 name_u8_cpy(&ss
.set_frames
[depth
].odatp
->name
, &set_namelist
[depth
]);
645 ss
.set_frames
[depth
].setp
->cdat_idx
= ( *cdat_stackp
)->idx
;
647 /* Insert allocated set and odat into their respective trees if there is a depth
648 (they have parents) */
650 { ss
.set_frames
[depth
].odatp
->parent_odatp
= ss
.set_frames
[depth
-1].odatp
;
651 if(ss
.set_frames
[depth
-1].setp
->num_sets
< MAX_SETS
)
652 ss
.set_frames
[depth
-1].setp
->set_list
[ss
.set_frames
[depth
-1].setp
->num_sets
++] = ss
.set_frames
[depth
].setp
;
654 { printf("you have allocated too many sets in insert_namelist()\n");
658 else /* no parent set, so assign to cdat set_list */
659 { ss
.set_frames
[depth
].odatp
->parent_odatp
= NULL
; //no parent odat = NULL.
660 if(curr_cdat_set()->num_sets
< MAX_SETS
)
661 curr_cdat_set()->set_list
[curr_cdat_set()->num_sets
++] = ss
.set_frames
[depth
].setp
;
663 { printf("you have allocated too many sets in insert_namelist()\n");
669 ss
.set_frames
[depth
].num_names
= set_numnames
;
670 ss
.curr_depth
= depth
;
672 /* Every set has a vdat, but some won't be populated because the namelist that instantiated */
673 /* the set might not have a SS statement that populates the models of the vdat. This is ok */
674 /* because 1) IR is supposed to be bloated so that binary out isnt 2) this functionality */
675 /* preserves the assumptions that insert_framesheet() makes when it calls curr_vdat() */
683 /* Set to 0 to reset for next set_namelist */
688 /* We create new odats for each map variant that are children of the current odat/set
689 set their name as the map name, and identify them by marking them as a map. This lets
690 us distinguish between sibling odats that have the same name because the map of the parent
691 odat had the same name as another, regular odat. */
692 #define CURR_SS_FRAME() (ss.set_frames[ss.curr_depth])
693 #define CURR_SS_SETP() (CURR_SS_FRAME().setp)
694 #define CURR_SS_ODATP() (CURR_SS_FRAME().odatp)
697 ( struct name
* name
, int direction
, int height
, int width
, int refid
, uint8_t* filepath
)
699 struct odat
* curr_map_odatp
; //pointer to odat in odat_buf
700 struct set
* curr_map_setp
; //pointer to set in set_buf
703 curr_map_odatp
= alloc_odat();
704 curr_map_setp
= alloc_set();
705 /* Create a new odat, make its parent be the set. Make a set for mdat, its name should */
706 /* be the name of the odat + name of model. That makes a conflict beween odats that are named */
707 /* the same thing as the model of a sibling odat that was created from a map. They can have */
708 /* same name if the map odat is marked. So mark the map odat. */
710 /* insert parent odat */
711 curr_map_odatp
->parent_odatp
= CURR_SS_ODATP();
713 /* insert into set_list */
714 if(CURR_SS_SETP()->num_sets
< MAX_SETS
)
715 CURR_SS_SETP()->set_list
[CURR_SS_SETP()->num_sets
++] = curr_map_setp
;
717 { printf("You have allocated to many sets, error in insert_map()\n");
721 /* indicate that newly created odat is a map */
722 curr_map_odatp
->ismap
= 1;
723 /* set odat and set name */
724 name_u8_cpy(&curr_map_odatp
->name
, name
);
726 /* set cdat idx values for both set and odat */
727 curr_map_setp
->cdat_idx
= num_cdats
;
729 /* Insert map information into the odats map */
730 curr_map_odatp
->map
.height
= height
;
731 curr_map_odatp
->map
.width
= width
;
732 u8_stpncpy(curr_map_odatp
->map
.filepath
, filepath
, FPATH_MAX
);
735 /* Generate refid if needed, put into ref_buf */
739 insert_ref(curr_map_odatp
, refid
);
741 /* If current odatp on stack has a link, then we need to make our own link. just set the vdat_idx */
742 if(CURR_SS_ODATP()->vdat_idx
== 0)
743 { linkp
= alloc_link();
744 linkp
->type
= CURR_SS_ODATP()->linkp
->type
;
745 linkp
->dest_odatp
= CURR_SS_ODATP();
746 linkp
->dest_refid
= refid
;
747 linkp
->link_t
.mlink
.src_refid
= CURR_SS_ODATP()->linkp
->link_t
.mlink
.src_refid
;
749 /* Copy the animation name of the vlink*/
750 name_u8_cpy(&linkp
->link_t
.vlink
.src_animname
, &CURR_SS_ODATP()->linkp
->link_t
.vlink
.src_animname
);
751 /* Copy the namelist of the vlink*/
752 for(i
= 0; i
< MAX_DEPTH
; i
++)
753 name_u8_cpy(&linkp
->link_t
.vlink
.src_namelist
[i
], &CURR_SS_ODATP()->linkp
->link_t
.vlink
.src_namelist
[i
]);
756 curr_map_odatp
->vdat_idx
= CURR_SS_ODATP()->vdat_idx
;
761 /* 11/22 Each vdat has a multiple models. Each model has 8 framesheets, one in each
762 direction, that create a spritesheet. Inserting framesheets into the correct
763 model is just a matter of checking whether or not the last models name matches
764 the current one. We can never get a framesheet that is for the same model before
765 AND after some other model, due to alphasorting of the files in each directory */
768 ( struct name
* model_name
, int direction
, int height
, int width
, int refid
, uint8_t* filepath
)
769 { struct vdat
* curr_vdatp
;
770 struct model
* curr_modelp
;
771 static struct name last_model_name
[32];
773 curr_vdatp
= curr_vdat();
775 /* If the model name changed, that means there are no more
776 framesheets for that model to be processed, a guaruntee we make
777 b/c the filenames are alphabetically sorted */
778 if(!name_u8_cmp(last_model_name
, model_name
))
779 { if(curr_vdatp
->num_models
)
780 curr_vdatp
->num_models
++;
781 num_models
++; // total number of models
785 if(CURR_SS_ODATP()->refid
== 0)
788 insert_ref(CURR_SS_ODATP(), refid
); /* given a odatp and a refid, insert the odatp into the ref_buf. */
791 printf("error: redefining a previously set refid\n");
793 curr_modelp
= curr_model();
795 name_u8_cpy(&curr_modelp
->name
, model_name
);
796 curr_modelp
->spritesheet
[direction
].height
= height
;
797 curr_modelp
->spritesheet
[direction
].width
= width
;
798 u8_stpncpy(curr_modelp
->spritesheet
[direction
].filepath
, filepath
, FPATH_MAX
);
800 name_u8_cpy(last_model_name
, model_name
);
807 ( struct name
* src_mapname
, int src_refid
)
808 { struct link
* linkp
;
811 linkp
= alloc_link();
815 /* set the name of the src map for the link, if a name exists */
817 name_u8_cpy(&linkp
->link_t
.mlink
.src_mapname
, src_mapname
);
818 /* Set the source ref id of the link */
819 linkp
->link_t
.mlink
.src_refid
= src_refid
;
821 /* Copy the entire namelist of the link, if it exists */
822 for(i
= 0; i
< link_numnames
; i
--)
823 { name_u8_cpy(&linkp
->link_t
.mlink
.src_namelist
[i
], &link_namelist
[i
]);
824 name_u8_set(&link_namelist
[i
], (ucs4_t
) 0);
828 linkp
->dest_odatp
= CURR_SS_ODATP();//current odat on set_stack
835 ( struct name
* name
)
837 //Push name onto current namelist, set the set_namelist.
838 name_u8_cpy(&link_namelist
[link_numnames
++], name
);
843 /* Nearly identical to mlink */
846 ( struct name
* src_animname
, int src_refid
)
847 { struct link
* linkp
;
850 linkp
= alloc_link();
855 /* set the name of the src animname for the link, if a name exists */
857 name_u8_cpy(&linkp
->link_t
.vlink
.src_animname
, src_animname
);
859 /* Set the source ref id of the link */
860 linkp
->link_t
.mlink
.src_refid
= src_refid
;
862 /* Copy the entire namelist of the link, if it exists */
863 for(i
= 0; i
< link_numnames
; i
++)
864 { name_u8_cpy(&linkp
->link_t
.vlink
.src_namelist
[i
], &link_namelist
[i
]);
865 name_u8_set(&link_namelist
[i
], (ucs4_t
) 0);//set to null for next link_namelist
869 linkp
->dest_odatp
= CURR_SS_ODATP();//current odat on set_stack
874 /* TODO: Do we really need to store the prev/next pointer? iterating through the
875 ref_buf could be achieved by iterating until the num_refs anyway. */
878 ( struct odat
* odatp
, int refid
)
879 { struct ref
* curr_refp
;
880 struct ref
* prev_refp
;
882 curr_refp
= alloc_ref();
883 prev_refp
= prev_ref();
885 prev_refp
->nextref
= curr_refp
;
886 curr_refp
->lastref
= prev_refp
;
888 curr_refp
->odatp
= odatp
;
889 curr_refp
->refid
= refid
;
893 CURRENT_POST()->refid
= refid
;
894 CURRENT_POST()->odatp
= odatp
;
903 { CURR_SS_ODATP()->refid
= refid
;
910 { struct vdat
* curr_vdatp
;
912 curr_vdatp
= curr_vdat();
914 curr_vdatp
->creator
= CURR_SS_ODATP();
915 CURR_SS_ODATP()->vdat_idx
= num_vdats
;
916 CURR_SS_ODATP()->vdatp
= curr_vdatp
;