171 lines
6.6 KiB
C++
171 lines
6.6 KiB
C++
/*****************************************************************************
|
|
* \file trynext.cc *
|
|
* *
|
|
* Description: Contains the tryNext() functions for the EntList descen- *
|
|
* dants. Their purpose is to search for additional branches *
|
|
* of OrList's to try the next available untried solution. AND *
|
|
* and ANDOR iterate through their children looking for OR's. *
|
|
* OR tries the next branch of its children if more remain. *
|
|
* *
|
|
* Created by: David Rosenfeld *
|
|
* Date: 10/24/96 *
|
|
*****************************************************************************/
|
|
|
|
#include "complexSupport.h"
|
|
#include "sc_memmgr.h"
|
|
|
|
// Local function prototypes:
|
|
static EntList * firstCandidate( EntList * );
|
|
static EntList * nextCandidate( EntList * );
|
|
|
|
/**
|
|
* Loops backwards through the children of this, recursively searching for
|
|
* alternate solutions (i.e., OR's which have alternate paths we haven't
|
|
* tried yet). We loop through all MultList type children which may have
|
|
* an OR with additional choices. (Which children to try is determined in
|
|
* a local function. We loop backwards because this is the reverse of the
|
|
* order we set the OR's. Later choices must be redone before earlier
|
|
* (reasons discussed in notes, 10/17). This function is the tryNext()
|
|
* for AND and ANDOR; the OR version is redefined.
|
|
*/
|
|
MatchType MultList::tryNext( EntNode * ents ) {
|
|
MatchType retval;
|
|
EntList * child = getLast();
|
|
|
|
child = firstCandidate( child );
|
|
while( child != NULL ) {
|
|
if( ( retval = ( dynamic_cast< MultList * >(child) )->tryNext( ents ) ) == MATCHALL ) {
|
|
// We're done - a good solution was found.
|
|
return MATCHALL;
|
|
}
|
|
if( retval == NEWCHOICE ) {
|
|
// If a new viable choice was found below, we must now reset all
|
|
// later OR's to their first choice. (That's what acceptChoice()
|
|
// does when choice = LISTEND.) This is necessary so that we can
|
|
// exhaust every possibility with this new choice. To do this we
|
|
// first reset all our children, and then return NEWCHOICE so that
|
|
// our parent (if exists) will also know to reset all its later OR
|
|
// children.
|
|
while( ( child = nextCandidate( child ) ) != NULL ) {
|
|
if( child->acceptChoice( ents ) && ents->allMarked() ) {
|
|
return MATCHALL;
|
|
}
|
|
}
|
|
return NEWCHOICE;
|
|
}
|
|
child = firstCandidate( child->prev );
|
|
}
|
|
// If we got here, we didn't find any new OR choices:
|
|
return NOMORE;
|
|
}
|
|
|
|
/**
|
|
* Finds an EntList from child's list which may have an OR with more
|
|
* choices below it. The acceptable choices are described in commenting
|
|
* below.
|
|
*/
|
|
static EntList * firstCandidate( EntList * child ) {
|
|
EntList * ent = child->lastNot( SIMPLE );
|
|
|
|
while( ent != NULL ) {
|
|
if( ent->viableVal() >= MATCHSOME ) {
|
|
// Return any non-SIMPLE ent where viable >= MATCHSOME. We even
|
|
// want to check an OR where numChoices = 1, because it may have
|
|
// an OR descendant with more choices.
|
|
return ent;
|
|
}
|
|
ent = ent->prevNot( SIMPLE );
|
|
}
|
|
return ent;
|
|
}
|
|
|
|
/**
|
|
* Same as prev function, searches forwards from ent after child.
|
|
*/
|
|
static EntList * nextCandidate( EntList * child ) {
|
|
EntList * ent = child->nextNot( SIMPLE );
|
|
|
|
while( ent != NULL ) {
|
|
if( ent->viableVal() >= MATCHSOME ) {
|
|
return ent;
|
|
}
|
|
ent = ent->nextNot( SIMPLE );
|
|
}
|
|
return ent;
|
|
}
|
|
|
|
/**
|
|
* Tries out the next choice of this. Basic algorithm is to first recurse
|
|
* to check for other solutions in the descendants of the current choice,
|
|
* and then to try our next choice.
|
|
*/
|
|
MatchType OrList::tryNext( EntNode * ents ) {
|
|
EntList * child;
|
|
MatchType retval;
|
|
|
|
mtxP->lock(); // For choice
|
|
if( choice == LISTEND ) {
|
|
// if we've already exhausted all the choices in this OR,
|
|
mtxP->unlock();
|
|
return NOMORE;
|
|
}
|
|
|
|
// First try other choices of descendants of current choice:
|
|
child = getChild( choice );
|
|
|
|
ents->sharedMtxP->lock(); // For EntNode Consistency
|
|
if( child->multiple() ) {
|
|
// I.e., if there are (or may be) more choices within the current
|
|
// choice, try those first. We must be sure to exhaust all choices in
|
|
// our descendants before moving on.
|
|
retval = ( ( MultList * )child )->tryNext( ents );
|
|
if( retval == MATCHALL ) {
|
|
mtxP->unlock();
|
|
ents->sharedMtxP->unlock();
|
|
return MATCHALL;
|
|
}
|
|
if( retval == NEWCHOICE ) {
|
|
// I.e., we found a next choice to go to, return so that the
|
|
// EntLists on the higher levels (if there are) can retry all the
|
|
// later choices with the new choice we just found. Otherwise,
|
|
// we'll continue below looking into our next choice.
|
|
mtxP->unlock();
|
|
ents->sharedMtxP->unlock();
|
|
return NEWCHOICE;
|
|
}
|
|
}
|
|
|
|
// No other choices among our descendants. Look for new choice at our
|
|
// level:
|
|
child->unmarkAll( ents );
|
|
if( choiceCount == 1 ) {
|
|
// Quick way to determine that there won't be any more choices here.
|
|
// (Also, it's nec. to unmark now, as we did above before returning and
|
|
// before the calling tryNext() tries earlier OR's - see notes, 11/12.)
|
|
choice = LISTEND;
|
|
mtxP->unlock();
|
|
ents->sharedMtxP->unlock();
|
|
return NOMORE;
|
|
}
|
|
mtxP->unlock();
|
|
|
|
// Otherwise, try our next:
|
|
if( acceptNextChoice( ents ) ) {
|
|
if( ents->allMarked() ) {
|
|
retval = MATCHALL;
|
|
} else {
|
|
retval = NEWCHOICE;
|
|
}
|
|
} else {
|
|
// Must have been no next choice (or none which mark anything new).
|
|
// acceptNextChoice() has set choice to LISTEND. We leave this OR
|
|
// unset and return NOMORE. If our calling function finds another
|
|
// choice elsewhere, it will reloop forwards and set all later OR's to
|
|
// their first choices, so that we'll be able to test every possibility
|
|
// with the new choice. At that time, this OrList will be reset to its
|
|
// first choice too.
|
|
retval = NOMORE;
|
|
}
|
|
ents->sharedMtxP->unlock();
|
|
return retval;
|
|
}
|