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