In OrgC++, organizations of data form a network of transparent pointers. By traversing these pointers, OrgC++ can quickly collect (SWEEP) all objects within the given organization, and place them onto an internal list. Any user-coded function can then be executed on objects in that list. This is a very useful feature which allows, for example, the printing or displaying of all the objects in the entire database.
The algorithm for collecting objects (finding a graph closure) is a breadth-first search, similar to the routing algorithm for electronic circuits. It expands from a given set of key objects to their neighbours in a wave-like fashion, until all objects have been detected.
Pointers inside hash tables and GENERAL_LINK pointers are included in this process.
This concept allows some powerful implementations with a minimum of programming effort. For example, internally, the save() function uses the SWEEP operation: the program collects a list of all objects, and saves individual objects by calling a function which is essentially ZZ_OBJECT_SAVE(). It then removes the internal list of objects.
The selection of entry points is a critical task, and must be done very carefully. In a RING, TREE or SINGLE_GRAPH, any object can be reached from any other object, but SINGLE_LINK, GENERAL_LINK, DIRECT_GRAPH, and the HASH TABLE are all unidirectional.
It may happen that the whole organization cannot be accessed from a single object, either due to the directional nature of the network, or when the data form several subsets that are mutually disconnected. In such a case, the programmer must provide key entries, from which there is at least one path to every object. If some objects can be reached from several key entries, OrgC++ automatically eliminates duplications.
There are situations when it is useful to keep several key entries, even if all the objects can be reached from a single object, for example, when you want to remember certain objects as "leading" or "critical".
For example, in test0n.c, all the objects in the netlist can be reached from the block bStart but, for technical reasons, it is useful to also preserve the main entry to all nets, nStart. For this reason, save() - which is based on SWEEP, uses two key entries.
| void util.swpSet(int num,char *keyEntries[],char *keyTypes[]) | sets the internal list of objects that can be reahed from the given key entries. A total of num key entries is given. |
| void util.swpFun(void (*fun)(char*,int,int,char),const char *priv) | executes the given function on all objects of the internal list; priv is a pointer to any additional information that such a function may need. |
| void util.swpFree(void) | removes the internal list (it has no parameters). |
The function, which is called by swpFun(), must have 4 parameters:
void fun(char *ptr,int typeInd,int size,const char *priv)
// ptr - pointer to the object, cast as (char *)
// typeInd - internal type index
// size - size of the object in bytes
// priv - pointer to private information such as a file pointer
The internal type index can be converted into type name using the function util.type().
int typeInd; // given type index
char *typeName; // resulting name
ZZ_HYPER_UTILITIES(util);
typeName=util.type(typeInd);
Programs test0n.c and test16c.c collect all objects using swpSet() and then print information about the object size and type, using swpFun().
In both examples, the private parameter is used to pass the output file pointer.
In test16c.c there is an example of which converts type index into type name (function util.type()).
| Chapter 14: Debugging |