If-less Topological Sort

  1. There is a Node object for each 'item' in the partial order. A Node object maintains a neighborhood of items that are all directly known to be less than the item of the Node object. A Node object also holds an object of the Topo class.

    A Topo object has a topo->exec() function which can operate either as a 'visit' function, a 'cycle' function, or a 'done' function. During execution the function is changed, on-the-fly, to match the situation at an item as follows: if the item has not yet been visited, the function is the 'visit' function, if the neighbors are being visited the function is the 'cycle' function, if all neighbors have been visited the function is the 'done' function. If a 'cycle' function is encountered during execution, a cycle has been found and the program is terminated. If a 'done' function is encountered execution returns to the caller. Otherwise, the 'visit' function is changed to the 'cycle' function, the neighborhood is visited - that is, the topo->exec() functions are invoked for all neighbors, if the neighbor is visited without exiting, the item's identity is output, and finally the 'cycle' function is replaced by the 'done' function.

    The classes Visit (visit.h, visit.cc), and Cycle (cycle.h) subclass Topo. Each re-implements topo->exec() as a 'visit' or 'cycle' described above. The 'done' function is obtained using Topo directly. Getting the topo->exec() function to change during execution is accomplished merely by replacing Topo objects - replace a Visit object with a Cycle object then a Topo object. This is seen in the exec() function of visit.cc. Initially, the Topo object is set to a Visit object in the constructor of class Node in node.cc.

  2. For each Node object a linked list of Cell objects is constructed, one for each neighbor (meaning 'this' item is directly 'greater' than the neighbor). Each Cell object has an exec() function which, similar to Topo objects, may take two forms depending on whether it is subclassed by a Neighbor object. If a Neighbor object, exec() first executes the topo->exec() of the neighbor and then invokes exec() of the next Cell object in the list (see method exec() in neighbor.cc). At the end of the list is a Cell object whose exec() terminates the traversal through the list.
  3. When input from file, all Node objects carrying items are placed in Neighbor objects (also of type Cell) and linked, with the last object in the list being a Cell object. When solve is invoked in solver.cc it initiates a walk through the list, invoking topo->exec() of each Node object, and terminating with the exec() call of a Cell object. This is shown in exec() of neighbor.cc.