/*************************************************************************//** * entnode.cc \class EntNode * * * * Description: The EntNode class is used to store a collection of entity * * names. It stores them in alphabetical order. It is the key * * component of the EntList classes, which are used to store * * information on the instantiable complex entity types. This * * file contains EntNode member function definitions. * * * * Created by: David Rosenfeld * * Date: 9/18/96 * *****************************************************************************/ #include "clstepcore/complexSupport.h" /** * Given a list of entity names, creates a sorted linked list of EntNodes * corresponding to the list. A name which = "*" is a dummy trailer * implying the list has been completed. This function first builds the * list, then sets this to the first element, and then deletes the first * element. This ensures that `this' points to the start of the list. */ EntNode::EntNode( const char ** names ) { int j = 1, comp; EntNode * prev, *prev2 = NULL, // prev2 - the one before prev *newnode, *firstnode; const char * nm; // Create a first EntNode: firstnode = prev = new EntNode( names[0] ); while( names[j] && *names[j] != '*' ) { nm = names[j]; while( prev != NULL && ( comp = StrCmpIns( prev->name, nm ) ) < 0 ) { prev2 = prev; prev = prev->next; } // One exceptional case: If new name is same as prev, skip it: if( comp != 0 ) { // At this point, we know the new node belongs between prev2 and // prev. prev or prev2 may = NULL if newnode belongs at the end of // the list or before the beginning, respectively. newnode = new EntNode( nm ); newnode->next = prev; if( prev2 == NULL ) { // This will be the case if the inner while was never entered. // That happens when newnode belonged at the beginning of the // list. If so, reset firstnode. firstnode = newnode; } else { prev2->next = newnode; } } // Reset for next name: prev = firstnode; prev2 = NULL; j++; } // Finally, place the contents of firstnode in 'this', and delete first- // node. This ensures that 'this' is first. *this = *firstnode; firstnode->next = NULL; // (Otherwise, deleting firstnode would delete entire list.) delete firstnode; } /** * Copies all of ent's values here. */ EntNode & EntNode::operator= ( EntNode & ent ) { Name( ent.name ); setmark( ent.mark ); multSuprs( ent.multSupers ); next = ent.next; return *this; } /** * Marks/unmarks all the nodes in this's list (default is to mark). */ void EntNode::markAll( MarkType stamp ) { EntNode * node = this; while( node != NULL ) { node->mark = stamp; node = node->next; } } /** * Returns true if this and all nodes following it are marked. */ bool EntNode::allMarked() { EntNode * node = this; while( node != NULL ) { if( node->mark == NOMARK ) { return false; } node = node->next; } return true; } /** * Returns the number of unmarked nodes in this's list. */ int EntNode::unmarkedCount() { int count = 0; EntNode * node = this; while( node != NULL ) { if( node->mark == NOMARK ) { count++; } node = node->next; } return count; } /** * Starting from `this', search for the last node (along our next's) which * alphabetically precedes ent. */ EntNode * EntNode::lastSmaller( EntNode * ent ) { EntNode * eptr = next, *prev = this; if( *this > *ent ) { return NULL; } while( eptr && *eptr > *prev && *eptr < *ent ) { prev = eptr; eptr = eptr->next; } return prev; } /** * Check if our nodes are in order. If not, re-sort. The earlier part of * the list has been sorted but not necessarily the remainder. This algo- * rithm sorts our nodes in chunks, and is fairly efficient when we know * our nodes are basically in order. (sort() is called from STEPcomplex:: * Initialize() when we are creating a complex entity and have renamed a * few of the nodes. The nodes at first were in order; only the renamed * ones may be out of place.) */ void EntNode::sort( EntNode ** first ) { EntNode * eptr1, *eptr2, *temp1, *temp2; while( next && *this > *next ) { // Find the earliest node greater than next. (I.e., is not only this > // next but also some of this's preceding nodes. Since the nodes // earlier in the list are sorted already, we can easily determine the // ordered chunk of nodes which next should precede.) (eptr1 is // actually set to the one before, so that we'll know that eptr1->next // should now be set to next.) eptr1 = ( *first )->lastSmaller( next ); // Take the latest node eptr1 is greater than. (I.e., beyond next are // there more nodes which should be immediately after eptr1.) (The // succeeding nodes are not necessarily in order, so lastSmaller() also // checks that nodes later than next are also > their prev's.) if( eptr1 ) { eptr2 = next->lastSmaller( eptr1->next ); } else { eptr2 = next->lastSmaller( *first ); } // Switch the two lists: if( eptr1 ) { temp1 = eptr1->next; eptr1->next = next; temp2 = eptr2->next; eptr2->next = temp1; next = temp2; } else { // `this' should be first in the list. temp2 = eptr2->next; eptr2->next = *first; *first = next; next = temp2; } } if( next ) { next->sort( first ); } }