Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

idep_ldep.cxx

Go to the documentation of this file.
00001 // idep_ldep.c
00002 #include "idep_linkdep.h" 
00003 #include "idep_namearray.h"
00004 #include "idep_nameindexmap.h"
00005 #include "idep_binrel.h"
00006 #include "idep_string.h"
00007 #include "idep_tokeniter.h"
00008 #include "idep_aliastable.h"
00009 #include "idep_aliasutil.h"
00010 
00011 #include <cmath>      // log()
00012 #include <ctype.h>    // isascii() isspace()
00013 #include <cstring>    // strchr() strrchr() strlen() strcmp()
00014 #include <memory>     // memcpy() memset()
00015 #include <fstream>    // ifstream
00016 #ifdef USE_STRSTREAM
00017 #include <strstream>  // ostrstream
00018 #else
00019 #include <sstream>  // ostrstream
00020 #endif
00021 #include <iostream>   
00022 #include <cassert>
00023 
00024 // Handle compiler differences in definition of format flags
00025 #if ( __GNUC__ < 3 )
00026   typedef int FmtFlags_t;
00027 #else
00028   typedef std::ios_base::fmtflags FmtFlags_t;
00029 #endif
00030 
00031                 // -*-*-*- static functions -*-*-*-
00032 
00033 static std::ostream& warn(std::ostream& ing, int index) 
00034 {
00035     return ing << "Warning<" << index << ">: "; // '<' and '>' match cycle  
00036 }
00037 
00038 static std::ostream& err(std::ostream& orr) 
00039 {
00040     return orr << "Error: ";
00041 }
00042 
00043 static const char *stripDotSlash(const char *originalPath)
00044 {
00045     if (originalPath) {
00046         while ('.' == originalPath[0] && '/' == originalPath[1]) {
00047             originalPath += 2;
00048         }
00049     }
00050     return originalPath;
00051 }
00052 
00053 static int isLocal(const char *dirFile)
00054 {
00055     return !strchr(dirFile, '/');
00056 }
00057 
00058 static char *removeFileName(char *dirPath)
00059 {
00060     char *slash = strrchr(dirPath, '/');
00061     if (slash) {
00062         slash[1] = '\0';
00063     }
00064     else {
00065         dirPath[0] = '\0';
00066     }
00067     return dirPath;
00068 }
00069 
00070 static char *removeSuffix(char *dirPath)
00071 {
00072     char *dot = strrchr(dirPath, '.');
00073     if (dot && !strchr(dot, '/')) {
00074         dot[0] = '\0';
00075     }
00076     return dirPath;
00077 }
00078 
00079 static int digits(int n) 
00080 {
00081     int fieldWidth = 10;
00082     assert (sizeof (long int) >= 4);
00083     long int x = 1000 * 1000 * 1000;    // requires 4-byte integer.
00084     while (fieldWidth > 1 && 0 == n / x) {
00085         --fieldWidth;
00086         x /= 10;
00087     }
00088     return fieldWidth;
00089 }
00090 
00091 static double logBase2(double x) 
00092 {
00093     // log (x) = ln(x)/ln(a) 
00094     //    a
00095 
00096     assert(x > 0.0);
00097     return log(x)/log(2);
00098 }
00099 
00100 static double ccdBalencedBinaryTree(int n) 
00101 {
00102     // CCD(n)         = (n + 1) * (log (n + 1) - 1) + 1
00103     //       balanced                 2
00104     //       binary
00105     //       tree
00106 
00107     assert(n >= 0);
00108     return (n + 1) * (logBase2(n + 1) - 1) + 1;
00109 }
00110 
00111                 // -*-*-*- idep_LinkDep_i -*-*-*-
00112 
00113 struct idep_LinkDep_i {
00114     idep_NameIndexMap d_unaliases;          // e.g., ".", "/usr/include"
00115     idep_AliasTable d_aliases;              // e.g., fooa -> fooarray
00116     idep_NameArray d_dependencyFiles;       // hold compile-time dependencies
00117 
00118     idep_NameIndexMap *d_componentNames_p;  // keys for relation
00119     idep_BinRel *d_dependencies_p;          // compile-time dependencies
00120     int *d_map_p;                           // map to levelized order   
00121     int *d_levels_p;                        // number of components per level
00122     int *d_levelNumbers_p;                  // level number for each component
00123     int *d_cycles_p;                        // labels components in each cycle
00124     int *d_weights_p;                       // number of components per cycle
00125     int *d_cycleIndices_p;                  // consecutive cycle index
00126     int d_numComponents;                    // number of components in system
00127     int d_numLevels;                        // number of levels in system 
00128     int d_numCycles;                        // number of cycles in system
00129     int d_numMembers;                       // number of components in cycles
00130     int d_ccd;                              // cumulative component dependency
00131 
00132     idep_LinkDep_i();
00133     ~idep_LinkDep_i();
00134 
00135     int entry(const char *name, int suffixFlag);
00136     void loadDependencies(std::istream& in, int suffixFlag);
00137     void createCycleArray();
00138     int calculate(std::ostream& orr, int canonicalFlag, int suffixFlag);
00139 };
00140 
00141 idep_LinkDep_i::idep_LinkDep_i() 
00142 : d_componentNames_p(0)
00143 , d_dependencies_p(0)
00144 , d_map_p(0)
00145 , d_levels_p(0)
00146 , d_levelNumbers_p(0)
00147 , d_cycles_p(0)
00148 , d_weights_p(0)
00149 , d_cycleIndices_p(0)
00150 , d_numComponents(-1)
00151 , d_numLevels(-1)
00152 , d_numCycles(-1)
00153 , d_numMembers(-1)
00154 , d_ccd(-1)
00155 {
00156 }
00157 
00158 idep_LinkDep_i::~idep_LinkDep_i() 
00159 {
00160     delete d_componentNames_p;
00161     delete d_dependencies_p;
00162     delete [] d_map_p;
00163     delete [] d_levels_p;
00164     delete [] d_levelNumbers_p;
00165     delete [] d_cycles_p;
00166     delete [] d_weights_p;
00167     delete [] d_cycleIndices_p;
00168 }
00169 
00170 int idep_LinkDep_i::entry(const char *name, int suffixFlag) 
00171 {
00172     int size = strlen(name) + 1;
00173     char *buf = new char[size];
00174     memcpy(buf, name, size);
00175 
00176     if (!isLocal(buf)) {
00177         removeFileName(buf);
00178         if (d_unaliases.lookup(buf) >= 0) {             // found unalias
00179             memcpy(buf, name, size);                    // restore buffer
00180         }
00181     }
00182 
00183     if (suffixFlag) {
00184         removeSuffix(buf);
00185     }
00186 
00187     const char *componentName = d_aliases.lookup(buf);
00188     if (!componentName) {
00189         const char SLASH_CHAR = '/';
00190         const char NULL_CHAR = '\0';
00191         int len = strlen(buf);
00192         int last = len - 1;
00193         if (SLASH_CHAR == buf[last]) {             // If the input ends in '/' 
00194             buf[last] = NULL_CHAR;                 // try removing the '/' and
00195             componentName = d_aliases.lookup(buf); // checking for that alias.
00196             if (!componentName) {
00197                 buf[last] = SLASH_CHAR; // restore
00198             }
00199         }
00200     }
00201 
00202     if (!componentName) {
00203         componentName = buf;
00204     }
00205 
00206     int length = d_componentNames_p->length();
00207     int index = d_componentNames_p->entry(componentName);
00208     if (d_componentNames_p->length() > length) {
00209         d_dependencies_p->appendEntry();
00210     }
00211 
00212     delete [] buf;
00213 
00214     return index;
00215 }
00216 
00217 void idep_LinkDep_i::loadDependencies(std::istream& in, int suffixFlag)
00218 {
00219     enum { INVALID_INDEX = -1 };
00220     const char NEWLINE_CHAR = '\n';
00221     int lineno = 1;
00222     int fromIndex = INVALID_INDEX;
00223     int lastTokenWasNewline = 1;
00224 
00225     for (idep_TokenIter it(in); it; ++it) {     
00226         if ('#' == *it()) {                          // strip comment if any
00227             while (it && '\n' != *it()) {
00228                 ++it;
00229             }
00230             if (!it) {                               // either !it or '\n'
00231                 continue;
00232             }
00233         }
00234 
00235         if (NEWLINE_CHAR == *it()) {                    
00236             ++lineno;                                // end of line
00237             if (lastTokenWasNewline) {
00238                 fromIndex = INVALID_INDEX;           // end of current sequence
00239             }
00240             lastTokenWasNewline = 1;                 // record newline state
00241         }
00242         else {
00243             if (INVALID_INDEX == fromIndex) {
00244                 fromIndex = entry(it(), suffixFlag); // start of new sequence
00245             }
00246             else {                                   // found a dependency
00247                 int toIndex = entry(it(), suffixFlag);     
00248                 d_dependencies_p->set(fromIndex, toIndex); 
00249             }
00250             lastTokenWasNewline = 0;                 // record newline state
00251         }
00252     }
00253 }
00254 
00255 void idep_LinkDep_i::createCycleArray()
00256 {
00257     assert (!d_cycles_p);               // should not already exist
00258     assert (!d_weights_p);              // should not already exist
00259     assert (!d_cycleIndices_p);         // should not already exist
00260     assert (d_numComponents >= 0);      // should be valid
00261 
00262     // Create the cycle array used to detect and identify potential cycles.
00263     
00264     d_cycles_p = new int[d_numComponents];  // identifies members of cycles
00265     d_weights_p = new int[d_numComponents]; // identifies weights of cycles
00266     d_cycleIndices_p = new int[d_numComponents];  // consecutive indices
00267 
00268     // Members of each cycle are identified by the index of their first member.
00269 
00270     enum { NO_CYCLE = -1 };                 
00271     int i;
00272     for (i = 0; i < d_numComponents; ++i) {  
00273         d_cycles_p[i] = NO_CYCLE;       // Initially each entry is invalid. 
00274         d_weights_p[i] = 0;             // Initially weight of each cycle is 0.
00275         d_cycleIndices_p[i] = NO_CYCLE; // Initially each entry is invalid. 
00276                                         // These indices will be determined
00277                                         // after levelization has occurred.
00278     }
00279 
00280     d_numCycles = 0;                    // # of unique design cycles
00281     d_numMembers = 0;                   // # of cyclicly-dependent components
00282 
00283     // Load the cycle array.  For each cycle detected, the non-negative 
00284     // index of the lowest participating component is used as a tag to 
00285     // identify that cycle.  For each component we will scan ahead to see 
00286     // on what other components this component is mutually dependent.  
00287     // If one or more is found, each of these locations will be set to 
00288     // the index value of the first (primary) component in the cycle.  
00289     // Ideally there will be no cycles, in which case each entry in the 
00290     // array will be left set to -1.  We will use the cycle array initially 
00291     // to report all cyclic dependencies and again later to facilitate
00292     // the levelization algorithm in the presence of cycles.
00293 
00294     for (i = 0; i < d_numComponents; ++i) { 
00295         if (d_cycles_p[i] >= 0) {
00296             continue;               // part of a previously reported cycle
00297         }
00298         int cycleFound = 0;
00299         d_cycles_p[i] = i;          // first component in potential cycle
00300         int j;
00301         for (j = i + 1; j < d_numComponents; ++j) {
00302             if (d_cycles_p[j] >= 0) {
00303                 continue;           // part of a previously reported cycle
00304             }
00305             if (d_dependencies_p->get(i, j) && d_dependencies_p->get(j, i)) { 
00306                 cycleFound = 1;     // record that we have a cycle
00307                 d_cycles_p[j] = i;  // record index of first component
00308             }
00309         }
00310         if (cycleFound) {           // if cycle found involving component `i'
00311             int weight = 0;
00312             for (j = i; j < d_numComponents; ++j) { // find each cycle member
00313                 if (d_cycles_p[j] == i) {
00314                     ++weight;       // # members in this cycle
00315                 }
00316             }
00317             for (j = i; j < d_numComponents; ++j) { // find each cycle member
00318                 if (d_cycles_p[j] == i) {
00319                     d_weights_p[j] = weight;  // store weight for each member
00320                 }
00321             }
00322             d_numMembers += weight;   // total # of members in cycles   
00323             ++d_numCycles;
00324         }
00325         else {
00326             d_cycles_p[i] = NO_CYCLE; // component `i' is not part of a cycle
00327         }
00328     }
00329 }
00330 
00331 int idep_LinkDep_i::calculate(std::ostream& orr, int canonicalFlag, int suffixFlag)
00332 {
00333     enum { IOERRR = -1 };
00334 
00335     // clean up any previous calculation artifacts
00336     delete d_componentNames_p;  
00337     delete d_dependencies_p;
00338     delete [] d_map_p;
00339     delete [] d_levels_p;
00340     delete [] d_levelNumbers_p;
00341     delete [] d_cycles_p;
00342     delete [] d_weights_p;
00343     delete [] d_cycleIndices_p;
00344 
00345     // allocate new data structures for this calculation
00346     d_componentNames_p = new idep_NameIndexMap;
00347     d_dependencies_p = new idep_BinRel;     
00348     d_map_p = 0;                // allocated later when length is known
00349     d_levels_p = 0;             // allocated later when length is known
00350     d_levelNumbers_p = 0;       // allocated later when length is known
00351     d_cycles_p = 0;             // allocated later when length is known
00352     d_numLevels = -1;           // invalidate for now
00353     d_numComponents = -1;       // invalidate for now (-1 value is important)
00354     d_numCycles = -1;           // invalidate for now
00355     d_numMembers = -1;          // invalidate for now
00356     d_ccd = -1;                 // invalidate for now
00357 
00358     // Now try to read dependencies from specified set of files.
00359     // If an I/O error occurs, abort; otherwise keep on processing.
00360     int i;
00361     for (i = 0; i < d_dependencyFiles.length(); ++i) {
00362         const int INSANITY = 1000;
00363         if (d_dependencies_p->length() > INSANITY) {
00364             orr << "SANITY CHECK: Number of components is currently " 
00365                << d_dependencies_p->length() << " !!!!" << std::endl;
00366 
00367         }
00368         enum { IOERROR = -1 };
00369         const char *file = d_dependencyFiles[i];
00370 
00371         if ('\0' == *file) {
00372             loadDependencies(std::cin, suffixFlag);
00373             // reset eof for standard input
00374             std::cin.clear(std::ios::iostate(0));
00375         }
00376         else {
00377             std::ifstream in(file);
00378             if (!in) {
00379                 err(orr) << "dependency file \"" << file 
00380                         << "\" not found." << std::endl;
00381                 return IOERROR;
00382             }
00383             loadDependencies(in, suffixFlag);
00384         }
00385     }
00386 
00387     // We can now allocate fixed size arrays:
00388 
00389     d_numComponents = d_dependencies_p->length();
00390     assert (d_componentNames_p->length() == d_numComponents);
00391 
00392     // Create the level array for component name indices.  We will fill in the 
00393     // level array with the number of components on each level.  
00394 
00395     d_levels_p = new int[d_numComponents]; // will holds # of components/level
00396     d_numLevels = 0;                       // initially there are no levels
00397 
00398     // Create the level number array to hold the level number for each 
00399     // component.  This array will be filled in at the end of this function.
00400 
00401     d_levelNumbers_p = new int[d_numComponents]; // will holds level #'s
00402 
00403     // Create the mapping array for component name indices.  This array
00404     // will hold the sorted indices of the original component names.
00405 
00406     d_map_p = new int[d_numComponents]; // array of levelized component indices
00407     int pIndex = 0;                     // current length of mapping
00408 
00409     // Create an array of byte vectors.  Each byte vector identifies the 
00410     // components that are below the indicated level index.  The rows are 
00411     // allocated as the levels in the system are defined, beginning with level 
00412     // corresponding to d_numLevels = 0.  At the end of this calculation, the 
00413     // first d_numLevels + 1 byte vectors in this array must be deleted 
00414     // explicitly.
00415     //
00416     // level
00417     // index
00418     //       +-------+   
00419     //   N   |   ?   |
00420     //       +-------+
00421     //  N-1  |   ?   |         +----------------------------------+
00422     //       +-------+         | `i' is defined to be d_numLevels |
00423     //       :       :         +----------------------------------+---+
00424     //       :       :         | `N' is defined to be d_numComponents |
00425     //       +-------+         +--------------------------------------+
00426     //  i+1  |   ?   |
00427     //       +-------+
00428     //   i   |   o---|--->[ 1 ][ 1 ][ 0 ][ 1 ][ 1 ][ 1 ][ 0 ] ... [ 0 ]
00429     //       +-------+
00430     //       :       :
00431     //       :       :
00432     //       +-------+
00433     //   1   |   o---|--->[ 0 ][ 1 ][ 0 ][ 0 ][ 1 ][ 0 ][ 0 ] ... [ 0 ]
00434     //       +-------+
00435     //   0   |   o---|--->[ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ 0 ] ... [ 0 ]
00436     //       +-------+    
00437     // component index:     0    1    2    3    4    5    6        N-1
00438 
00439     char **lowerThan = new char *[d_numComponents + 1]; // array of byte sets 
00440 
00441     lowerThan[0] = new char[d_numComponents];  // set of lower-level components
00442     memset(lowerThan[0], 0, d_numComponents);  // initially this set is empty
00443     char *current = new char[d_numComponents]; // components on current level
00444 
00445     d_dependencies_p->makeTransitive(); // perform transitive closure algorithm
00446 
00447     createCycleArray();            // determine and label members of all cycles
00448 
00449     // We can now use the transitive dependency relation to sort the 
00450     // components in this system into levelized order (provided the
00451     // graph is asyclic).  In order to facilitate the levelization 
00452     // algorithm, the principal members of each cycle will be temporarily 
00453     // stripped of their dependency on the other members of that cycle.
00454     // All of the remaining members will be ignored by the levelization
00455     // algorithm (by marking them as already belonging to a lower level). 
00456 
00457     for (i = 0; i < d_numComponents; ++i) {
00458         if (d_cycles_p[i] == i) {
00459           int j;
00460           for (j = i + 1; j < d_numComponents; ++j) {
00461             if (d_cycles_p[j] == i) {
00462               assert(d_dependencies_p->get(i,j));
00463               d_dependencies_p->clr(i,j); // strip cyclic dependency
00464               lowerThan[0][j] = 1; // ignore other members in algorithm
00465             }
00466           }
00467         }
00468     }
00469 
00470     // We will now construct the levelized array of component indices.  For
00471     // each level in this system, we will examine each component in the system
00472     // to see if it depends on any higher level components.  Note that we have 
00473     // already stripped out cyclic dependencies as described above.  If a 
00474     // component is part of a lower level we will ignore it.  Otherwise, we 
00475     // will check to see if that component depends on any other components 
00476     // that are _not_ at a lower level.  If so, the component is skipped over; 
00477     // otherwise the component index is added to the current level and 
00478     // appended to the end of the levelized list.  If this index corresponds
00479     // to the principal member of a cycle, we use the weight of the cycle to 
00480     // determine the level below the current level to use to to check
00481     // dependencies.  If the principal member of the cycle depends only on
00482     // components at a level "weight" (or more) lower than the current level,
00483     // all other members are immediately appended to the list in their
00484     // original order.  At this point, we restore the cyclic dependencies of 
00485     // that principal component on the other members of its cycle.  After 
00486     // iterating through all of the components, the number of components on 
00487     // the current level is appended to the level array and the current level 
00488     // set is united with the lower level set.  This process repeats until all
00489     // components are assigned a level.
00490 
00491     while (pIndex < d_numComponents) {  // not all components assigned a level
00492         int componentCount = 0;         // number of components on this level
00493         memset(current, 0, d_numComponents); // initially current level empty
00494         int i;
00495         for (i = 0; i < d_numComponents; ++i) {
00496             if (d_cycles_p[i] >= 0 && d_cycles_p[i] != i) {
00497                 continue;   // component is non principal member of a cycle
00498             }
00499 
00500             if (lowerThan[d_numLevels][i]) {    
00501                 continue;   // already at a lower level;
00502             }
00503 
00504             int weight = 1; // weight of non-cyclically dependent component
00505 
00506             if (d_cycles_p[i] == i) {   // if principal member of cycle
00507                 weight = d_weights_p[i];
00508                 if (d_weights_p[i] > d_numLevels + 1) {
00509                     continue; // weight of cycle two heigh for current level
00510                 }
00511             }
00512 
00513             int searchLevel = d_numLevels + 1 - weight; // allowed dependencies
00514             int j;
00515             for (j = 0; j < d_numComponents; ++j) {
00516                 if (i == j) {
00517                     continue;
00518                 }
00519                 if (d_dependencies_p->get(i,j) && !lowerThan[searchLevel][j]) {
00520                     break; // depends on component not at or below search level
00521                 }
00522             }
00523             if (j < d_numComponents) {
00524                 continue;   // consider next candidate i
00525             }
00526             current[i] = 1; // record component as being at the current level
00527             d_map_p[pIndex++] = i; // append component in levelized order
00528             ++componentCount;   
00529             if (d_cycles_p[i] == i) {   // if principal member of a cycle
00530                 for (j = i + 1; j < d_numComponents; ++j) {
00531                     if (d_cycles_p[j] == i) {  // if other member of this cycle
00532                         d_map_p[pIndex++] = j; // append it to current level
00533                         ++componentCount;
00534                         d_dependencies_p->set(i,j); // restore dependencies
00535                     }
00536                 }
00537             }
00538         }
00539 
00540         // advance to next level
00541         for (i = 0; i < d_numComponents; ++i) {
00542             current[i] |= lowerThan[d_numLevels][i]; 
00543         }
00544         d_levels_p[d_numLevels++] = componentCount; // components per level
00545         lowerThan[d_numLevels] = current;    // attach new lower level
00546         current = new char[d_numComponents]; // reallocate current array
00547     }
00548 
00549     assert (pIndex == d_numComponents);
00550 
00551     // at this point we can load the level number array
00552 
00553     int start = 0;
00554 
00555     for (i = 0; i < d_numLevels; ++i) {
00556         int top = start + d_levels_p[i];
00557         int j;
00558         for (j = start; j < top; ++j) {
00559             d_levelNumbers_p[d_map_p[j]] = i;
00560         }
00561         start = top;
00562     }
00563 
00564     // Sort components within each level lexicographically to make names 
00565     // easier to find and to provide a canonical order to facilitate finding
00566     // differences as software is modified (e.g., via the Unix diff command).
00567 
00568     start = 0;
00569     int k;
00570     for (k = 0; k < d_numLevels; ++k) {
00571       int top = start + d_levels_p[k];
00572       int i;
00573       for (i = start + 1; i < top; ++i) {
00574         int j;
00575         for (j = start; j < i; ++j) {
00576           if (strcmp((*d_componentNames_p)[d_map_p[i]],
00577                      (*d_componentNames_p)[d_map_p[j]]) < 0) {
00578             int tmp = d_map_p[i];
00579             d_map_p[i] = d_map_p[j];
00580             d_map_p[j] = tmp;
00581           }
00582         }
00583       }
00584       start = top;
00585     }
00586 
00587     // We can now uses the cycles array and the level map to create the 
00588     // cycleIndex array.  This array assigns all components of each cycle
00589     // a unique cycle index (in increasing order w.r.t. level).
00590 
00591     int cycleCount = 0;
00592     for (i = 0; i < d_numComponents; ++i) { 
00593         const int label = d_cycles_p[d_map_p[i]];
00594         if (label < 0) {
00595             continue; // not part of any cycle
00596         }
00597 
00598         const int index = d_cycleIndices_p[d_map_p[i]];
00599         if (index >= 0 && index < cycleCount) {
00600             continue; // part of lower level cycle
00601         }
00602 
00603         // Found the next cycle, go through the remander of the sequence and
00604         // annotate each correspondingly labeled component with current cycle 
00605         // index in the cycleIndices array.
00606         int j;
00607         for (j = i; j < d_numComponents; ++j) { 
00608           if (label == d_cycles_p[d_map_p[j]]) {
00609             d_cycleIndices_p[d_map_p[j]] = cycleCount;
00610           }
00611         }
00612 
00613         ++cycleCount;
00614     }
00615 
00616     assert(cycleCount == d_numCycles); 
00617         
00618     // Now sort components within each level again, but this time
00619     // group cyclically dependent components together in order of
00620     // cycle index to facilitate understanding of cycle composition.
00621     // The previous sort ensured that cycle indices will be in the 
00622     // order of the lexicographically smallest member of the cycle 
00623     // on a given level.
00624 
00625     start = 0;
00626     for (k = 0; k < d_numLevels; ++k) {
00627       int top = start + d_levels_p[k];
00628       int i;
00629       for (i = start + 1; i < top; ++i) {
00630         int j;
00631         for (j = start; j < i; ++j) {
00632           int ci = d_cycleIndices_p[d_map_p[i]];
00633           int cj = d_cycleIndices_p[d_map_p[j]];
00634           if (ci < cj || ci == cj &&
00635               strcmp((*d_componentNames_p)[d_map_p[i]],
00636                      (*d_componentNames_p)[d_map_p[j]]) < 0) {
00637             int tmp = d_map_p[i];
00638             d_map_p[i] = d_map_p[j];
00639             d_map_p[j] = tmp;
00640           }
00641         }
00642       }
00643       start = top;
00644     }
00645 
00646     // Clean up local data structures.
00647     for (i = 0; i <= d_numLevels; ++i) {
00648         delete [] lowerThan[i];
00649     }
00650     delete [] lowerThan;
00651     delete [] current;
00652 
00653     // Calculate CCD and cache the value in a data member of the object.
00654     idep_BinRel tmp = *d_dependencies_p; // temporary for calculating CCD
00655     for (i = 0; i < d_numComponents; ++i) {
00656         if (0 == d_levelNumbers_p[i]) { 
00657             for (int j = 0; j < d_numComponents; ++j) {
00658                 tmp.clr(j, i); // ignore dependencies on all level 0 components
00659             }
00660         }
00661         else {
00662             tmp.set(i, i);     // each component itself contributes unit weight
00663         }
00664     }
00665 
00666     int sum = 0;
00667 
00668     for (i = 0; i < d_numComponents; ++i) {
00669         for (int j = 0; j < d_numComponents; ++j) {
00670             if (tmp.get(i,j)) {
00671                 ++sum;
00672             }
00673         }
00674     }
00675 
00676     d_ccd = sum;        // Cache this value -- too hard to calculate later.
00677 
00678     if (canonicalFlag) {
00679         // In order to ensure a canonical representations with redundant
00680         // dependencies removed, it is necessary to create a canonical
00681         // sorted binary relation based on the d_map_p array.  After removing
00682         // transitive entries from that relation, the results are then mapped 
00683         // back to the d_dependencies_p relation.
00684 
00685         idep_BinRel tmp(d_numComponents);
00686         int i;
00687         for (i = 0; i < d_numComponents; ++i) {
00688             int u = d_map_p[i];
00689             for (int j = 0; j < d_numComponents; ++j) {
00690                 int v = d_map_p[j];
00691                 int bit = d_dependencies_p->get(u, v);
00692                 tmp.set(i, j, bit);
00693             }
00694         }
00695 
00696         tmp.makeNonTransitive();
00697 
00698         for (i = 0; i < d_numComponents; ++i) {
00699             int u = d_map_p[i];
00700             for (int j = 0; j < d_numComponents; ++j) {
00701                 int v = d_map_p[j];
00702                 int bit = tmp.get(i, j);
00703                 d_dependencies_p->set(u, v, bit);
00704             }
00705         }
00706     }
00707 
00708     return d_numMembers;
00709 }
00710 
00711                 // -*-*-*- idep_LinkDep -*-*-*-
00712 
00713 idep_LinkDep::idep_LinkDep() 
00714 : d_this(new idep_LinkDep_i)
00715 {
00716 }
00717 
00718 idep_LinkDep::~idep_LinkDep()
00719 {
00720     delete d_this;
00721 }
00722 
00723 void idep_LinkDep::addDependencyFile(const char *fileName)
00724 {
00725     d_this->d_dependencyFiles.append(fileName);
00726 }
00727 
00728 const char *idep_LinkDep::addAlias(const char *alias, const char *component)
00729 {
00730     return d_this->d_aliases.add(alias, component) < 0 ?
00731                                         d_this->d_aliases.lookup(alias) : 0;
00732 }
00733 
00734 int idep_LinkDep::readAliases(std::ostream& orr, const char *file)
00735 {
00736     return idep_AliasUtil::readAliases(&d_this->d_aliases, orr, file);
00737 }
00738 
00739 void idep_LinkDep::addUnaliasDirectory(const char *dirName)
00740 {
00741     if (*dirName) {                             
00742         int len = strlen(dirName);
00743         if ('/' == dirName[len-1]) {            // already ends in '/'
00744             const char *n = stripDotSlash(dirName);
00745             if (*n) {                           // avoid adding empty dir 
00746                 d_this->d_unaliases.add(n);
00747             }
00748         }
00749         else {                                  // add trailing '/'
00750             char *buf = new char[len+2];                
00751             memcpy (buf, dirName, len);
00752             buf[len] = '/';
00753             buf[len+1] = '\0';
00754             const char *n = stripDotSlash(buf);
00755             if (*n) {                           // avoid adding empty dir
00756                 d_this->d_unaliases.add(n);
00757             }
00758             delete [] buf;
00759         }
00760     }
00761 }
00762 
00763 int idep_LinkDep::readUnaliasDirectories(const char *file)
00764 {
00765     enum { BAD = -1, GOOD = 0 };
00766 
00767     std::ifstream in(file);
00768     if (!in) {  
00769         return BAD;
00770     }
00771 
00772     for (idep_TokenIter it(in); it; ++it) {
00773         if ('\n' != *it()) {
00774             d_this->d_unaliases.add(it());
00775         }
00776     }
00777 
00778     return GOOD;
00779 }
00780 
00781 int idep_LinkDep::calculate(std::ostream& orr, int canonicalFlag, int suffixFlag)
00782 {
00783     return d_this->calculate(orr, canonicalFlag, suffixFlag);
00784 }
00785 
00786 int idep_LinkDep::numComponents() const
00787 {
00788     return d_this->d_numComponents;
00789 }
00790 
00791 int idep_LinkDep::numPackages() const
00792 {
00793     return numComponents() > 0 ? d_this->d_levels_p[0] : 0;
00794 }
00795 
00796 int idep_LinkDep::numLocalComponents() const
00797 {
00798     return numComponents() - numPackages();
00799 }
00800 
00801 int idep_LinkDep::numLevels() const
00802 {
00803     return d_this->d_numLevels - 1; // depth of component dependency graph
00804 }
00805 
00806 int idep_LinkDep::numCycles() const
00807 {
00808     return d_this->d_numCycles;
00809 }
00810 
00811 int idep_LinkDep::numMembers() const
00812 {
00813     return d_this->d_numMembers;
00814 }
00815 
00816 int idep_LinkDep::ccd() const
00817 {
00818     return d_this->d_ccd; 
00819 }
00820 
00821 double idep_LinkDep::acd() const
00822 {
00823     return numLocalComponents() > 0 ? ccd()/(double)numLocalComponents() : 0.0;
00824 }
00825 
00826 double idep_LinkDep::nccd() const
00827 {
00828     return numLocalComponents() > 0 ? 
00829         ccd()/ccdBalencedBinaryTree(numLocalComponents()) : 0.0;
00830 }
00831  
00832 void idep_LinkDep::printAliases(std::ostream& o) const
00833 {
00834     idep_AliasIter it(*this);
00835     if (it) {
00836         int fieldWidth = 0;
00837         {
00838             for (idep_AliasIter it(*this); it; ++it) {
00839                 int len = strlen(it.fromName());
00840                 if (fieldWidth < len) {
00841                      fieldWidth = len;
00842                 }
00843             }
00844         }
00845         o << "ALIASES:" << std::endl;
00846         for (; it; ++it) {
00847             o.width(fieldWidth);
00848             o << it.fromName() << " -> " << it.toName() << std::endl;
00849         }
00850         o << std::endl;
00851     }
00852 }
00853 
00854 void idep_LinkDep::printUnaliases(std::ostream& o) const
00855 {
00856     idep_UnaliasIter it(*this);
00857     if (it) {
00858         o << "UNALIASES:" << std::endl;
00859         for (; it; ++it) {
00860              o << it() << std::endl;
00861         }
00862         o << std::endl;
00863     }
00864 }
00865 
00866 void idep_LinkDep::printCycles(std::ostream& ing) const
00867 {
00868     const char *const SPACE = "    ";
00869     for (idep_CycleIter cit(*this); cit; ++cit) {
00870         warn(ing, cit.cycle()) << "The following " << cit.weight() 
00871                   << " components are cyclically dependent:" << std::endl;
00872 
00873         for (idep_MemberIter mit(cit); mit; ++mit) {
00874             ing << SPACE << mit() << std::endl;
00875         }
00876         ing << std::endl;
00877     }
00878 }
00879 
00880 void idep_LinkDep::printLevels(std::ostream& o, int longFlag, int supressFlag) const
00881 {
00882     if (!supressFlag) {
00883         o << "LEVELS:" << std::endl;
00884     }
00885 
00886     const char CY_LT = '<';     // define characters to surround cycle index
00887     const char CY_RT = '>';     // define characters to surround cycle index
00888 
00889     int numLevelDigits = digits(numLevels() - 1);
00890     int componentNameFieldWidth = 0;
00891 
00892     int numCycleDigits = digits(numCycles() - 1);
00893     int cycleFieldWidth = numCycleDigits + 2;
00894 
00895     if (longFlag) {
00896         for (idep_LevelIter lit(*this); lit; ++lit) {
00897             for (idep_ComponentIter cit(lit); cit; ++cit) {
00898                 int len = strlen(cit());
00899                 if (componentNameFieldWidth < len) {
00900                      componentNameFieldWidth = len;
00901                 }
00902             }
00903         }
00904     }
00905 
00906     for (idep_LevelIter lit(*this); lit; ++lit) {
00907         if (!supressFlag) {
00908             o.width(numLevelDigits);
00909             o << lit() << ". ";
00910         }
00911         int firstFlag = 1;
00912         for (idep_ComponentIter cit(lit); cit; ++cit) {
00913             if (firstFlag) {
00914                 firstFlag = 0;
00915             }
00916             else {
00917                 if (!supressFlag) {
00918                     o.width(numLevelDigits + 2);
00919                     o << "";
00920                 }
00921             }
00922 
00923             if (longFlag) {
00924                 o.width(componentNameFieldWidth);
00925             }
00926             o << cit();
00927 
00928             if (numCycles() > 0 && !supressFlag) {
00929                 char field[100]; // will always be large enough
00930 #ifdef USE_STRSTREAM
00931                 std::ostrstream f(field, sizeof field);
00932 #else
00933                 std::ostringstream f(field);
00934 #endif
00935                 f << CY_LT << cit.cycle() << CY_RT << std::ends;
00936                 o.width(cycleFieldWidth);
00937                 if (cit.cycle()) {
00938                     FmtFlags_t oldState = o.flags();
00939                     o.setf(std::ios::left, std::ios::adjustfield);
00940                     o << field;
00941                     o.flags(oldState);
00942                 }
00943                 else {
00944                     o << ""; 
00945                 }
00946             }
00947 
00948             if (longFlag) {
00949                 int firstFlag = 1;
00950                 for (idep_DependencyIter dit(cit); dit; ++dit) {
00951                     if (firstFlag) {
00952                         firstFlag = 0;
00953                     }
00954                     else {
00955                         if (!supressFlag) {
00956                             o.width(numLevelDigits + 2);
00957                             o << "";
00958                             if (numCycles() > 0) {
00959                                 o.width(numCycleDigits + 2);
00960                                 o << "";
00961                             }
00962                         }
00963                         o.width(componentNameFieldWidth);
00964                         o << "";
00965                     }
00966                     o << ' ';
00967                     if (!supressFlag) {
00968                         o.width(numLevelDigits);
00969                         o << dit.level() << ". ";
00970                     }
00971                     o << dit();
00972                     if (dit.cycle() && !supressFlag) {
00973                         o << CY_LT << dit.cycle() << CY_RT;
00974                     }
00975                     o << std::endl;
00976                 }
00977             }
00978             o << std::endl;
00979         }
00980         o << std::endl;
00981     }
00982 }
00983 
00984 inline const char *s(int n) { return (n == 1) ? "" : "s"; }
00985     // Helps get singular and plural right.
00986 
00987 void idep_LinkDep::printSummary(std::ostream& o) const
00988 {
00989     FmtFlags_t iostate = o.setf(std::ios::left, std::ios::adjustfield);
00990     const int FIELD_BUFFER_SIZE = 100;   // Not completely arbitrary -- this
00991     char field[FIELD_BUFFER_SIZE];       // size will be always big enough!
00992     o << "SUMMARY:" << std::endl;
00993 
00994     const int N = 12;           // width of number field
00995     const int G = 1;            // width of gap
00996     const int W = 23;           // width of entire column
00997 
00998     if (numCycles() > 0) {
00999         { 
01000 #ifdef USE_STRSTREAM
01001             std::ostrstream f(field, sizeof field);
01002 #else
01003             std::ostringstream f(field);
01004 #endif
01005             f.width(N);
01006             f << numCycles() << " Cycle" << s(numCycles()) << std::ends;
01007             o.width(W);
01008             o << field;
01009         }
01010         o.width(G);
01011         o << "";
01012         { 
01013 #ifdef USE_STRSTREAM
01014             std::ostrstream f(field, sizeof field);
01015 #else
01016             std::ostringstream f(field);
01017 #endif
01018             f.width(N);
01019             f << numMembers() << " Members" << std::ends;
01020             o.width(W);
01021             o << field;
01022         }
01023         o << std::endl;
01024     }
01025     { 
01026 #ifdef USE_STRSTREAM
01027         std::ostrstream f(field, sizeof field);
01028 #else
01029         std::ostringstream f(field);
01030 #endif
01031         f.width(N);
01032         f << numLocalComponents() << " Component" 
01033                                   << s(numLocalComponents()) << std::ends;
01034         o.width(W);
01035         o << field;
01036     }
01037     o.width(G);
01038     o << "";
01039     { 
01040 #ifdef USE_STRSTREAM
01041         std::ostrstream f(field, sizeof field);
01042 #else
01043         std::ostringstream f(field);
01044 #endif
01045         f.width(N);
01046         f << numLevels() << " Level" << s(numLevels()) << std::ends;
01047         o.width(W);
01048         o << field;
01049     }
01050     o.width(G);
01051     o << "";
01052     { 
01053 #ifdef USE_STRSTREAM
01054         std::ostrstream f(field, sizeof field);
01055 #else
01056         std::ostringstream f(field);
01057 #endif
01058         f.width(N);
01059         f << numPackages() << " Package" << s(numPackages()) << std::ends;
01060         o.width(W);
01061         o << field;
01062     }
01063     o << std::endl;
01064     { 
01065 #ifdef USE_STRSTREAM
01066         std::ostrstream f(field, sizeof field);
01067 #else
01068         std::ostringstream f(field);
01069 #endif
01070         f.width(N);
01071         f << ccd() << " CCD" << std::ends;
01072         o.width(W);
01073         o << field;
01074     }
01075     o.width(G);
01076     o << "";
01077     { 
01078 #ifdef USE_STRSTREAM
01079         std::ostrstream f(field, sizeof field);
01080 #else
01081         std::ostringstream f(field);
01082 #endif
01083         f.width(N);
01084         f << acd() << " ACD" << std::ends;
01085         o.width(W);
01086         o << field;
01087     }
01088     o.width(G);
01089     o << "";
01090     { 
01091 #ifdef USE_STRSTREAM
01092         std::ostrstream f(field, sizeof field);
01093 #else
01094         std::ostringstream f(field);
01095 #endif
01096         f.width(N);
01097         f << nccd() << " NCCD" << std::ends;
01098         o.width(W);
01099         o << field;
01100     }
01101     o << std::endl;
01102 
01103     o.setf(iostate);
01104 
01105     o << std::endl;
01106 }
01107 
01108                 // -*-*-*- free operators -*-*-*-
01109  
01110 std::ostream &operator<<(std::ostream& o, const idep_LinkDep& dep) 
01111 {
01112     dep.printAliases(o);
01113     dep.printUnaliases(o);
01114     dep.printCycles(o);
01115     dep.printLevels(o, 1);
01116     dep.printSummary(o);
01117     return o;
01118 }
01119 
01120                 // -*-*-*- idep_AliasIter_i -*-*-*-
01121 
01122 struct idep_AliasIter_i {
01123     idep_AliasTableIter d_iter;
01124 
01125     idep_AliasIter_i(const idep_AliasTable& table);
01126 };
01127 
01128 idep_AliasIter_i::idep_AliasIter_i(const idep_AliasTable& table)
01129 : d_iter(table)
01130 {
01131 }
01132 
01133                 // -*-*-*- idep_AliasIter -*-*-*-
01134 
01135 idep_AliasIter::idep_AliasIter(const idep_LinkDep& dep) 
01136 : d_this(new idep_AliasIter_i(dep.d_this->d_aliases))
01137 {
01138 }
01139 
01140 idep_AliasIter::~idep_AliasIter()
01141 {
01142     delete d_this;
01143 }
01144 
01145 void idep_AliasIter::operator++() 
01146 {
01147     ++d_this->d_iter;
01148 }
01149  
01150 idep_AliasIter::operator const void *() const
01151 {
01152     return d_this->d_iter;
01153 }
01154  
01155 const char *idep_AliasIter::fromName() const
01156 {
01157     return d_this->d_iter.alias();
01158 }
01159 
01160 const char *idep_AliasIter::toName() const
01161 {
01162     return d_this->d_iter.originalName();
01163 }
01164 
01165                 // -*-*-*- idep_UnaliasIter_i -*-*-*-
01166 
01167 struct idep_UnaliasIter_i {
01168     const idep_NameIndexMap& d_array;
01169     int d_index;
01170 
01171     idep_UnaliasIter_i(const idep_NameIndexMap& array);
01172 };
01173 
01174 idep_UnaliasIter_i::idep_UnaliasIter_i(const idep_NameIndexMap& array) 
01175 : d_array(array)
01176 , d_index(0)
01177 {
01178 }
01179 
01180                 // -*-*-*- idep_UnaliasIter -*-*-*-
01181 
01182 idep_UnaliasIter::idep_UnaliasIter(const idep_LinkDep& dep) 
01183 : d_this(new idep_UnaliasIter_i(dep.d_this->d_unaliases))
01184 {
01185 }
01186 
01187 idep_UnaliasIter::~idep_UnaliasIter()
01188 {
01189     delete d_this;
01190 }
01191 
01192 
01193 void idep_UnaliasIter::operator++() 
01194 {
01195     assert (*this);
01196     ++d_this->d_index;
01197 }
01198  
01199 idep_UnaliasIter::operator const void *() const
01200 {
01201     return d_this->d_index < d_this->d_array.length() ? this : 0;
01202 }
01203  
01204 const char *idep_UnaliasIter::operator()() const
01205 {
01206     return d_this->d_array[d_this->d_index];
01207 }
01208 
01209                 // -*-*-*- idep_CycleIter_i -*-*-*-
01210 
01211 struct idep_CycleIter_i {
01212   const idep_LinkDep_i& d_dep;
01213   int d_cycleIndex;
01214   int d_componentIndex;
01215   
01216   idep_CycleIter_i(const idep_LinkDep_i& dep);
01217 };
01218 
01219 idep_CycleIter_i::idep_CycleIter_i(const idep_LinkDep_i& dep)
01220 : d_dep(dep)
01221 , d_cycleIndex(-1)
01222 , d_componentIndex(-1)
01223 {
01224 }
01225 
01226                 // -*-*-*- idep_CycleIter -*-*-*-
01227 
01228 idep_CycleIter::idep_CycleIter(const idep_LinkDep& dep) 
01229 : d_this(new idep_CycleIter_i(*dep.d_this))
01230 {
01231     ++*this;    // set to first cycle
01232 }
01233 
01234 idep_CycleIter::~idep_CycleIter()
01235 {
01236     delete d_this;
01237 }
01238 
01239 void idep_CycleIter::operator++() 
01240 {
01241     assert(*this);
01242     ++d_this->d_cycleIndex;
01243     do {
01244         ++d_this->d_componentIndex;
01245     } 
01246     while (*this && d_this->d_dep.d_cycleIndices_p[d_this->d_dep.d_map_p[
01247                         d_this->d_componentIndex]] != d_this->d_cycleIndex);
01248 }
01249  
01250 idep_CycleIter::operator const void *() const
01251 {
01252     return d_this->d_componentIndex < d_this->d_dep.d_numComponents ? this : 0;
01253 }
01254  
01255 int idep_CycleIter::weight() const
01256 {
01257     return d_this->d_dep.d_weights_p[d_this->d_dep.d_map_p[
01258                                 d_this->d_componentIndex]];
01259 }
01260 
01261 int idep_CycleIter::cycle() const
01262 {
01263     return d_this->d_cycleIndex + 1; // cycle 0 reserved for acyclic components
01264 }
01265 
01266                 // -*-*-*- idep_MemberIter_i -*-*-*-
01267 
01268 struct idep_MemberIter_i {
01269     const idep_LinkDep_i& d_dep;
01270     const int d_cycleIndex;
01271     int d_index;
01272 
01273     idep_MemberIter_i(const idep_CycleIter_i& iter);
01274 };
01275 
01276 idep_MemberIter_i::idep_MemberIter_i(const idep_CycleIter_i& iter) 
01277 : d_dep(iter.d_dep)
01278 , d_cycleIndex(iter.d_cycleIndex)
01279 , d_index(iter.d_componentIndex)
01280 {
01281 }
01282 
01283                 // -*-*-*- idep_MemberIter -*-*-*-
01284 
01285 idep_MemberIter::idep_MemberIter(const idep_CycleIter& iter) 
01286 : d_this(new idep_MemberIter_i(*iter.d_this))
01287 {
01288 }
01289 
01290 idep_MemberIter::~idep_MemberIter()
01291 {
01292     delete d_this;
01293 }
01294 
01295 void idep_MemberIter::operator++() 
01296 {
01297     assert(*this);
01298     do {
01299         ++d_this->d_index;
01300     } 
01301     while (*this && d_this->d_dep.d_cycleIndices_p[d_this->d_dep.d_map_p[
01302                                 d_this->d_index]] != d_this->d_cycleIndex);
01303 }
01304  
01305 idep_MemberIter::operator const void *() const
01306 {
01307     return d_this->d_index < d_this->d_dep.d_numComponents ? this : 0;
01308 }
01309  
01310 const char *idep_MemberIter::operator()() const
01311 {
01312     return (*d_this->d_dep.d_componentNames_p)[d_this->d_dep.d_map_p[
01313                                                         d_this->d_index]];
01314 }
01315 
01316                 // -*-*-*- idep_LevelIter_i -*-*-*-
01317 
01318 struct idep_LevelIter_i {
01319     const idep_LinkDep_i& d_dep;
01320     int d_level;
01321     int d_start;
01322 
01323     idep_LevelIter_i(const idep_LinkDep_i& dep);
01324 };
01325 
01326 idep_LevelIter_i::idep_LevelIter_i(const idep_LinkDep_i& dep)
01327 : d_dep(dep)
01328 , d_level(0)
01329 , d_start(0)
01330 {
01331 }
01332 
01333                 // -*-*-*- idep_LevelIter -*-*-*-
01334 
01335 idep_LevelIter::idep_LevelIter(const idep_LinkDep& dep) 
01336 : d_this(new idep_LevelIter_i(*dep.d_this))
01337 {
01338 }
01339 
01340 idep_LevelIter::~idep_LevelIter()
01341 {
01342     delete d_this;
01343 }
01344 
01345 void idep_LevelIter::operator++() 
01346 {
01347     assert(*this);
01348     d_this->d_start += d_this->d_dep.d_levels_p[d_this->d_level++];
01349 }
01350  
01351 idep_LevelIter::operator const void *() const
01352 {
01353     return d_this->d_level < d_this->d_dep.d_numLevels ? this : 0;
01354 }
01355  
01356 int idep_LevelIter::operator()() const
01357 {
01358     return d_this->d_level;
01359 }
01360 
01361 
01362                 // -*-*-*- idep_ComponentIter_i -*-*-*-
01363 
01364 struct idep_ComponentIter_i {
01365     const idep_LinkDep_i& d_dep;
01366     int d_index;
01367     int d_top;
01368 
01369     idep_ComponentIter_i(const idep_LevelIter_i& iter);
01370 };
01371 
01372 idep_ComponentIter_i::idep_ComponentIter_i(const idep_LevelIter_i& iter)
01373 : d_dep(iter.d_dep)
01374 , d_index(iter.d_start)
01375 , d_top(iter.d_start + iter.d_dep.d_levels_p[iter.d_level])
01376 {
01377 }
01378 
01379                 // -*-*-*- idep_ComponentIter -*-*-*-
01380 
01381 idep_ComponentIter::idep_ComponentIter(const idep_LevelIter& iter) 
01382 : d_this(new idep_ComponentIter_i(*iter.d_this))
01383 {
01384 }
01385 
01386 idep_ComponentIter::~idep_ComponentIter()
01387 {
01388     delete d_this;
01389 }
01390 
01391 void idep_ComponentIter::operator++() 
01392 {
01393     assert(*this);
01394     ++d_this->d_index;
01395 }
01396  
01397 idep_ComponentIter::operator const void *() const
01398 {
01399     return d_this->d_index < d_this->d_top ? this : 0;
01400 }
01401  
01402 const char *idep_ComponentIter::operator()() const
01403 {
01404     return (*d_this->d_dep.d_componentNames_p)[
01405                                 d_this->d_dep.d_map_p[d_this->d_index]];
01406 }
01407 
01408 int idep_ComponentIter::cycle() const
01409 {
01410     return d_this->d_dep.d_cycleIndices_p[
01411                                 d_this->d_dep.d_map_p[d_this->d_index]] + 1;
01412 }
01413 
01414                 // -*-*-*- idep_DependencyIter_i -*-*-*-
01415 
01416 struct idep_DependencyIter_i {
01417     const idep_LinkDep_i& d_dep;
01418     int d_row;
01419     int d_col;
01420 
01421     idep_DependencyIter_i(const idep_ComponentIter_i& iter);
01422 };
01423 
01424 idep_DependencyIter_i::idep_DependencyIter_i(const idep_ComponentIter_i& iter) 
01425 : d_dep(iter.d_dep)
01426 , d_row(iter.d_dep.d_map_p[iter.d_index])
01427 , d_col(-1)
01428 {
01429 }
01430 
01431                 // -*-*-*- idep_DependencyIter -*-*-*-
01432 
01433 idep_DependencyIter::idep_DependencyIter(const idep_ComponentIter& iter) 
01434 : d_this(new idep_DependencyIter_i(*iter.d_this))
01435 {
01436     ++*this;
01437 }
01438 
01439 idep_DependencyIter::~idep_DependencyIter()
01440 {
01441     delete d_this;
01442 }
01443 
01444 
01445 void idep_DependencyIter::operator++() 
01446 {
01447     assert(*this);
01448     do {
01449         ++d_this->d_col;
01450     } 
01451     while (*this &&                             // look in levelized order
01452            !d_this->d_dep.d_dependencies_p->get(d_this->d_row, 
01453                                 d_this->d_dep.d_map_p[d_this->d_col])); 
01454 }
01455  
01456 idep_DependencyIter::operator const void *() const
01457 {
01458     return d_this->d_col < d_this->d_dep.d_numComponents ? this : 0;
01459 }
01460  
01461 const char *idep_DependencyIter::operator()() const
01462 {
01463     return (*d_this->d_dep.d_componentNames_p)[ // levelized order
01464                                 d_this->d_dep.d_map_p[d_this->d_col]];
01465 }
01466 
01467 int idep_DependencyIter::level() const
01468 {
01469     return d_this->d_dep.d_levelNumbers_p[      // levelized order
01470                                 d_this->d_dep.d_map_p[d_this->d_col]];
01471 }
01472 
01473 int idep_DependencyIter::cycle() const
01474 {
01475     return d_this->d_dep.d_cycleIndices_p[      // levelized order
01476                                 d_this->d_dep.d_map_p[d_this->d_col]] + 1;
01477 }
01478 
01479 
01480 

Generated on Fri Mar 28 15:33:09 2008 for loon by  doxygen 1.3.9.1