Note on bde2gencpp project - RJL 051027 RJLRef: $PH/COOL-GEN/gencpp/gencppComparison/testgenv12bde/aareadme_testgenv12bde Update 051027 to aareadme_testgenv12bde in $PH/COOL-GEN/gencpp/gencppComparison/testgenv12bde. This is an update to my 02f522 test of the bde2gencpcp refactoring project. My goal here was just to compare the size of the generated source code to bde/pr_util. The generated code replaces bde's pr_util.a library. bde/src code was not refactored to permit compilation. The option -DUSE_STL is NOT used when running gencpp. The example below shows that gencpp generates code with conditional compilation. -DUSE_STL is an option used when compiling a gencpp application like bde. I did use the gencpp -metafile and -log options below. Gencpp produced logging code in each class's set_field functions (get_field is not logged.) It also generates pr_log.c and o [??? lost content-RJL] void HN::log_do_set_key_row (const char fieldname[NAMELENGTH+1], hcg_key new_key) { if (strcmp(fieldname,"HNid")==0) #ifdef USE_STL set_pkid (new_key); #else RC::set_pkid (new_key); #endif else if (strcmp(fieldname,"HGid")==0) HGid = new_key; } I concatenated metaschema.sch with 94sbde_schema.sch to produce bdeschema.sch, which was fed to gencpp: 'gencpp -metafile -log bdeschema.sch' So gencpp generated bdeschema.h and files XXops.cc and XXschema.h for every table type XX in the metaschema and bde's data model. (LCP SM tables could also be inserted BETWEEN metatables and bde application tables.) PLEASE INSPECT THE GENERATED CODE, and note its uniformity (if you understand one file you understand them all). NO REFACTORING OF BDE/SRC CODE WAS DONE TO COMPILE THIS CODE. Also read Naiayana's comments on refactoring in my last message. HNops.cc in this directory comments that RFLAG is not used to protect set_field calls inside of row-class constructors from getting logged (because the constructor logs the completed row-object instead). pr_log.cc is also generated by gencpp -log. This file from chgen has pr_replay and replay_log functions. Here is an extract from pr_log.c showing code to create and log an HN_row object: ---------------- int log_do_add(char *view, char *tablename, char *theRest) { int status = 0; /* the return status of the function */ int idx = 0; /* parsing temp index */ char pkey[HCG_KEY_SIZE+1]; int tablename_size; int tbl_encoding; #ifndef USE_STL struct SV *SV_elt; struct TT *TT_elt; ... struct HG *HG_elt; struct HN *HN_elt; ... struct GX *GX_elt; #else SV *SV_elt; TT *TT_elt; ... HG *HG_elt; HN *HN_elt; ... GX *GX_elt; #endif if (!find_tbl_idx(tablename)) { fprintf(stderr, "%s: %d: log_do_add: unknown table (%s) found in log\n", __FILE__, __LINE__, tablename); return -1; } tbl_encoding = encoding(hcg_table_seq_list[hcg_tbl_idx].ttabbrev); /* global hcg_tbl_idx is set by find_tbl_idx */ /* the following switch statement is adapted from the one in pr_parse */ switch( tbl_encoding ) { ... case 8: /* encoding of HN */ #ifndef USE_STL HN_elt = HN_elt->create_row(); //???HN_elt is a pre-req to HN_elt??? // Why? HN::create_row is a class not instance method? #else HN_elt = new HN; #endif if (!HN_elt) fprintf(stderr,"%s: %d: do_log_add: pr_create failed\n", __FILE__, __LINE__); else HN_elt->log_do_add_row (view, theRest, idx); break; ----------- HNops.cc also contains functions like log_do_set__row functions which replay he log file; e.g. for HN, -------------- void HN::log_do_set_key_row (const char fieldname[NAMELENGTH+1], hcg_key new_key) { if (strcmp(fieldname,"HNid")==0) #ifdef USE_STL set_pkid (new_key); #else RC::set_pkid (new_key); #endif else if (strcmp(fieldname,"HGid")==0) HGid = new_key; } ------------- (I picked this one because the bugs in pr_set_key from chgen are repeated above, UNLESS the generic method set_pkid that is over- ridden by each row class does the right stuff for the intrusive list ptrs associated with fkey fields.) HNops.cc and HNschema.h do not implement set_pkid; Here is its implementation as a method of root class RC at the end of bdeschema.h: Is RC a worthy ancestor? Note that very little can be inherited from RC. It contains only pkid and RFLAG data members. [I used to worry about a root class having the pkid for any table row. Then I realized that compressed pkeys are integers, and each table had a pre-allocatabed sub-range of pkid values. So moving them to class RC is not a problem, assuming these sub-range constrains are respected when saving and reloading.] [RJL 060212: But what is the value of RC as a root-class? If 'this' points to an RC_object, its pkey must be dissected to switch to the correct down-cast call to the over-riding sub-row-class method. This is not a good option. C++ (and I) prefer 'this' to point to the correct leaf-node subclass, so this->method directly executes the over-ride. With chgen, the pkey must be referenced indirectly; with gencpp it can be inherited from the RC-superclass object. In order for gencpp-proeduced C++ code to inherigt the RC's pkey, gencpcp must generate c'tors that call superclass c'tors, so g++ is aware of pkey inheritance. That's fine with me, but chgen was never extended to make this happen: chgen expected the programmer to build ancestor objects with additional pr_create, pr_set*,...,pr_add call sequences. I don't know what gencpp does in this case. - RJL 060212] It is clear that method set_pkid will not handle fkey updates. I fear that set_fkid (or set_idref, analogous to XML's IDREF) is not supported for log/replay. Nor should it be until it can handle is associated pointers. ------------ /******************************************************************************/ /* Class: RC (Root Class) */ /******************************************************************************/ class RC { private : hcg_key pkid; int RFLAG; /* for pr_utility macro log */ public : void set_pkid (hcg_key id) { pkid = id; } void set_RFLAG (int flag) { RFLAG = flag; } hcg_key get_pkid () { return pkid; } int get_RFLAG () { return RFLAG; } } ; ---------------------- ============================================================= aareadme_testgenv12bde - RJL050913 in $PH/COOL-GEN/gencpp/gencppComparison/testgenv12bde (relocated from ~/02f522/gencpp/testgenv12bde - RJL 021105) Update 021110: RJL 021110: EVERY string not in last-column field position MUST be non-zero length! This applies to all table types - WARNING: gencpp stores null string ("\0" value) defaults. When pr_dumped, these fields disappear - unless non-blank values are assigned first. FO has 8K fewer bytes and 226 fewer lines than GD (both have no parent or child tables) This is because table FO is NOT in the .sch file and therefore changes are not logged.: ------------------ saturn.cs.uml.edu(200)> lg FOops.cc GDops.cc -rw-r--r-- 1 lechner fac 20814 Nov 5 20:14 FOops.cc -rw-r--r-- 1 lechner fac 28404 Nov 10 23:08 GDops.cc saturn.cs.uml.edu(201)> wc FOops.cc GDops.cc 643 1860 20814 FOops.cc 869 2556 28404 GDops.cc 1512 4416 49218 total -------------------- meets_view is disabled: it is defined as {return 1;} at pr_load.cc:278. End of 021110 update ------------ This directory is to test bde with gencpp. I concatenated metaschema.sch with 94sbde_schema.sch to produce bdeschema.sch, then I updated many obsolete comments in bdeschema.sch to reflect current plans for bde. The gencpp executable has pr*.c code from genv12 metaschema.sch. It is located at ~/02f522/gencpp/testgenv12/bin/alpha/gencpp When I ran this gencpp with options -metafile -ansi -log on bdeschema.sch containing 15 table declarations, the number of auto-generated source code lines is counted as follows: ---------------- [saturn.cs.uml.edu1](15)> cat bdeschema.sch | wc 200 1841 11251 [saturn.cs.uml.edu1](16)> cat *.h | wc 4224 18925 170798 [saturn.cs.uml.edu1](17)> cat *.cc | wc 16998 47784 520013 --------------- I.e., from 200 lines of schema table definitions, gencpp generated more than 21K lines of source code. This can be compared to bde/pr_util from chgenv12: --------- setenv RL ~/bde2alpha_rl/sandbox/bdecheckout/bde cat $RL/schema/94s*.sch | wc 180 1752 10404 cat $RL/pr_util/*.h|wc 1120 5226 50395 cat $RL/pr_util/*.c|wc 5631 17526 180536 -------- I.e., 180 lines declaring 10 bde table types generated 6751 lines of *.h and *.c code. This is a warning about how big the source code might grow, unless templates are exploited more intensively. Of course, pr_util/*.c code has many more macro expansions than the .cc code, so the runtime .exe size may not differ as much as the source code size. here is a direct comparison of pr*.c and pr*.cc sizes (not much different): -------------------- saturn.cs.uml.edu(165)> pwd ; wc pr*.cc ; cd $BDE/pr_util;pwd; wc pr*.c ; echo; cd ~/02f522/gencpp/testgenv12bde /usr/cs/fac1/lechner/02f522/gencpp/testgenv12bde 44 139 1554 pr_delete.cc 187 504 5522 pr_dump.cc 74 156 1835 pr_free.cc 2407 7244 69683 pr_load.cc 2010 5979 59726 pr_log.cc 137 470 4950 pr_stats.cc 4859 14492 143270 total /usr/cs/fac1/lechner/bde2alpha_rl/sandbox/bdecheckout/bde/pr_util 312 1083 10318 pr_delete.c 266 897 9842 pr_dump.c 50 162 1756 pr_free.c 2849 8940 90562 pr_load.c 2048 6058 63742 pr_log.c 106 386 4316 pr_stats.c 5631 17526 180536 total ---------------------