Limited Semi-PolyMorphic (LSP) structs?
Era Scarecrow
rtcvb32 at yahoo.com
Tue Aug 27 21:45:11 PDT 2013
On Wednesday, 28 August 2013 at 03:45:06 UTC, Andre Artus wrote:
> Era,
>
> I haven't had time to go through your everything you wrote here
> but are you looking to create some form of discriminated union
> (AKA tagged union) using D structs?
>
> Do you have a specific problem you need to solve, or are you
> just exploring the language?
The tagged union struct does sorta match the basic idea. What i
have is a structure that basically is just a single struct,
however it's semi-polymorphic. (I guess that's obvious by the
subject). What changes is only really behavior and rarely would
it actually add more data, so inheriting and OOP fits it fairly
well, however since structs can't inherit it becomes an issue. I
can either inherit, or i can make the function(s) large and
clunky and basically do it as C.
ie:
struct AB {
char type;
void A() {
if (type == 'A') {
}
if (type == 'B') {
}
}
}
Etc. One of the biggest reasons to modify the behavior is for
the records/subrecords i'm working on they need to build their
identifiers based on what they are. Locations give X,Y, if it's
an NPC, their name, if it's a texture the texture name, if it's a
Dialog it needs to create a hash and append it to the ID
afterwards. These are just a few. If i can inherit all the
individual creations shorten to less than 10 lines per, otherwise
i have a massive function.
Here's one such function: Mind you this is from C and the code
is already hard to follow. Inheritance simplifies and breaks it
apart easier, but they don't NEED the full polymorphism & classes
(and vTables), I'd rather make overriding structs and 'build_ID'
per the individual (and unique cases), but I don't want to have
to manage it that way.
To note "memcmp(rec->name, "PGRD", N_LEN)" is the test for the
polymorphism. Records and subrecords are identified by a 4
character string.
[code]
/*builds the record's ID name that will be used with sorting and
search
routines. Appends appropriate order information for DIAL's and
makes
all INFO's unique (known to have duplicates sometimes).
*/
void build_ID(Record *rec) {
//build the ID string to identify this for speedy searches.
memset(rec->ID, 0, REC_ID_SIZE);
memcpy(rec->ID, rec->name, N_LEN);
rec->ID[N_LEN] = '_';
SubRecord *sr = find_SubRecord(rec, "NAME", NULL);
SubRecord *sr2 = find_SubRecord(rec, "INDX", NULL);
if (sr) {
int i = sr->size;
if (sr->size > (REC_ID_SIZE - 6))
i = REC_ID_SIZE - 6;
strncpy(rec->ID + N_LEN + 1, sr->data, i); //possible buffer
overrun without limiter.
} else if (sr2 && memcmp(rec->name, "SKIL", N_LEN) == 0){
struct flags_paired *flag_output[MAX_FLAGS];
flag_output[0] = NULL; //clear it out.
get_str_flag(flag_output, "ISkill ID", *(sr2->number));
sprintf(rec->ID, "SKIL_%02d - %s", *(sr2->number),
flag_output[0]->string);
return;
} else if (sr2 && memcmp(rec->name, "MGEF", N_LEN) == 0){
struct flags_paired *flag_output[MAX_FLAGS];
flag_output[0] = NULL; //clear it out.
get_str_flag(flag_output, "IMagicEffect Index",
*(sr2->number));
sprintf(rec->ID, "MGEF_%03d - %s", *(sr2->number),
flag_output[0]->string);
return;
}
if (memcmp(rec->name, "CELL", N_LEN) == 0) {
int *x, *y, *z;
sr2 = find_SubRecord(rec, "RGNN", NULL);
if (sr2 && (strlen_safe(rec->ID, REC_ID_SIZE) +
strlen_safe(sr2->data, sr2->size) < REC_ID_SIZE)) {
sprintf(rec->ID + strlen_safe(rec->ID, REC_ID_SIZE),
"%s%s", ((strlen(rec->ID) > 5) ? ", " : ""), sr2->string);
}
sr = find_SubRecord(rec, "DATA", NULL);
if (sr) { //if it's interrior, the previous name will do.
x = sr->data + 4;
y = sr->data + 8;
z = sr->data;
if ((*z & 1) == 0) { //ensure it's exterior when appending
location
rec->ID[REC_ID_SIZE - 13] = 0; //Forces truncation if
too long
sprintf(rec->ID + strlen_safe(rec->ID, REC_ID_SIZE), " -
%04d,%04d", *x, *y);
} else { //ensure cleanup of x ,y
*x = 0;
*y = 0;
}
}
}
if (memcmp(rec->name, "DIAL", N_LEN) == 0) {
//prefixes for sorting. In this order.
//Journals, Dialogs, Greetings.
//this is due to noticing a 'oath of silence' always coming up
for no reason.
//apparently the journal and other entries must come before
they are called.
char *name = sr->data; //from previous sr
char *type = "U"; //U stands for Unknown.
sr = find_SubRecord(rec, "DATA", NULL);
if (sr)
type = sr->data;
char letter = 'Z';
switch(*type) {
case 4: //Journal
letter = 'A'; break;
case 0: //regular topic
letter = 'B'; break;
case 2: //Greeting
letter = 'C'; break;
case 3: //Persuasion
letter = 'D'; break;
case 1: //Voice
letter = 'E'; break;
case 'U': //default unknown.
letter = 'U'; break;
}
sprintf(rec->ID, "DIAL_%c_%s", letter, name);
}
if (memcmp(rec->name, "INFO", N_LEN) == 0) {
sr = find_SubRecord(rec, "INAM", NULL);
if (sr) {
strncpy(rec->ID + N_LEN + 1, sr->data, REC_ID_SIZE - 7);
return;
}
}
if (memcmp(rec->name, "SCPT", N_LEN) == 0) {
sr = find_SubRecord(rec, "SCHD", NULL);
if (sr) {
strncpy(rec->ID + N_LEN + 1, sr->data, 32); //first 32's
the name
return;
}
}
if (memcmp(rec->name, "PGRD", N_LEN) == 0) {
//sr should still be valid...
sr = find_SubRecord(rec, "DATA", NULL);
if (sr) {
int *i_val = sr->data, sz;
sz = strlen_safe(rec->ID, REC_ID_SIZE);
if (sz > (REC_ID_SIZE - 12))
sz = REC_ID_SIZE - 12;
if (*i_val || i_val[1]) {
rec->ID[REC_ID_SIZE - 13] = 0; //Forces truncation if
too long
sprintf(rec->ID + sz, " - %04d,%04d", *i_val, *(i_val +
1));
}
return;
}
}
if (strlen_safe(rec->ID, REC_ID_SIZE) <= N_LEN + 1 &&
(memcmp(rec->name, "TES3", N_LEN) != 0 &&
memcmp(rec->name, "LAND", N_LEN) != 0)) {
sr = find_SubRecord(rec, "DATA", NULL);
if (sr) {
int *i_val = sr->data;
sprintf(rec->ID + N_LEN, " - %08d", *i_val); //first 32
are the name
}
}
if (strlen_safe(rec->ID, REC_ID_SIZE) <= N_LEN + 1 ||
memcmp(rec->name, "LAND", N_LEN) == 0) {
//see if an Index INDX or INTV would work
sr = find_SubRecord(rec, "INTV", NULL);
if (sr == NULL)
sr = find_SubRecord(rec, "INDX", NULL);
if (sr) {
int *i_val = sr->data;
rec->ID[REC_ID_SIZE - 13] = 0; //Forces truncation if too
long
if (sr->size == 8) { //first 32 are the name
if (memcmp(rec->name, "LAND", N_LEN)) {
rec->ID[REC_ID_SIZE - 18] = 0; //Forces truncation if
too long
sprintf(rec->ID + strlen_safe(rec->ID, REC_ID_SIZE), "-
Index %04d,%04d", *i_val, *(i_val + 1));
} else //if it's land, we match CELL format.
sprintf(rec->ID + strlen_safe(rec->ID, REC_ID_SIZE), "
- %04d,%04d", *i_val, *(i_val + 1));
} else
sprintf(rec->ID + strlen_safe(rec->ID, REC_ID_SIZE), "-
Index %04d", *i_val); //first 32 are the name
return;
}
}
}
[/code]
More information about the Digitalmars-d-learn
mailing list