//Paul E Johnson Sept. 14, 2000 GPL copyright //AVLTRSet is a Set (and ordered set) class replacement for Swarm. //avltr is "right threaded" avl tree. Better if you need "next" support. //requires a swarm 2000-09-10 or better #import // initSwarm #import // Array #import // CreateDrop #import // Swarm #import // getZone #import //superclass of AVLtree #include #include #include //for the AVLtree #define COUNT 10 typedef int (*compare_avl_t) (const void *, const void *,void *); //@interface AVLTRSet: Collection_any @interface AVLTRSet: SwarmObject { avltr_tree * aTree; compare_avl_t compareFunc; } + createBegin: aZone; + createBegin: (int (*)(const void*,const void*,void*)) compareFunc Param: (void *) param Zone: aZone; - setCompareFunction: (compare_avl_t) compareFunction; - setCompareCStrings; - setCompareIDs; - setCompareIntegers; - setCompareUnsignedIntegers; - createEnd; - (int) count; - (unsigned) getCount; -(BOOL) add: anObject; - (id *) replace: anObject; - (BOOL) contains: aKey; - (BOOL) containsKey: aKey; - at: aKey; - (BOOL)at: aKey memberSlot: (id **)memptr; - remove: aKey; - removeKey: aKey; - (void)forEach: (SEL)aSelector; - (void)forEach: (SEL)aSelector : arg1; - (void)forEach: (SEL)aSelector : arg1 : arg2; - (void)forEach: (SEL)aSelector : arg1 : arg2 : arg3; - (void)forEachKey: (SEL)aSelector; - (void)forEachKey: (SEL)aSelector : arg1; - (void)forEachKey: (SEL)aSelector : arg1 : arg2; - (void)forEachKey: (SEL)aSelector : arg1 : arg2 : arg3; - begin: aZone; - createIndex: (id )aZone fromMember: anObject ; - (void) drop; - removeAll; - deleteAll; //New thing I made up because I didn't like the Swarm's Set default behavior - forcefulReplace: anObject; -(void) walk: (void (*)(void*,void*)) aFunction Param: (void *) PARAM; - traverse: (avltr_traverser *) travPtr; - (avltr_tree *) getTree; @end @interface AVLTRSetIndex_c: Index_any { int offset; void ** traverser; void *currentObject; id position; @public avltr_tree * tree; } - init; - next; - prev; - get; - replace: anObject; - remove; - (id )getLoc; - (void)setLoc: (id )locSymbol; - (int)getOffset; - setOffset: (unsigned)targetOffset; //- (void)mapAllocations: (mapalloc_t)mapalloc; @end @implementation AVLTRSet //compare functions for AVLtrees must take 3 args, 2 objects and 1 optional parameter. static int compare_object_ids (const void *A, const void *B, void *PARAM) { int a = (unsigned) A; int b = (unsigned) B; if (a < b ) return -1; return a > b; } static int compare_integers (const void * val1, const void *val2, void *PARAM) { if ((PTRINT) val1 < (PTRINT) val2) return -1; return ((PTRINT) val1 > (PTRINT) val2); } static int compare_unsigned (const void * val1, const void * val2, void * PARAM) { if ((PTRUINT) val1 < (PTRUINT) val2) return -1; return ((PTRUINT) val1 > (PTRUINT) val2); } static int compare_cstrings (const void* val1, const void * val2, void * PARAM) { return strcmp ((const char *)val1, (const char *)val2); } PHASE(Creating) +createBegin: aZone { AVLTRSet * obj; obj = [super createBegin: aZone]; return obj; } //It is mandatory to choose one of these compare functions at create time. - setCompareFunction: (compare_avl_t) compareFunction { compareFunc = compareFunction; aTree = avltr_create ( compareFunc, NULL); return self; } - setCompareCStrings { compareFunc = compare_cstrings; aTree = avltr_create ( compareFunc, NULL); return self; } - setCompareIDs { compareFunc = compare_object_ids; aTree = avltr_create ( compareFunc, NULL); return self; } - setCompareIntegers { compareFunc = compare_integers; aTree = avltr_create ( compareFunc, NULL); return self; } - setCompareUnsignedIntegers { compareFunc = compare_unsigned; aTree = avltr_create ( compareFunc, NULL); return self; } //Consider instead to use default comparison of IDs. That makes it a Set. -createEnd { if ( aTree == NULL ) raiseEvent (InvalidArgument, "You Forgot to set a compare function"); return [super createEnd]; } //convenience method +createBegin: (int (*)(const void*,const void*,void*)) comparFunc Param: (void *) param Zone: aZone { AVLTRSet * obj; obj = [super createBegin: aZone]; obj->aTree = avltr_create (comparFunc, param); return obj; } PHASE(Using) //Methods in Set_c have to be implemented, so here they are: //JUST a shallow copy! Note passing NULL as 2nd argument of avltr_copy - copy: aZone { AVLTRSet *newSet; newSet = [aZone copyIVars: self]; newSet->aTree = avltr_copy (aTree,NULL); return newSet; } - (int) count { return avltr_count(aTree); } - (unsigned) getCount { return (unsigned) avltr_count(aTree); } //add an object if it is not currently in the set //if anObject is in the set, then return that value. //does nothing and returns NO otherwise -(BOOL) add: anObject { id value = avltr_insert (aTree, anObject );//uses integer keys; if (value == NULL) return YES; else return NO; } // if anObject matching key exists, replace it, return old one. // otherwise do nothing and return nil - (id *) replace: anObject { void * value; if (( value = avltr_find(aTree, anObject) )) { avltr_replace (aTree, anObject); } return value; //have to worry about NULL being different from nil? } - (BOOL) contains: aKey { if (avltr_find(aTree, aKey)) return YES; else return NO; } - (BOOL)containsKey: aKey { return [self contains: aKey]; } //Note: There is no way to have more than one object with that key, so the //at: method does not make any effort to do the Swarm thing and collect //all objects with a key. - at: aKey { void ** value = avltr_find(aTree, aKey); return *value; } - (BOOL)at: aKey memberSlot: (id **)memptr { raiseEvent (NotImplemented, nil); return NO; } - remove: aKey { return avltr_delete(aTree, aKey); } - removeKey: aKey { return avltr_delete(aTree, aKey); } - (void)forEach: (SEL)aSelector { void ** anObjectPtr; for ( anObjectPtr = avltr_next (aTree, NULL); anObjectPtr != NULL; anObjectPtr = avltr_next(aTree, anObjectPtr)) { id anObject = * anObjectPtr; [anObject perform: aSelector]; } } - (void)forEach: (SEL)aSelector : arg1 { void ** anObjectPtr; for ( anObjectPtr = avltr_next (aTree, NULL); anObjectPtr != NULL; anObjectPtr = avltr_next(aTree, anObjectPtr)) { id anObject = * anObjectPtr; [anObject perform: aSelector with: arg1]; } } - (void)forEach: (SEL)aSelector : arg1 : arg2 { void ** anObjectPtr; for ( anObjectPtr = avltr_next (aTree, NULL); anObjectPtr != NULL; anObjectPtr = avltr_next(aTree, anObjectPtr)) { id anObject = * anObjectPtr; [anObject perform: aSelector with: arg1 with: arg2]; } } - (void)forEach: (SEL)aSelector : arg1 : arg2 : arg3 { void ** anObjectPtr; for ( anObjectPtr = avltr_next (aTree, NULL); anObjectPtr != NULL; anObjectPtr = avltr_next(aTree, anObjectPtr)) { id anObject = * anObjectPtr; [anObject perform: aSelector with: arg1 with: arg2 with: arg3]; } } - (void)forEachKey: (SEL)aSelector { [self forEach: (SEL)aSelector]; } - (void)forEachKey: (SEL)aSelector : arg1 { [self forEach: (SEL)aSelector: arg1]; } - (void)forEachKey: (SEL)aSelector : arg1 : arg2 { [self forEach: (SEL)aSelector: arg1 : arg2]; } - (void)forEachKey: (SEL)aSelector : arg1 : arg2 : arg3 { [self forEach: (SEL)aSelector: arg1 : arg2]; } -begin: aZone { AVLTRSetIndex_c * newIndex; newIndex = [aZone allocIVars: [AVLTRSetIndex_c self]]; newIndex->tree = aTree; // newIndex->collection = self; [newIndex init]; return newIndex; } - createIndex: (id )aZone fromMember: anObject { raiseEvent(WarningMessage,"Not Implemented"); return self; } - (void) drop { avltr_destroy(aTree,NULL); //does not drop objects tree refers to [super drop]; } - removeAll { avltr_destroy(aTree,NULL); return self; } - deleteAll { avltr_free(aTree); //drops objects in the tree and tree too return self; } // - (void) mapAllocations: (mapalloc_t)mapalloc // { // mapObject (mapalloc, list); // } // Super power insert. Inserts if object does not exist, replaces if object does. // returns object being replaced if there is one. - forcefulReplace: anObject { id value = avltr_replace (aTree, anObject );//uses integer keys; if (value != NULL) return value; else return nil; } -(void) walk: (void (*)(void*,void*)) aFunction Param: (void *) PARAM { avltr_walk(aTree , aFunction, NULL); } - traverse: (avltr_traverser *) travPtr { id anObject; anObject = avltr_traverse (aTree, travPtr) ; return anObject; } - (avltr_tree *) getTree { return aTree; } @end @implementation AVLTRSetIndex_c - next { traverser = avltr_next (tree, traverser); if (traverser != NULL) { currentObject = *traverser; position = Member; } else { position = End; currentObject = NULL; } offset ++ ; return currentObject ; //returns a null at the end of the tree } - prev { int i; int currentOffset = offset; void * anObject; [self init]; for (i=0; i < currentOffset; i++) { anObject = [self next]; } printf("previousOffset was %d, new offset is %d \n",currentOffset, offset); return anObject; } - get { return currentObject; } - replace: anObject { void ** valuePtr; void * removedObject = NULL; if ( (valuePtr = avltr_find(tree, anObject) ) ) { void * anObject = *valuePtr; removedObject = avltr_replace (tree, anObject); } return removedObject; //removed object } - remove { id removed; // int currentOffset = offset; removed = avltr_delete ( tree, currentObject ); offset = offset - 1 ; //following not needed for avltr? // [self init]; // while ( offset < currentOffset-1 ) // { // [self next]; //step up to object before removal // } return removed; } - init { traverser = NULL; offset = -1; currentObject = NULL; return self; } - (id )getLoc { if (offset == -1) return Start; else return position; } - (void)setLoc: (id )locSymbol { if ( locSymbol == Start) [self init]; if ( locSymbol == End) //this is silly, nobody should ever do it. while (avltr_next(tree, traverser )); } - (int)getOffset { return offset ; } - setOffset: (unsigned)targetOffset { [self init]; do { [self next]; } while ( offset < targetOffset ); return currentObject; } // I don't understand what this is for, but Set_Index has it... // - (void) mapAllocations: (mapalloc_t)mapalloc // { // mapObject (mapalloc, listIndex); // } //Methods from "Index_any" that do not have meaning in a Set - findNext: anObject { raiseEvent (NotImplemented, nil); return self; } - findPrev: anObject { raiseEvent (NotImplemented, nil); return self; } @end @interface Agent: CreateDrop { id population; unsigned personalNumber; } + create: (id )aZone setPopulation: (id )thePopulation setPIN: (unsigned)pin; - print; - (int) getPIN; @end @implementation Agent + create: (id )aZone setPopulation: (id )thePopulation setPIN: (unsigned)pin { Agent *obj = [self createBegin: aZone]; obj->population = thePopulation; obj->personalNumber = pin; return [obj createEnd]; } - print { fprintf(stderr,"Hello, from Agent %d \n",personalNumber); return self; } - (int) getPIN { return personalNumber; } @end @interface ModelSwarm: Swarm { id population; AVLTRSet * myTree1; AVLTRSet * myTree2; } - buildObjects; @end @implementation ModelSwarm //here is a user-specified comparison function. Note 3 args! static int compare_agent_position (const void *A, const void *B, void *PARAM) { int a = [(const id) A getPIN]; int b = [(const id) B getPIN]; if (a < b ) return -1; return a> b; } static void print_node ( void *A, void *PARAM) { id a = (id) A; [a print]; } - buildObjects { unsigned i; id anAgent; [super buildObjects]; population = [Array create: globalZone setCount: COUNT]; myTree1 = [AVLTRSet createBegin: self ]; [myTree1 setCompareIDs]; myTree1= [myTree1 createEnd]; myTree2 = [ AVLTRSet createBegin: self]; [myTree2 setCompareFunction: compare_agent_position ] ; myTree2 = [myTree2 createEnd] ; //[AVLtree create for (i = 0; i < COUNT; i++) { BOOL returnValue1; BOOL returnValue2; anAgent= [Agent create: self setPopulation: population setPIN: i]; [population atOffset: i put: anAgent]; returnValue1 = [myTree1 add: anAgent];//uses ID keys returnValue2 = [myTree2 add: anAgent];//retrieves node or inserts if key not in tree already this amounts to a "set" printf("In creation loop, count %i \n", i); [[myTree1 at: anAgent] print]; } { avltr_tree * tree1 = [myTree1 getTree]; printf ("MyTree1 has %d \n \n", avltr_count(tree1)); avltr_walk ( tree1, print_node, NULL); } return self; } - (void)test { int i; id anAgent=nil; id index1; id index2; printf("Now, use the wrapper around avltr_walk to march through the tree1\n"); printf("This is supposed to start with the smallest key and move on up.\n"); [myTree1 walk: print_node Param: NULL]; printf("here is the object at the first offset in myTree2 \n"); anAgent = [population atOffset: 1]; [[myTree2 at: anAgent] print]; printf("myTree1 for the agent that is in population offset 3 \n"); anAgent = [population atOffset: 3]; [[myTree1 at: anAgent] print]; printf("Now do same with forEach and print \n"); [myTree1 forEach: M(print)]; anAgent = nil; printf("Now, go forwards through the tree1 with a for loop that uses \n"); printf("at: aKey, where the value of the agent itself from [population atOffset:i] as the key \n"); for (i = 0; i< COUNT; i++) { id outputAgent=nil; anAgent = [population atOffset: i]; outputAgent= [myTree1 at: anAgent]; } printf("Now, go backwards through the tree2 with a for loop\n"); for (i = 0; i< COUNT; i++) { id outputAgent = nil; anAgent = [population atOffset: COUNT-i-1]; outputAgent = [myTree2 at: anAgent]; [outputAgent print]; } printf ("Now, grab the agent 5th (index value=4) from the tree1 by asking for it by name \n"); anAgent=nil; anAgent = [myTree1 at: [population atOffset: 4]]; [anAgent print]; printf ("Create a swarm index for the trees \n"); index1 = [myTree1 begin: self]; index2 = [myTree2 begin: self]; printf ("use index1 next 7 times, to step up through object 6 \n"); for ( i = 0; i < 7; i ++ ) { anAgent = [index1 next]; [anAgent print]; } printf (" Now delete the 5th agent from the tree1 and walk it\n"); [myTree1 removeKey: [population atOffset: 4]]; [myTree1 walk: print_node Param: NULL]; printf ("Observe that the 5th object still exists \n"); printf ("but it is no longer pointed to by an element in the AVLtree \n"); printf ("now confirm the index is still valid: it should begin at agent 7, who is next \n"); for ( anAgent = [index1 next]; [index1 getLoc]==Member; anAgent = [index1 next]) { int offset; offset = [index1 getOffset]; printf ("Offset reported by index1 is %d \n", offset); [anAgent print]; } printf ("Now tell the index to go to offset 3, then step 5 times to see what it says \n"); [index1 setOffset: 3]; for (i = 0; i < 5; i ++) { int offset; offset = [index1 getOffset]; printf("index1 currently positioned on offset %d and the agent at that positions say: \n", offset); [[index1 get] print]; [index1 next]; } printf ("Now test to make sure nothing happens if we walk off the end\n"); while ( (anAgent = [index1 next]) ) { printf("current offset is %d \n", [index1 getOffset]); [[index1 get] print]; } printf ("If you saw anything, there is something wrong \n"); printf ("Now, lets remove an object by repositioning the index at offset 2, then walk the collection"); [index1 setOffset: 2]; [index1 remove]; [index1 setLoc: Start]; for ( anAgent = [index1 next]; [index1 getLoc]==Member; anAgent = [index1 next]) { printf("current offset is %d \n", [index1 getOffset]); [[index1 get] print]; } printf("Now test index prev. The index should be at End, or offset = %d ", [index1 getOffset]); for (i = 0; i < 5; i ++) { int offset; offset = [index1 getOffset]; [[index1 prev] print]; printf("index1 currently positioned on offset %d, which should be the last \n", offset); } // printf ("What happens if you drop an agent before removing it from the tree? \n"); // printf ("Go into the source code and uncomment the next 3 lines after this \n"); // printf ("comment if you want to see a segmentation violation \n"); // //printf ("lets drop the 6th agent, then do the walk\n"); // //[[population atOffset: 5] drop]; // //[myTree1 walk: print_node Param: NULL]; // anAgent = nil; // printf("traverse \n"); // while ( (anAgent=[myTree1 traverse: &trav]) != NULL) // [anAgent print]; // for (anAgent = [index1 next]; [index1 getLoc]==Member; anAgent= [index1 next]) // { // [anAgent print]; // } // printf("No lets use the index to delete an item and find out who is left"); // printf("This gets the object at offset 5 (that's the 6th object) in the tree: \n"); // anAgent = [index1 setOffset: 5]; // [anAgent print]; // printf("And removes it and now we see that object is gone: \n"); // [index1 remove]; // [index1 setLoc: [population atOffset: 5]]; // for (anAgent = [index1 next]; [index1 getLoc]==Member; anAgent= [index1 next]) // { // [anAgent print]; // } } @end int main (int argc, const char **argv) { initSwarmBatch (argc, argv); { id modelSwarm = [ModelSwarm create: globalZone]; [modelSwarm buildObjects]; [modelSwarm test]; } return 0; } /* Local Variables: compile-command: "$SWARMHOME/bin/libtool-swarm --mode=link gcc -D_GNU_SOURCE \ -DAPPNAME=avlusage4 -o avlusage4 -Wall -Werror -g -Wno-import -I$SWARMHOME/include \ -I$SWARMHOME/include/swarm -L$SWARMHOME/lib/swarm avlusage4.m -lswarm -lobjc" End: */