@global dynamictypes_defined; /* This file provides the ability to create dynamic types, or types that change based on their content. For example, consider the following vector type: struct Vector { unsigned int size; int* data; }; The data pointer is actually an array of length specified by size. With dynamic typing, one can specify types where objects of the above type can be translated into the appropriate: stuct Vector { unsigned int size; int data[size]; }; The basic idea is to include an extra mapping in fields for the keyword "refine", which specifies a function for performing the transformation. Then for a pointer to an object p, one can call refine(p) to create a pointer that points to the refined version of the type of p. */ if (dynamictypes_defined == nil) { @local unrollTypedef; @global REFINE_KEY, refine, dynamictypes_example; dynamictypes_defined = 1; REFINE_KEY = "refine"; @define unrollTypedef(t) { while (istypedef(t)) t = typedeftype(t); return t; } /** * Refines the type of the pointer p. * params: p is a pointer whose type is being refined * output: a pointer p', which has the same value as p but has a refined type (if the original type of p supported refinement). */ @define refine(p) { @local t, flds, new_flds, i, new_sz, new_t; t = unrollTypedef(@typeof(p)); if (!isptr(t)) return p; t = unrollTypedef(subtype(t)); if (!isstruct(t)) return p; if (!ismapped(p,sizeof(t))) return p; flds = fields(t); new_flds = mkvec(length(flds)); new_sz = 0; for(i=0; i new_sz) new_sz = fld_sz; } else { @local new_off, new_t; [new_off,new_t] = refiner(p); new_flds[i] = mkfield(new_t,fieldid(flds[i]),new_off); new_flds[i][2] = copy(flds[i][2]); new_flds[i][2]["offset"] = new_off; fld_sz = sizeof(symtype(new_flds[i]))+new_off; if (fld_sz > new_sz) new_sz = fld_sz; } } new_t = mkctype_struct(suetag(t),new_flds,new_sz); return {mkctype_ptr(new_t,nsptr(domof(p)))}p; } /** An example of how one might use dynamic types. */ @define dynamictypes_example() { @local ns,dom,q,i; @include ns = @names c64le { struct Vector { @0 int size; @["offset" : 4, REFINE_KEY : @lambda(p) { @local dom; dom = domof(p); return [4,mkctype_array(@typeof(dom`int), p->size)]; }] int data[]; @0x8; }; enum TYPE { T_INT = 0, T_VEC = 1 }; struct EnumPtr { @0x0 int type; @["offset" : 0x4, REFINE_KEY : @lambda(p) { @local dom; dom = domof(p); switch (p->type) { case dom`T_INT: return [4,@typeof(dom`int*)]; case dom`T_VEC: return [4, subtype( @typeof(struct dom`Vector*))]; } return [4,@typeof(dom`int)]; } ] void* contents; @0x8; }; @0x8 struct Vector vector; }; dom = mkdom(ns,mkzas(1024)); //initialize the dom q = &dom`vector; q->size = 5; q = refine(q); for(i=0; isize; ++i) q->data[i] = i*i; q++; q->size = 3; q = refine(q); for(i=0; isize; ++i) { q->data[i] = i*i*i; } printf("%s\n",objectStr(q)); q++; q = (struct dom`EnumPtr*)q; q->type = dom`T_INT; q = refine(q); q->contents = &(dom`vector.data[3]); //traversing the data struct q = &dom`vector; printf("Pre-refinement:\n"); printf("%s\n",objectStr(q)); q = refine(q); printf("Post-refinement:\n"); printf("%s\n",objectStr(q)); printf("Type size: %d bytes (dec)\n",sizeof(subtype(@typeof(q)))); q = refine(q+1); printf("%s\n",objectStr(q)); q = (struct dom`EnumPtr*)(q+1); printf("Pre-refinement:\n"); printf("%s\n",objectStr(q)); q = refine(q); printf("Post-refinement:\n"); printf("%s\n",objectStr(q)); } //dynamictypes_example(); }