/*serialization3.m. Begin from serialization1.m Here's the idea. There is a List It contains Data objects Each Data object contains a variety of variables and containers. Data objects can have Lists, Maps, as well as arrays of ints and doubles, and these may even be dynamically allocated. In this example, the lispOutDeep: code calls the function lisp_process_array() to save the dynamic arrays of doubles and ints. The compiler complains that it does not know about this function, but the program runs anyway. lisp_process_array() is in swarm's src/defobjc/internal.h file, but when I build swarm, that file does not get copied into the install directory. I don't know yet what is needed to deal with it. I will get to it. The other serialization work is taken care of by [super lispOutVars: stream deep: YES]; Then run ./serialize3 -m create and look over collection.scm. Then run ./serialize3 to bring the list back to life. One Gotcha I discovered. Watch out to not include things in Data's createEnd method. When the archiver creates objects, it allocates memory for variables and if you have code in createEnd, it will stomp on the variables that the archiver has already set. To avoid that, there is now a buildObjects in Data that is called when objects are first created, but it is not called when they are reborn by the serializer.. Requires Swarm newer than 2002-02-06 Add the cpp flag DYN_MEM to use dynamically allocated arrays inside the Data class. By Paul Johnson Adapted from a post by Marcus Daniels Mar 29, 2000 swarm-support email and including "lispOutDeep" method by Marcus, Feb. 6, 2002 */ #import // initSwarm #import // Archivers #import // CreateDrop #import // getZone #define CATEGORY_COUNT 12 #define SCALE_COUNT 7 @interface Integer: CreateDrop { int value; } - setInt: (int)theValue; - (int)getInt; @end @implementation Integer - setInt: (int)theValue { value = theValue; printf("INTEGER CREATED: %d\n", theValue); return self; } - (int)getInt { return value; } @end #define INTEGER(value) \ [[[Integer createBegin: scratchZone] createEnd] setInt: value] @interface Data: CreateDrop { const char *date; double someDouble; int someInt; id myList; #ifndef DYN_MEM int category[CATEGORY_COUNT]; double scales[SCALE_COUNT]; #else int * category; double * scales; #endif } - createEnd; - buildObjects; - setDate: (const char *)date; - (void)describe: stream; - (double)getValue; - setVal: (double)value; - (void)lispOutDeep: stream; @end @implementation Data - createEnd { return [super createEnd]; } //can't dump these into createEnd, because createEnd gets run //automatically when lisp loads these objects again. - buildObjects { int i, randNumber1; randNumber1 = [uniformIntRand getIntegerWithMin: 0L withMax: 5L]; #ifdef DYN_MEM printf("DYN_MEM is set\n"); scales = [globalZone allocBlock: (SCALE_COUNT* sizeof(double)) ]; category = [globalZone allocBlock: (CATEGORY_COUNT* sizeof(int))]; #endif myList = [List create: [self getZone]]; for ( i = 0; i < randNumber1; i++) { int randNumber2 = [uniformIntRand getIntegerWithMin: 10L withMax: 20L]; [myList addLast: INTEGER(randNumber2)]; } someInt = 55; return self; } - setDate: (const char *)theDate { date = STRDUP (theDate); return self; } - setVal: (double)theValue { int i; someDouble = theValue; for (i = 0; i < CATEGORY_COUNT; i++) { category[i] = i; } for (i = 0; i < SCALE_COUNT; i++) { scales[i] = [uniformDblRand getDoubleWithMin:0 withMax:1L]; } return self; } - (void)describe: stream { int i; id anObject, index; [stream catC: "Hello, I'm a Data object. Here's my story \n"]; [stream catC: "Date: "]; [stream catC: date]; [stream catC: " someDouble: "]; [stream catDouble: someDouble]; [stream catC: "\nHere is myList. It is a bunch of objects storing integers. I have "]; [stream catInt: [myList getCount]]; [stream catC: " items in myList. Their values are:" ]; index = [myList begin: getZone(self)]; while (( anObject = [index next]) ) { [stream catC: " "]; [stream catInt: [anObject getInt]] ; } [stream catC: " \n"]; [stream catC: " The integer array called category: "]; for (i = 0; i < CATEGORY_COUNT; i++) { [stream catInt: category[i]]; [stream catC: " "]; } [stream catC: "\n And the double valued array called scale: "]; for (i = 0; i < SCALE_COUNT; i++) { [stream catDouble: scales[i]]; [stream catC: " "]; } [stream catC: "\n"]; } - (double)getValue { return someDouble; } - (void)lispOutDeep: stream { int categoryCount = CATEGORY_COUNT; int scaleCount = SCALE_COUNT; [stream catStartMakeInstance: "Data"]; //This method saves variables that are not explicitly saved by the array commands below. //I'm generally confused what it does... [super lispOutVars: stream deep: YES]; #ifdef DYN_MEM [stream catSeparator]; [stream catKeyword: "category"]; [stream catSeparator]; lisp_process_array (1, &categoryCount, fcall_type_sint, category, NULL, stream, NO); [stream catSeparator]; [stream catKeyword: "scales"]; [stream catSeparator]; lisp_process_array (1, &scaleCount, fcall_type_double, scales, NULL, stream, NO); #endif [stream catEndMakeInstance]; } @end @interface Controller: CreateDrop { id collection; } - createList; @end #define NAME "myCollection" @implementation Controller #define DATA(date,value) \ [[[[[Data createBegin: getZone (self)] createEnd] buildObjects] setDate: date] setVal: value] - createList { collection = [List create: getZone (self)]; [collection addLast: DATA ("1999-01-01", 1.0)]; [collection addLast: DATA ("1999-01-02", 2.0)]; [collection addLast: DATA ("1999-12-31", 3.0)]; return collection; } @end int main (int argc, const char **argv) { id archiver; id controller; initSwarmBatch (argc, argv); #ifdef USE_HDF5 archiver = [HDF5Archiver create: globalZone setPath: "collection.hdf"]; #else archiver = [[[LispArchiver createBegin: globalZone] setPath: "collection.scm"] createEnd]; #endif controller = [Controller create: globalZone]; if (strcmp ([arguments getAppModeString], "create") == 0) { id list = [controller createList]; [archiver putDeep: NAME object: list]; #ifndef USE_HDF5 [archiver sync]; //required only for Lisp anymore? #endif } else { id collection; collection = [archiver getObject: NAME]; xfprint (collection); } [archiver drop]; //must drop to make it write in hdf5 mode. Replaces effect of sync? return 0; } /* Local Variables: compile-command: "$SWARMHOME/bin/libtool-swarm --mode=link gcc3 -DDYN_MEM -D_GNU_SOURCE -o serialize3 -Wall -g -Wno-import -I$SWARMHOME/include -I$SWARMHOME/include/swarm -L$SWARMHOME/lib -L$SWARMHOME/lib/swarm serialization3.m -lswarm -lobjc " End: */