home *** CD-ROM | disk | FTP | other *** search
- /*
-
- generic function list manager for GCOOPE version 1.0
-
- by Brian Lee Price
-
- Released as Public Domain July, 1994.
-
- These routines handle GCOOPE's virtual/overloaded/polymorphic/
- generic functions, all generic function dispatching uses the
- lists set up and accessed through them.
-
- Please examine gcstruct.h and listmgr.c prior to any serious
- review of the source code presented here.
-
- */
-
- #define __GENERICS__
-
- #include "gcstruct.h"
-
- #include <stdlib.h>
- #include <mem.h>
-
- /*
- AVAILABLE FOR EXTERNAL USE:
-
- Tag compare routine is designed for use with qsort and bsearch.
-
- */
-
- int tagCmp(const void * ptrA, const void * ptrB)
- {
- return *((const tag *) ptrA)-*((const tag *) ptrB);
- }
-
-
- /*
- FOR KERNAL USE ONLY!
-
- usage:
- newGenericFunctionIndex = addGeneric(default_method);
-
- The dynList polyTable is actually an unordered list of ordered
- lists, the generic function index is used to find the appropriate
- ordered list containing the method dispatching info for that
- generic function. On a failure this routine returns the value
- MAX_GEN.
- */
-
- generic addGeneric(method defMthd)
- {
- int x;
- genEntry * genList;
-
- if((x=addItem(&genTable, sizeof(genEntry)))<0) return MAX_GEN;
- genList=genTable.listPtr;
- genList+=x;
- genList->elemSize=sizeof(genMethod);
- genList->defMthd=defMthd;
- return x;
- }
-
- /*
- FOR KERNEL USE ONLY!
-
- usage:
- genItemElemSize=rmvVirtFunc(generic_type_generic_function_to_remove);
-
- Here you find the common way of accessing a generic function, that
- method is by the tag variable of type generic for the generic function.
- This value is actually an index to genTable.
- Note that this routine uses the return value setup as in the listmgr
- function rmvItem, NOT the FUNCOKAY/FUNCFAIL value.
- */
-
- int rmvGeneric(generic genFunc)
- {
- genEntry * genList;
-
- if(genFunc>=genTable.maxElems || genFunc<0) return -1;
- genList=genTable.listPtr;
- genList+=genFunc;
- if(genList->listPtr!=NULL)
- s_free(genList->listPtr);
- return rmvItem(&genTable, genFunc);
- }
-
- /*
- FOR KERNEL USE ONLY.
-
- usage:
- genericFunctionEntryPtr=getMthd(generic_type_function,
- class_tag_value_of_class_for_method_lookup);
-
- This is the core routine for generic function dispatching,
- given a generic function index value and a class tag value
- (see objList.c for an explanation of class tags), this routine
- will return a pointer to the generic list entry in the generic
- list indexed by the generic function index value and looked up
- via. bsearch with the class tag value used as the key. The
- reason this routine does not just return the method pointer is
- because some possible future enhancements could result in
- additional information being stored in the generic list entry
- structure.
-
- */
-
-
- genMethod * getMthd(generic genFunc, int clsTag)
- {
- genEntry * genList;
-
- if(genFunc>=genTable.maxElems || genFunc<0) return NULL;
- genList=genTable.listPtr;
- genList+=genFunc;
-
- return bsearch(&clsTag,genList->listPtr,genList->firstFree,
- sizeof(genMethod), tagCmp);
- /*
- Note that this function will return NULL on an error, the return
- value of this function ABSOLUTELY MUST be validated or you are
- guaranteed a spectacular program crash!
- */
- }
-
-
-
-
- /*
- FOR KERNEL USE ONLY!
-
- usage:
- functionStatus=addMethod(generic_type_function,
- type_method_method_pointer, method_class_tag_value,
- child_class_tag_value);
- Things are getting tricky, this routine installs a method given
- by addMthd into the generic function list given by genFunc,
- for the calling class given by clsTag. The value owner may
- (or may not) be used by the function dispatcher, however it
- is the class tag of the actual owning class of the method while
- clsTag is (possibly) an class which inherits the method.
- An easy to miss feature of this routine is that it will
- overwrite a previous entry for the same generic function and
- calling class. The reason is that methods are installed in the
- reverse order of inheritance, thus it is possible for an
- inheriting class to replace a method defined in a superClass.
- This function uses the (standard ???) FUNCFAIL/FUNCOKAY
- return values.
- */
-
- stat addMethod(generic genFunc, method addMthd,
- tag clsTag, tag owner)
- {
- int x;
- genEntry * genList;
- genMethod * methPtr;
-
- if(addMthd==(method) NULL || genFunc>=genTable.maxElems || genFunc<0)
- return FUNCFAIL;
- genList=genTable.listPtr;
- genList+=genFunc;
- if(NULL!=(methPtr=bsearch(&clsTag, genList->listPtr, genList->firstFree,
- sizeof(genMethod), tagCmp)))
- {
- methPtr->instMethod=addMthd;
- methPtr->owner=owner;
- return FUNCOKAY;
- }
-
- if((x=addItem(genList, sizeof(genMethod)))<0) return FUNCFAIL;
- methPtr=genList->listPtr;
- methPtr+=x;
- methPtr->class=clsTag;
- methPtr->owner=owner;
- methPtr->instMethod=addMthd;
- qsort(genList->listPtr, genList->firstFree, sizeof(genMethod), tagCmp);
- return FUNCOKAY;
- }
-
-
-
- /*
- FOR KERNEL USE ONLY.
-
- usage:
- functionStatus=rmvMethod(type_generic_function, calling_class_tag,
- owning_class_tag);
-
- This function will remove a method from a generic function's list.
- It is designed to be called during class removal. It returns the
- semi-standard FUNCFAIL/FUNCOKAY status value.
- */
-
- stat rmvMethod(generic genFunc, tag clsTag)
- {
- genEntry * genList;
- genMethod * methPtr;
- stat retVal=FUNCFAIL;
-
- if(genFunc>=genTable.maxElems || genFunc<0) goto end;
- genList=genTable.listPtr;
- genList+=genFunc;
-
- if(genList->listPtr==NULL) goto end;
- if((methPtr=bsearch(&clsTag,genList->listPtr,genList->firstFree,
- sizeof(genMethod), tagCmp))==NULL) goto end;
- memset(methPtr,0x,sizeof(genMethod));
- genList->firstFree=(int) ((methPtr - genList->listPtr)/genList->elemSize);
- compactList(genList, TRUE);
-
- retVal=FUNCOKAY;
-
- end:
- return retVal;
- }
-
-