Expel Tarjan from his nest
authorPanu Matilainen <pmatilai@redhat.com>
Fri, 17 Sep 2010 06:03:34 +0000 (09:03 +0300)
committerPanu Matilainen <pmatilai@redhat.com>
Fri, 17 Sep 2010 06:03:34 +0000 (09:03 +0300)
- Nested functions are a gcc-extension and very non-portable. Refactor
  to eliminate the nesting by passing the "global" variables via
  a struct from detectSCCs().

lib/order.c

index 7e77834..386233c 100644 (file)
@@ -305,100 +305,107 @@ static void addQ(tsortInfo p, tsortInfo * qp, tsortInfo * rp,
     }
 }
 
-/* Search for SCCs and return an array last entry has a .size of 0 */
-static scc detectSCCs(tsortInfo orderInfo, int nelem, int debugloops)
-{
-    int index = 0;                /* DFS node number counter */
-    tsortInfo stack[nelem];  /* An empty stack of nodes */
-    int stackcnt = 0;
-
-    int sccCnt = 2;
-    scc SCCs = xcalloc(nelem+3, sizeof(struct scc_s));
-
-    auto void tarjan(tsortInfo tsi);
-
-    void tarjan(tsortInfo tsi) {
-       tsortInfo tsi_q;
-       relation rel;
-
-        /* use negative index numbers */
-       index--;
-       /* Set the depth index for p */
-       tsi->tsi_SccIdx = index;
-       tsi->tsi_SccLowlink = index;
-
-       stack[stackcnt++] = tsi;                   /* Push p on the stack */
-       for (rel=tsi->tsi_relations; rel != NULL; rel=rel->rel_next) {
-           /* Consider successors of p */
-           tsi_q = rel->rel_suc;
-           if (tsi_q->tsi_SccIdx > 0)
-               /* Ignore already found SCCs */
-               continue;
-           if (tsi_q->tsi_SccIdx == 0){
-               /* Was successor q not yet visited? */
-               tarjan(tsi_q);                       /* Recurse */
-               /* negative index numers: use max as it is closer to 0 */
-               tsi->tsi_SccLowlink = (
-                   tsi->tsi_SccLowlink > tsi_q->tsi_SccLowlink
-                   ? tsi->tsi_SccLowlink : tsi_q->tsi_SccLowlink);
-           } else {
-               tsi->tsi_SccLowlink = (
-                   tsi->tsi_SccLowlink > tsi_q->tsi_SccIdx
-                   ? tsi->tsi_SccLowlink : tsi_q->tsi_SccIdx);
-           }
+typedef struct sccData_s {
+    int index;                 /* DFS node number counter */
+    tsortInfo *stack;          /* Stack of nodes */
+    int stackcnt;              /* Stack top counter */
+    scc SCCs;                  /* Array of SCC's found */
+    int sccCnt;                        /* Number of SCC's found */
+} * sccData;
+
+static void tarjan(sccData sd, tsortInfo tsi) {
+    tsortInfo tsi_q;
+    relation rel;
+
+    /* use negative index numbers */
+    sd->index--;
+    /* Set the depth index for p */
+    tsi->tsi_SccIdx = sd->index;
+    tsi->tsi_SccLowlink = sd->index;
+
+    sd->stack[sd->stackcnt++] = tsi;                   /* Push p on the stack */
+    for (rel=tsi->tsi_relations; rel != NULL; rel=rel->rel_next) {
+       /* Consider successors of p */
+       tsi_q = rel->rel_suc;
+       if (tsi_q->tsi_SccIdx > 0)
+           /* Ignore already found SCCs */
+           continue;
+       if (tsi_q->tsi_SccIdx == 0){
+           /* Was successor q not yet visited? */
+           tarjan(sd, tsi_q);                       /* Recurse */
+           /* negative index numers: use max as it is closer to 0 */
+           tsi->tsi_SccLowlink = (
+               tsi->tsi_SccLowlink > tsi_q->tsi_SccLowlink
+               ? tsi->tsi_SccLowlink : tsi_q->tsi_SccLowlink);
+       } else {
+           tsi->tsi_SccLowlink = (
+               tsi->tsi_SccLowlink > tsi_q->tsi_SccIdx
+               ? tsi->tsi_SccLowlink : tsi_q->tsi_SccIdx);
        }
+    }
 
-       if (tsi->tsi_SccLowlink == tsi->tsi_SccIdx) {
-           /* v is the root of an SCC? */
-           if (stack[stackcnt-1] == tsi) {
-               /* ignore trivial SCCs */
-               tsi_q = stack[--stackcnt];
-               tsi_q->tsi_SccIdx = 1;
-           } else {
-               int stackIdx = stackcnt;
-               do {
-                   tsi_q = stack[--stackIdx];
-                   tsi_q->tsi_SccIdx = sccCnt;
-               } while (tsi_q != tsi);
-
-               stackIdx = stackcnt;
-               do {
-                   tsi_q = stack[--stackIdx];
-                   /* Calculate count for the SCC */
-                   SCCs[sccCnt].count += tsi_q->tsi_count;
-                   /* Subtract internal relations */
-                   for (rel=tsi_q->tsi_relations; rel != NULL;
-                                                       rel=rel->rel_next) {
-                       if (rel->rel_suc != tsi_q &&
-                               rel->rel_suc->tsi_SccIdx == sccCnt)
-                           SCCs[sccCnt].count--;
-                   }
-               } while (tsi_q != tsi);
-               SCCs[sccCnt].size = stackcnt - stackIdx;
-               /* copy members */
-               SCCs[sccCnt].members = xcalloc(SCCs[sccCnt].size,
-                                              sizeof(tsortInfo));
-               memcpy(SCCs[sccCnt].members, stack + stackIdx,
-                      SCCs[sccCnt].size * sizeof(tsortInfo));
-               stackcnt = stackIdx;
-               sccCnt++;
-           }
+    if (tsi->tsi_SccLowlink == tsi->tsi_SccIdx) {
+       /* v is the root of an SCC? */
+       if (sd->stack[sd->stackcnt-1] == tsi) {
+           /* ignore trivial SCCs */
+           tsi_q = sd->stack[--sd->stackcnt];
+           tsi_q->tsi_SccIdx = 1;
+       } else {
+           int stackIdx = sd->stackcnt;
+           do {
+               tsi_q = sd->stack[--stackIdx];
+               tsi_q->tsi_SccIdx = sd->sccCnt;
+           } while (tsi_q != tsi);
+
+           stackIdx = sd->stackcnt;
+           do {
+               tsi_q = sd->stack[--stackIdx];
+               /* Calculate count for the SCC */
+               sd->SCCs[sd->sccCnt].count += tsi_q->tsi_count;
+               /* Subtract internal relations */
+               for (rel=tsi_q->tsi_relations; rel != NULL;
+                                                   rel=rel->rel_next) {
+                   if (rel->rel_suc != tsi_q &&
+                           rel->rel_suc->tsi_SccIdx == sd->sccCnt)
+                       sd->SCCs[sd->sccCnt].count--;
+               }
+           } while (tsi_q != tsi);
+           sd->SCCs[sd->sccCnt].size = sd->stackcnt - stackIdx;
+           /* copy members */
+           sd->SCCs[sd->sccCnt].members = xcalloc(sd->SCCs[sd->sccCnt].size,
+                                          sizeof(tsortInfo));
+           memcpy(sd->SCCs[sd->sccCnt].members, sd->stack + stackIdx,
+                  sd->SCCs[sd->sccCnt].size * sizeof(tsortInfo));
+           sd->stackcnt = stackIdx;
+           sd->sccCnt++;
        }
     }
+}
+
+/* Search for SCCs and return an array last entry has a .size of 0 */
+static scc detectSCCs(tsortInfo orderInfo, int nelem, int debugloops)
+{
+    /* Set up data structures needed for the tarjan algorithm */
+    scc SCCs = xcalloc(nelem+3, sizeof(*SCCs));
+    tsortInfo *stack = xcalloc(nelem, sizeof(*stack));
+    struct sccData_s sd = { 0, stack, 0, SCCs, 2 };
 
     for (int i = 0; i < nelem; i++) {
        tsortInfo tsi = &orderInfo[i];
        /* Start a DFS at each node */
        if (tsi->tsi_SccIdx == 0)
-           tarjan(tsi);
+           tarjan(&sd, tsi);
     }
 
-    SCCs = xrealloc(SCCs, (sccCnt+1)*sizeof(struct scc_s));
+    free(stack);
+
+    SCCs = xrealloc(SCCs, (sd.sccCnt+1)*sizeof(struct scc_s));
+
     /* Debug output */
-    if (sccCnt > 2) {
+    if (sd.sccCnt > 2) {
        int msglvl = debugloops ?  RPMLOG_WARNING : RPMLOG_DEBUG;
-       rpmlog(msglvl, "%i Strongly Connected Components\n", sccCnt-2);
-       for (int i = 2; i < sccCnt; i++) {
+       rpmlog(msglvl, "%i Strongly Connected Components\n", sd.sccCnt-2);
+       for (int i = 2; i < sd.sccCnt; i++) {
            rpmlog(msglvl, "SCC #%i: requires %i packages\n",
                   i, SCCs[i].count);
            /* loop over members */