//Paul Johnson Sept. 14, 2000 //avl_tree based set class for swarm. //Comparison function must be set between createBegin and createEnd #import // initSwarm #import // Array #import // CreateDrop #import // Swarm #import // getZone #import //superclass of AVLtree #include //#include //for the AVLtree #include #define COUNT 10 typedef int (*compare_avl_t) (const void *, const void *,void *); //@interface AVLSet: Collection_any @interface AVLSet: SwarmObject { avl_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; - copy: aZone; - (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: (avl_traverser *) travPtr; @end @interface AVLSetIndex_c: Index_any { int offset; avl_traverser trav; id currentObject; @public avl_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 AVLSet //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 { AVLSet * 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 = avl_create ( compareFunc, NULL); return self; } - setCompareCStrings { compareFunc = compare_cstrings; aTree = avl_create ( compareFunc, NULL); return self; } - setCompareIDs { compareFunc = compare_object_ids; aTree = avl_create ( compareFunc, NULL); return self; } - setCompareIntegers { compareFunc = compare_integers; aTree = avl_create ( compareFunc, NULL); return self; } - setCompareUnsignedIntegers { compareFunc = compare_unsigned; aTree = avl_create ( compareFunc, NULL); return self; } //by default,use IDs to compare. 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 { AVLSet * obj; obj = [super createBegin: aZone]; obj->aTree = avl_create (comparFunc, param); return obj; } PHASE(Using) //Methods in Set certainly have to be implemented here, so here they are: - copy: aZone { AVLSet *newSet; newSet = [aZone copyIVars: self]; newSet->aTree = avl_copy (aTree,NULL); return newSet; } - (int) count { return avl_count(aTree); } - (unsigned) getCount { return (unsigned) avl_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 = avl_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 = avl_find(aTree, anObject) )) { avl_replace (aTree, anObject); } return value; //have to worry about NULL being different from nil? } - (BOOL) contains: aKey { if (avl_find(aTree, aKey)) return YES; else return NO; } - (BOOL)containsKey: aKey { return [self contains: aKey]; } - at: aKey { void * value=avl_find(aTree, aKey); return value; } - (BOOL)at: aKey memberSlot: (id **)memptr { raiseEvent (NotImplemented, nil); return NO; } - remove: aKey { return avl_delete(aTree, aKey); } - removeKey: aKey { return avl_delete(aTree, aKey); } - (void)forEach: (SEL)aSelector { id anObject; avl_traverser trav = {0}; while (( anObject = avl_traverse (aTree, &trav)) != NULL) [anObject perform: aSelector]; } - (void)forEach: (SEL)aSelector : arg1 { id anObject; avl_traverser trav = {0}; while (( anObject = avl_traverse (aTree, &trav)) != NULL ) [anObject perform: aSelector with: arg1]; } - (void)forEach: (SEL)aSelector : arg1 : arg2 { id anObject; avl_traverser trav = {0}; while (( anObject = avl_traverse (aTree, &trav)) != NULL ) [anObject perform: aSelector with: arg1 with: arg2]; } - (void)forEach: (SEL)aSelector : arg1 : arg2 : arg3 { id anObject; avl_traverser trav = {0}; while (( anObject = avl_traverse (aTree, &trav)) != NULL ) [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 { AVLSetIndex_c * newIndex; newIndex = [aZone allocIVars: [AVLSetIndex_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 { avl_destroy(aTree,NULL); //does not drop objects tree refers to [super drop]; } - removeAll { avl_destroy(aTree,NULL); return self; } - deleteAll { avl_free(aTree); //drops objects in the tree and tree too return self; } // 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 = avl_replace (aTree, anObject );//uses integer keys; if (value != NULL) return value; else return nil; } -(void) walk: (void (*)(void*,void*)) aFunction Param: (void *) PARAM { avl_walk(aTree , aFunction, NULL); } - traverse: (avl_traverser *) travPtr { id anObject; anObject = avl_traverse (aTree, travPtr) ; return anObject; } @end @implementation AVLSetIndex_c - next { currentObject = avl_traverse (tree, &trav); offset ++; return currentObject ; //returns a null at the end of the tree } //sorry, I don't see a way to make an avltree walk backwards! - prev { int i; int currentOffset = offset; void * anObject = NULL; [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 * value; if (( value = avl_find(tree, anObject) )) { avl_replace (tree, anObject); } return value; //removed object } - remove { id removed; int currentOffset = offset; removed = avl_delete ( tree, currentObject ); [self init]; while ( offset < currentOffset-1 ) { [self next]; //step up to object before removal } return removed; } - init { avl_traverser newtrav = {0}; trav = newtrav ; offset = -1; currentObject = nil; return self; } - (id )getLoc { if (offset == -1) return Start; else if (currentObject != NULL) { fprintf (stderr,"Member! offset= %d",offset); return Member; } else if (offset >= avl_count(tree)) { return End; } else raiseEvent(WarningMessage,"Invalid AVLSet position"); return End; } - (void)setLoc: (id )locSymbol { if ( locSymbol == Start) [self init]; if ( locSymbol == End) //this is silly, nobody should ever do it. while (avl_traverse(tree, &trav)); } - (int)getOffset { return offset ; } - setOffset: (unsigned)targetOffset { [self init]; do { [self next]; } while ( offset < targetOffset ); return currentObject; } //I don't know what this does! // - (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 { printf("Hello, from Agent %d \n",personalNumber); return self; } - (int) getPIN { return personalNumber; } @end @interface ModelSwarm: Swarm { id population; AVLSet * myTree1; AVLSet * 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 = [AVLSet createBegin: self ]; [myTree1 setCompareIDs]; myTree1= [myTree1 createEnd]; myTree2 = [ AVLSet createBegin: self]; [myTree2 setCompareFunction: compare_agent_position ] ; myTree2 = [myTree2 createEnd] ; //[AVLtree create for (i = 0; i < COUNT; i++) { anAgent= [Agent create: self setPopulation: population setPIN: i]; [population atOffset: i put: anAgent]; [myTree1 add: anAgent];//uses ID keys [myTree2 add: anAgent];//retrieves node or inserts if key not in tree already } //this amounts to a "set" return self; } - (void)test { int i; // int j; id anAgent=nil; avl_traverser trav = {0}; id index1; id index2; printf("Now, use the avl_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("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]; [outputAgent print]; } 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]; } anAgent = nil; printf("Now, grab the agent 5th from the tree2 by asking for it by name \n"); anAgent = [myTree2 at: [population atOffset: 4]]; [anAgent 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 (" 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 ("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]; printf ("Create a swarm index for the trees \n"); index1 = [myTree1 begin: self]; index2 = [myTree2 begin: self]; 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=avlusage3 -o avlusage3 -Wall -Werror -g -Wno-import -I$SWARMHOME/include \ -I$SWARMHOME/include/swarm -L$SWARMHOME/lib/swarm avlusage3.m -lswarm -lobjc" End: */