/*serialization.m. By Paul Johnson March 6, 2002 Adapted from a post by Marcus Daniels Mar 29, 2000 swarm-support email (which was archived as http://lark.cc.ku.edu/~pauljohn/SwarmFaq/WorkingExampleCode/objc/HDF5orLispListsInOut.m) and including "lispOutDeep" method created by Marcus, Feb. 6, 2002 Requires Swarm newer than 2002-02-05 This is a serialization example that shows how to serialize dynamically allocated arrays and reload them. This currently works in Lisp to write and read. The default build uses statically allocated memory. Add the cpp flag -DDYN_MEM to use dynamically allocated arrays inside the Data class. Please note the fundamental importance of the lispOutDeep method in the Data class. That method has explicit code that writes the dynamically allocated arrays. That method "catches" all the other IVARs with [super lispOutVars: stream deep: YES]; The super class's lispOutVars:deep: method is inherited from high up in the SwarmObject hierarchy, and it writes out all primitives (doubles, ints, and such) as well as triggering Swarm's archiving routines for Swarm Lists and other things Swarm knows how to archive. If there are statically allocated arrays, it will also find/save them as well. If the Data object has references to things you don't want saved along with the object, then don't do it that way. There are commands that can be used to save particular variables. This is able to write and read static arrays in lisp format. With Marcus's help, I can write and read dynamically allocated arrays in Lisp/scm format. I am able to write static arrays in hfd5 format. I get seg faults when I try to load the hdf5 format files. To save data use: ./serialize1 -m create ./serialize1 to read the saved data back in and generate some printout. I cut out the MAP compiler flag and map related examples to reduce distraction. */ #import // initSwarm #import // Archivers #import // CreateDrop #import // getZone #define CATEGORY_COUNT 12 #define SCALE_COUNT 7 @interface Data: CreateDrop { const char *date; double value; #ifndef DYN_MEM int category[CATEGORY_COUNT]; double scales[SCALE_COUNT]; #else int * category; double * scales; #endif } #ifdef DYN_MEM - createEnd; #endif - setDate: (const char *)date; - (void)describe: stream; - (double)getValue; - setVal: (double)value; - (void)lispOutDeep: stream; #ifdef DYN_MEM - hdf5OutDeep: (id )hdf5obj; #endif @end @implementation Data #ifdef DYN_MEM - createEnd { printf("DYN_MEM is set\n"); scales = [globalZone allocBlock: (SCALE_COUNT* sizeof(double)) ]; category = [globalZone allocBlock: (CATEGORY_COUNT* sizeof(int))]; return [super createEnd]; } #endif - setDate: (const char *)theDate { date = STRDUP (theDate); return self; } - setVal: (double)theValue { int i; value = 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; } //This will print out some variables. It is triggered by xfprint() in main. - (void)describe: stream { int i; [stream catC: "This is a Data object. Here are some IVARS\n"]; [stream catC: "Date: "]; [stream catC: date]; [stream catC: " Value: "]; [stream catDouble: value]; [stream catC: " Integer Array called category: "]; for (i = 0; i < CATEGORY_COUNT; i++) { [stream catInt: category[i]]; [stream catC: " "]; } [stream catC: "\n Double Array called scale: "]; for (i = 0; i < SCALE_COUNT; i++) { [stream catDouble: scales[i]]; [stream catC: " "]; } [stream catC: "\n"]; } - (double)getValue { return value; } - (void)lispOutDeep: stream { int categoryCount = CATEGORY_COUNT; int scaleCount = SCALE_COUNT; [stream catStartMakeInstance: "Data"]; [super lispOutVars: stream deep: YES];//Important to note this!! #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]; } #ifdef DYN_MEM - hdf5OutDeep: (id )hdf5obj { int categoryCount = CATEGORY_COUNT; int scaleCount = SCALE_COUNT; [super hdf5OutDeep: hdf5obj]; // [hdf5obj shallowStoreObject: self]; [hdf5obj storeAsDataset: "category" typeName: NULL type: fcall_type_sint rank: 1 dims: &categoryCount ptr: category]; [hdf5obj storeAsDataset: "scales" typeName: NULL type: fcall_type_double rank: 1 dims: &scaleCount ptr: scales ]; return self; } #endif @end @interface Controller: CreateDrop { id collection; } - createList; @end #define NAME "myCollection" @implementation Controller #define DATA(date,value) \ [[[[Data createBegin: getZone (self)] createEnd] 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 -DUSE_HDF5 -D_GNU_SOURCE -o serialize1 -g -Wno-import -I$SWARMHOME/include -I$SWARMHOME/include/swarm -L$SWARMHOME/lib -L$SWARMHOME/lib/swarm serialization1.m -lswarm -lobjc " End: */