/* * GRAPH.C */ #define GRAPH struct _GRAPH #define GNODE struct _GNODE #define GCTRL struct _GCTRL /* * Flags field: The upper 4 bits are copied to the lower 4 bits after * the flags are processed, allowing for 'temporary' * conditions. * * FL_SKIP Propogate a skip condition. As soon as the next node * is ready to begin processing, cause it not to run * its function and propogate the FL_SKIP to all of its * children, and all of their children, etc... * * FL_SRC Infinite source, this arc is always ready with the * given value. */ GLINK { MINNODE FNode; /* link from, list based at node */ MINNODE TNode; /* link to, list based at node */ GNODE *FGNode; /* from this node */ GNODE *TGNode; /* to this node */ long FromId; /* Identify value slot for source */ long ToId; /* Identify value slot for destination */ long Value; /* value to pass to 'to' node */ ubyte Ready; /* value pending, else no value pending*/ ubyte Flags; /* FL_SKIP,FL_NULL,FL_SRC */ ubyte XFlags; /* XL_READ */ ubyte filler; }; GNODE { MINNODE GNode; /* master list node */ GRAPH *Graph; /* owning graph */ APTR Func; /* Function */ long Arg; /* Argument */ short WaitCnt; /* # parents who are not ready */ MINLIST ChildList; /* list of children */ MINLIST ParentList; /* list of parents */ MINLIST WakeUpList; /* WakeUp tasks waiting for an ARC to clear */ }; GRAPH { MINLIST GNodes; /* list of all graphs in node */ long A45[2]; /* global base registers */ long UsrLen; }; GRAPH * AllocGraph(usrdatalen) { GRAPH *graph = AllocMem(sizeof(GRAPH), MEMF_PUBLIC|MEMF_CLEAR); NewList(&graph->GNodes); graph->a45[0] = A4; graph->a45[1] = A5; graph->UsrLen = usrdatalen; } GNODE * AllocGraphNode(graph, func, arg, usrdata/NULL) GRAPH *graph; long arg; { GNODE *gnode = AllocMem(sizeof(GNODE), MEMF_PUBLIC|MEMF_CLEAR); AddTail(&graph->GNodes, &gnode->GNode); gnode->Graph = graph; gnode->Func = func; gnode->Arg = arg; NewList(&gnode->ChildList); NewList(&gnode->ParentList); NewList(&gnode->WakeUpList); } /* * Remove all arcs and free a graph node */ FreeGraphNode(gnode) GNODE *gnode; { Forbid(); Remove(gnode); while (glink = GetHead(&gnode->ChildList)) RemGraphArc(gnode, glink->FGTNode); while (glink = GetHeadOff(&gnode->ParentList, 8)) RemGraphArc(glink->FGFNode, gnode); Permit(); FreeMem(gnode, sizeof(GNODE)); }; FreeGraph(graph) GRAPH *graph; { Forbid(); while (gnode = GetHead(&graph->GNodes)) FreeGraphNode(gnode); Permit(); FreeMem(graph, sizeof(GRAPH)); } /* * Set the user data for a given node. The data is copied into an * equivalent buffer for the node. */ SetUserData(gnode, usrdata/NULL) GNODE *gnode; { } /* * Add a directed arc to the graph. Set the arc to 'not ready' and * increment the child node's WaitCnt */ AddGraphArc(from, to) GNODE *from, *to; { GLINK *glink = AllocMem(sizeof(GLINK), MEMF_PUBLIC); Forbid(); AddTail(&from->ChildList, &glink->FNode); AddTail(&to->ParentList, &glink->TNode); glink->FGNode = from; glink->FTNode = to; ++to->WaitCnt; Permit(); } chklink(glink, gnode) GLINK *glink; GNODE *gnode; { if (glink->TGNode == gnode) return(glink); return(NULL); } RemGraphArc(from, to) GNODE *from, *to; { GLINK *glink; Forbid(); if (glink = SearchFwdNode(GetHead(&from->ChildList), chklink, 0, to)) { Remove(&glink->FNode); Remove(&glink->TNode); if (!glink->Ready) { if (--to->WaitCnt == 0 && GetHeadOff(&to->ParentList, 8)) GHandler(to); } } Permit(); } SetGNodeFunc(gnode, func) GNODE *gnode; APTR func; { gnode->Func = func; } SetGNodeArg(gnode, arg) GNODE *gnode; { gnode->Arg = arg; } APTR GetGNodeFunc(gnode) GNODE *gnode; { return(gnode->Func); } long GetGNodeArg(gnode) GNODE *gnode; { return(gnode->Arg); } /* * This function may ONLY be called by a node function, and retrieves * the value from one of the parent arcs (arcs comming in). When the * node function returns, any remaining unread parent arc's values will * be discarded. */ long GetArcValue(ToId) { } /* * This function may ONLY be called by a node function, and sets the * result value to one of its child arcs (arcs going out). When the * node function returns, any remaining unset child arc's values will * be SKIPd. * * NOTE! This function will block on child nodes which have yet to * read the previous value with GetArcValue() or are still running. */ SetArcValue(gnode, FromId, flags) GNODE *gnode; { } /* * This function may be called by anybody, and forces a value into an * arc. This function is usually used to 'prime' a graph. */ PrimeArc(from, to, value) GNODE *from, *to; { } /* * GetGraph() * * Load the two buffers with entries corrosponding to the graph. arcen * and nodeen initially contain the number of ARC and NODE structure * entries that have been allocated. These variables will hold the * actual number of ARC and NODE entries in the graph regardless of * whether the operation succeeds. * * 0 is returned if the operation does not succeed, 1 if it does. * The size of the node structure depends on the size of attached * user information. * * ARC structure: two words / entry, representing an arc (from, to), * where each word is an index (by entry #) into nodebuf. * i.e. 0, 1, 2 ... even if usrdatalen is 0. * * NODE structure: any user data that has been applied to the node, as * specified by AllocGraphNode(). */ GetArcs(graph, arcbuf, &arcen, nodebuf, &nodeen) GRAPH *graph; { }