Fossil SCM
Pull in recent graph layout changes.
Commit
0551ff817897b267c22632f6684fa16b13c47c48
Parent
64541535d92a6fd…
1 file changed
+66
-29
+66
-29
| --- src/graph.c | ||
| +++ src/graph.c | ||
| @@ -43,11 +43,12 @@ | ||
| 43 | 43 | |
| 44 | 44 | GraphRow *pNext; /* Next row down in the list of all rows */ |
| 45 | 45 | GraphRow *pPrev; /* Previous row */ |
| 46 | 46 | |
| 47 | 47 | int idx; /* Row index. First is 1. 0 used for "none" */ |
| 48 | - int isLeaf; /* True if no direct child nodes */ | |
| 48 | + u8 isLeaf; /* True if no direct child nodes */ | |
| 49 | + u8 isDup; /* True if this is duplicate of a prior entry */ | |
| 49 | 50 | int iRail; /* Which rail this check-in appears on. 0-based.*/ |
| 50 | 51 | int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */ |
| 51 | 52 | int bDescender; /* Raiser from bottom of graph to here. */ |
| 52 | 53 | u32 mergeIn; /* Merge in from other rails */ |
| 53 | 54 | int mergeOut; /* Merge out to this rail */ |
| @@ -108,20 +109,23 @@ | ||
| 108 | 109 | free(p); |
| 109 | 110 | } |
| 110 | 111 | |
| 111 | 112 | /* |
| 112 | 113 | ** Insert a row into the hash table. If there is already another |
| 113 | -** row with the same rid, the other row is replaced. | |
| 114 | +** row with the same rid, overwrite the prior entry if the overwrite | |
| 115 | +** flag is set. | |
| 114 | 116 | */ |
| 115 | -static void hashInsert(GraphContext *p, GraphRow *pRow){ | |
| 117 | +static void hashInsert(GraphContext *p, GraphRow *pRow, int overwrite){ | |
| 116 | 118 | int h; |
| 117 | 119 | h = pRow->rid % p->nHash; |
| 118 | 120 | while( p->apHash[h] && p->apHash[h]->rid!=pRow->rid ){ |
| 119 | 121 | h++; |
| 120 | 122 | if( h>=p->nHash ) h = 0; |
| 121 | 123 | } |
| 122 | - p->apHash[h] = pRow; | |
| 124 | + if( p->apHash[h]==0 || overwrite ){ | |
| 125 | + p->apHash[h] = pRow; | |
| 126 | + } | |
| 123 | 127 | } |
| 124 | 128 | |
| 125 | 129 | /* |
| 126 | 130 | ** Look up the row with rid. |
| 127 | 131 | */ |
| @@ -201,11 +205,13 @@ | ||
| 201 | 205 | pRow = pRow->pNext; |
| 202 | 206 | } |
| 203 | 207 | for(i=0; i<32; i++){ |
| 204 | 208 | if( (inUseMask & (1<<i))==0 ){ |
| 205 | 209 | int dist; |
| 206 | - if( iNearto<=0 ) return i; | |
| 210 | + if( iNearto<=0 ){ | |
| 211 | + return i; | |
| 212 | + } | |
| 207 | 213 | dist = i - iNearto; |
| 208 | 214 | if( dist<0 ) dist = -dist; |
| 209 | 215 | if( dist<iBestDist ){ |
| 210 | 216 | iBestDist = dist; |
| 211 | 217 | iBest = i; |
| @@ -218,14 +224,15 @@ | ||
| 218 | 224 | |
| 219 | 225 | /* |
| 220 | 226 | ** Compute the complete graph |
| 221 | 227 | */ |
| 222 | 228 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 223 | - GraphRow *pRow, *pDesc; | |
| 229 | + GraphRow *pRow, *pDesc, *pDup, *pLoop; | |
| 224 | 230 | int i; |
| 225 | 231 | u32 mask; |
| 226 | 232 | u32 inUse; |
| 233 | + int hasDup = 0; /* True if one or more isDup entries */ | |
| 227 | 234 | |
| 228 | 235 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 229 | 236 | |
| 230 | 237 | /* Initialize all rows */ |
| 231 | 238 | p->nHash = p->nRow*2 + 1; |
| @@ -232,11 +239,15 @@ | ||
| 232 | 239 | p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
| 233 | 240 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 234 | 241 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 235 | 242 | pRow->iRail = -1; |
| 236 | 243 | pRow->mergeOut = -1; |
| 237 | - hashInsert(p, pRow); | |
| 244 | + if( (pDup = hashFind(p, pRow->rid))!=0 ){ | |
| 245 | + hasDup = 1; | |
| 246 | + pDup->isDup = 1; | |
| 247 | + } | |
| 248 | + hashInsert(p, pRow, 1); | |
| 238 | 249 | } |
| 239 | 250 | p->mxRail = -1; |
| 240 | 251 | |
| 241 | 252 | /* Purge merge-parents that are out-of-graph |
| 242 | 253 | */ |
| @@ -248,18 +259,19 @@ | ||
| 248 | 259 | } |
| 249 | 260 | } |
| 250 | 261 | } |
| 251 | 262 | |
| 252 | 263 | /* Figure out which nodes have no direct children (children on |
| 253 | - ** the same rail). Mark such nodes is isLeaf. | |
| 264 | + ** the same rail). Mark such nodes as isLeaf. | |
| 254 | 265 | */ |
| 255 | 266 | memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); |
| 256 | 267 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; |
| 257 | 268 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 258 | 269 | GraphRow *pParent; |
| 259 | - hashInsert(p, pRow); | |
| 260 | - if( pRow->nParent>0 | |
| 270 | + hashInsert(p, pRow, 0); | |
| 271 | + if( !pRow->isDup | |
| 272 | + && pRow->nParent>0 | |
| 261 | 273 | && (pParent = hashFind(p, pRow->aParent[0]))!=0 |
| 262 | 274 | && pRow->zBranch==pParent->zBranch |
| 263 | 275 | ){ |
| 264 | 276 | pParent->isLeaf = 0; |
| 265 | 277 | } |
| @@ -294,46 +306,49 @@ | ||
| 294 | 306 | */ |
| 295 | 307 | inUse = (1<<(p->mxRail+1))-1; |
| 296 | 308 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 297 | 309 | int parentRid; |
| 298 | 310 | if( pRow->iRail>=0 ) continue; |
| 299 | - assert( pRow->nParent>0 ); | |
| 300 | - parentRid = pRow->aParent[0]; | |
| 301 | - for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; pDesc=pDesc->pNext){} | |
| 302 | - if( pDesc==0 ){ | |
| 303 | - /* Time skew */ | |
| 304 | - pRow->iRail = ++p->mxRail; | |
| 305 | - pRow->railInUse = 1<<pRow->iRail; | |
| 306 | - continue; | |
| 307 | - } | |
| 308 | - if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ | |
| 309 | - pRow->iRail = pDesc->iRail; | |
| 311 | + if( pRow->isDup ){ | |
| 312 | + pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); | |
| 313 | + pDesc = pRow; | |
| 310 | 314 | }else{ |
| 311 | - pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); | |
| 315 | + assert( pRow->nParent>0 ); | |
| 316 | + parentRid = pRow->aParent[0]; | |
| 317 | + pDesc = hashFind(p, parentRid); | |
| 318 | + if( pDesc==0 ){ | |
| 319 | + /* Time skew */ | |
| 320 | + pRow->iRail = ++p->mxRail; | |
| 321 | + pRow->railInUse = 1<<pRow->iRail; | |
| 322 | + continue; | |
| 323 | + } | |
| 324 | + if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ | |
| 325 | + pRow->iRail = pDesc->iRail; | |
| 326 | + }else{ | |
| 327 | + pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); | |
| 328 | + } | |
| 329 | + pDesc->aiRaiser[pRow->iRail] = pRow->idx; | |
| 312 | 330 | } |
| 313 | - pDesc->aiRaiser[pRow->iRail] = pRow->idx; | |
| 314 | 331 | mask = 1<<pRow->iRail; |
| 315 | 332 | if( pRow->isLeaf ){ |
| 316 | 333 | inUse &= ~mask; |
| 317 | 334 | }else{ |
| 318 | 335 | inUse |= mask; |
| 319 | 336 | } |
| 320 | - for(pDesc = pRow; ; pDesc=pDesc->pNext){ | |
| 321 | - assert( pDesc!=0 ); | |
| 322 | - pDesc->railInUse |= mask; | |
| 323 | - if( pDesc->rid==parentRid ) break; | |
| 337 | + for(pLoop=pRow; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ | |
| 338 | + pLoop->railInUse |= mask; | |
| 324 | 339 | } |
| 340 | + pDesc->railInUse |= mask; | |
| 325 | 341 | } |
| 326 | 342 | |
| 327 | 343 | /* |
| 328 | 344 | ** Insert merge rails and merge arrows |
| 329 | 345 | */ |
| 330 | 346 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 331 | 347 | for(i=1; i<pRow->nParent; i++){ |
| 332 | 348 | int parentRid = pRow->aParent[i]; |
| 333 | - for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; | |
| 334 | - pDesc=pDesc->pNext){} | |
| 349 | + pDesc = hashFind(p, parentRid); | |
| 335 | 350 | if( pDesc==0 ) continue; |
| 336 | 351 | if( pDesc->mergeOut<0 ){ |
| 337 | 352 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 338 | 353 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 339 | 354 | pDesc->mergeUpto = pRow->idx; |
| @@ -341,10 +356,32 @@ | ||
| 341 | 356 | pDesc->railInUse |= mask; |
| 342 | 357 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 343 | 358 | pDesc=pDesc->pNext){ |
| 344 | 359 | pDesc->railInUse |= mask; |
| 345 | 360 | } |
| 361 | + } | |
| 362 | + pRow->mergeIn |= 1<<pDesc->mergeOut; | |
| 363 | + } | |
| 364 | + } | |
| 365 | + | |
| 366 | + /* | |
| 367 | + ** Insert merge rails from primaries to duplicates. | |
| 368 | + */ | |
| 369 | + if( hasDup ){ | |
| 370 | + for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 371 | + if( !pRow->isDup ) continue; | |
| 372 | + pDesc = hashFind(p, pRow->rid); | |
| 373 | + assert( pDesc!=0 && pDesc!=pRow ); | |
| 374 | + if( pDesc->mergeOut<0 ){ | |
| 375 | + int iTarget = (pRow->iRail + pDesc->iRail)/2; | |
| 376 | + pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); | |
| 377 | + pDesc->mergeUpto = pRow->idx; | |
| 378 | + mask = 1<<pDesc->mergeOut; | |
| 379 | + pDesc->railInUse |= mask; | |
| 380 | + for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ | |
| 381 | + pLoop->railInUse |= mask; | |
| 382 | + } | |
| 346 | 383 | } |
| 347 | 384 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 348 | 385 | } |
| 349 | 386 | } |
| 350 | 387 | |
| 351 | 388 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -43,11 +43,12 @@ | |
| 43 | |
| 44 | GraphRow *pNext; /* Next row down in the list of all rows */ |
| 45 | GraphRow *pPrev; /* Previous row */ |
| 46 | |
| 47 | int idx; /* Row index. First is 1. 0 used for "none" */ |
| 48 | int isLeaf; /* True if no direct child nodes */ |
| 49 | int iRail; /* Which rail this check-in appears on. 0-based.*/ |
| 50 | int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */ |
| 51 | int bDescender; /* Raiser from bottom of graph to here. */ |
| 52 | u32 mergeIn; /* Merge in from other rails */ |
| 53 | int mergeOut; /* Merge out to this rail */ |
| @@ -108,20 +109,23 @@ | |
| 108 | free(p); |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** Insert a row into the hash table. If there is already another |
| 113 | ** row with the same rid, the other row is replaced. |
| 114 | */ |
| 115 | static void hashInsert(GraphContext *p, GraphRow *pRow){ |
| 116 | int h; |
| 117 | h = pRow->rid % p->nHash; |
| 118 | while( p->apHash[h] && p->apHash[h]->rid!=pRow->rid ){ |
| 119 | h++; |
| 120 | if( h>=p->nHash ) h = 0; |
| 121 | } |
| 122 | p->apHash[h] = pRow; |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | ** Look up the row with rid. |
| 127 | */ |
| @@ -201,11 +205,13 @@ | |
| 201 | pRow = pRow->pNext; |
| 202 | } |
| 203 | for(i=0; i<32; i++){ |
| 204 | if( (inUseMask & (1<<i))==0 ){ |
| 205 | int dist; |
| 206 | if( iNearto<=0 ) return i; |
| 207 | dist = i - iNearto; |
| 208 | if( dist<0 ) dist = -dist; |
| 209 | if( dist<iBestDist ){ |
| 210 | iBestDist = dist; |
| 211 | iBest = i; |
| @@ -218,14 +224,15 @@ | |
| 218 | |
| 219 | /* |
| 220 | ** Compute the complete graph |
| 221 | */ |
| 222 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 223 | GraphRow *pRow, *pDesc; |
| 224 | int i; |
| 225 | u32 mask; |
| 226 | u32 inUse; |
| 227 | |
| 228 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 229 | |
| 230 | /* Initialize all rows */ |
| 231 | p->nHash = p->nRow*2 + 1; |
| @@ -232,11 +239,15 @@ | |
| 232 | p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
| 233 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 234 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 235 | pRow->iRail = -1; |
| 236 | pRow->mergeOut = -1; |
| 237 | hashInsert(p, pRow); |
| 238 | } |
| 239 | p->mxRail = -1; |
| 240 | |
| 241 | /* Purge merge-parents that are out-of-graph |
| 242 | */ |
| @@ -248,18 +259,19 @@ | |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | /* Figure out which nodes have no direct children (children on |
| 253 | ** the same rail). Mark such nodes is isLeaf. |
| 254 | */ |
| 255 | memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); |
| 256 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; |
| 257 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 258 | GraphRow *pParent; |
| 259 | hashInsert(p, pRow); |
| 260 | if( pRow->nParent>0 |
| 261 | && (pParent = hashFind(p, pRow->aParent[0]))!=0 |
| 262 | && pRow->zBranch==pParent->zBranch |
| 263 | ){ |
| 264 | pParent->isLeaf = 0; |
| 265 | } |
| @@ -294,46 +306,49 @@ | |
| 294 | */ |
| 295 | inUse = (1<<(p->mxRail+1))-1; |
| 296 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 297 | int parentRid; |
| 298 | if( pRow->iRail>=0 ) continue; |
| 299 | assert( pRow->nParent>0 ); |
| 300 | parentRid = pRow->aParent[0]; |
| 301 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; pDesc=pDesc->pNext){} |
| 302 | if( pDesc==0 ){ |
| 303 | /* Time skew */ |
| 304 | pRow->iRail = ++p->mxRail; |
| 305 | pRow->railInUse = 1<<pRow->iRail; |
| 306 | continue; |
| 307 | } |
| 308 | if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ |
| 309 | pRow->iRail = pDesc->iRail; |
| 310 | }else{ |
| 311 | pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); |
| 312 | } |
| 313 | pDesc->aiRaiser[pRow->iRail] = pRow->idx; |
| 314 | mask = 1<<pRow->iRail; |
| 315 | if( pRow->isLeaf ){ |
| 316 | inUse &= ~mask; |
| 317 | }else{ |
| 318 | inUse |= mask; |
| 319 | } |
| 320 | for(pDesc = pRow; ; pDesc=pDesc->pNext){ |
| 321 | assert( pDesc!=0 ); |
| 322 | pDesc->railInUse |= mask; |
| 323 | if( pDesc->rid==parentRid ) break; |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | /* |
| 328 | ** Insert merge rails and merge arrows |
| 329 | */ |
| 330 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 331 | for(i=1; i<pRow->nParent; i++){ |
| 332 | int parentRid = pRow->aParent[i]; |
| 333 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 334 | pDesc=pDesc->pNext){} |
| 335 | if( pDesc==0 ) continue; |
| 336 | if( pDesc->mergeOut<0 ){ |
| 337 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 338 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 339 | pDesc->mergeUpto = pRow->idx; |
| @@ -341,10 +356,32 @@ | |
| 341 | pDesc->railInUse |= mask; |
| 342 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 343 | pDesc=pDesc->pNext){ |
| 344 | pDesc->railInUse |= mask; |
| 345 | } |
| 346 | } |
| 347 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -43,11 +43,12 @@ | |
| 43 | |
| 44 | GraphRow *pNext; /* Next row down in the list of all rows */ |
| 45 | GraphRow *pPrev; /* Previous row */ |
| 46 | |
| 47 | int idx; /* Row index. First is 1. 0 used for "none" */ |
| 48 | u8 isLeaf; /* True if no direct child nodes */ |
| 49 | u8 isDup; /* True if this is duplicate of a prior entry */ |
| 50 | int iRail; /* Which rail this check-in appears on. 0-based.*/ |
| 51 | int aiRaiser[GR_MAX_RAIL]; /* Raisers from this node to a higher row. */ |
| 52 | int bDescender; /* Raiser from bottom of graph to here. */ |
| 53 | u32 mergeIn; /* Merge in from other rails */ |
| 54 | int mergeOut; /* Merge out to this rail */ |
| @@ -108,20 +109,23 @@ | |
| 109 | free(p); |
| 110 | } |
| 111 | |
| 112 | /* |
| 113 | ** Insert a row into the hash table. If there is already another |
| 114 | ** row with the same rid, overwrite the prior entry if the overwrite |
| 115 | ** flag is set. |
| 116 | */ |
| 117 | static void hashInsert(GraphContext *p, GraphRow *pRow, int overwrite){ |
| 118 | int h; |
| 119 | h = pRow->rid % p->nHash; |
| 120 | while( p->apHash[h] && p->apHash[h]->rid!=pRow->rid ){ |
| 121 | h++; |
| 122 | if( h>=p->nHash ) h = 0; |
| 123 | } |
| 124 | if( p->apHash[h]==0 || overwrite ){ |
| 125 | p->apHash[h] = pRow; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /* |
| 130 | ** Look up the row with rid. |
| 131 | */ |
| @@ -201,11 +205,13 @@ | |
| 205 | pRow = pRow->pNext; |
| 206 | } |
| 207 | for(i=0; i<32; i++){ |
| 208 | if( (inUseMask & (1<<i))==0 ){ |
| 209 | int dist; |
| 210 | if( iNearto<=0 ){ |
| 211 | return i; |
| 212 | } |
| 213 | dist = i - iNearto; |
| 214 | if( dist<0 ) dist = -dist; |
| 215 | if( dist<iBestDist ){ |
| 216 | iBestDist = dist; |
| 217 | iBest = i; |
| @@ -218,14 +224,15 @@ | |
| 224 | |
| 225 | /* |
| 226 | ** Compute the complete graph |
| 227 | */ |
| 228 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 229 | GraphRow *pRow, *pDesc, *pDup, *pLoop; |
| 230 | int i; |
| 231 | u32 mask; |
| 232 | u32 inUse; |
| 233 | int hasDup = 0; /* True if one or more isDup entries */ |
| 234 | |
| 235 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 236 | |
| 237 | /* Initialize all rows */ |
| 238 | p->nHash = p->nRow*2 + 1; |
| @@ -232,11 +239,15 @@ | |
| 239 | p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
| 240 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 241 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 242 | pRow->iRail = -1; |
| 243 | pRow->mergeOut = -1; |
| 244 | if( (pDup = hashFind(p, pRow->rid))!=0 ){ |
| 245 | hasDup = 1; |
| 246 | pDup->isDup = 1; |
| 247 | } |
| 248 | hashInsert(p, pRow, 1); |
| 249 | } |
| 250 | p->mxRail = -1; |
| 251 | |
| 252 | /* Purge merge-parents that are out-of-graph |
| 253 | */ |
| @@ -248,18 +259,19 @@ | |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | /* Figure out which nodes have no direct children (children on |
| 264 | ** the same rail). Mark such nodes as isLeaf. |
| 265 | */ |
| 266 | memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); |
| 267 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; |
| 268 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 269 | GraphRow *pParent; |
| 270 | hashInsert(p, pRow, 0); |
| 271 | if( !pRow->isDup |
| 272 | && pRow->nParent>0 |
| 273 | && (pParent = hashFind(p, pRow->aParent[0]))!=0 |
| 274 | && pRow->zBranch==pParent->zBranch |
| 275 | ){ |
| 276 | pParent->isLeaf = 0; |
| 277 | } |
| @@ -294,46 +306,49 @@ | |
| 306 | */ |
| 307 | inUse = (1<<(p->mxRail+1))-1; |
| 308 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 309 | int parentRid; |
| 310 | if( pRow->iRail>=0 ) continue; |
| 311 | if( pRow->isDup ){ |
| 312 | pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); |
| 313 | pDesc = pRow; |
| 314 | }else{ |
| 315 | assert( pRow->nParent>0 ); |
| 316 | parentRid = pRow->aParent[0]; |
| 317 | pDesc = hashFind(p, parentRid); |
| 318 | if( pDesc==0 ){ |
| 319 | /* Time skew */ |
| 320 | pRow->iRail = ++p->mxRail; |
| 321 | pRow->railInUse = 1<<pRow->iRail; |
| 322 | continue; |
| 323 | } |
| 324 | if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ |
| 325 | pRow->iRail = pDesc->iRail; |
| 326 | }else{ |
| 327 | pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); |
| 328 | } |
| 329 | pDesc->aiRaiser[pRow->iRail] = pRow->idx; |
| 330 | } |
| 331 | mask = 1<<pRow->iRail; |
| 332 | if( pRow->isLeaf ){ |
| 333 | inUse &= ~mask; |
| 334 | }else{ |
| 335 | inUse |= mask; |
| 336 | } |
| 337 | for(pLoop=pRow; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ |
| 338 | pLoop->railInUse |= mask; |
| 339 | } |
| 340 | pDesc->railInUse |= mask; |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | ** Insert merge rails and merge arrows |
| 345 | */ |
| 346 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 347 | for(i=1; i<pRow->nParent; i++){ |
| 348 | int parentRid = pRow->aParent[i]; |
| 349 | pDesc = hashFind(p, parentRid); |
| 350 | if( pDesc==0 ) continue; |
| 351 | if( pDesc->mergeOut<0 ){ |
| 352 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 353 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 354 | pDesc->mergeUpto = pRow->idx; |
| @@ -341,10 +356,32 @@ | |
| 356 | pDesc->railInUse |= mask; |
| 357 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 358 | pDesc=pDesc->pNext){ |
| 359 | pDesc->railInUse |= mask; |
| 360 | } |
| 361 | } |
| 362 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | /* |
| 367 | ** Insert merge rails from primaries to duplicates. |
| 368 | */ |
| 369 | if( hasDup ){ |
| 370 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 371 | if( !pRow->isDup ) continue; |
| 372 | pDesc = hashFind(p, pRow->rid); |
| 373 | assert( pDesc!=0 && pDesc!=pRow ); |
| 374 | if( pDesc->mergeOut<0 ){ |
| 375 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 376 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 377 | pDesc->mergeUpto = pRow->idx; |
| 378 | mask = 1<<pDesc->mergeOut; |
| 379 | pDesc->railInUse |= mask; |
| 380 | for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ |
| 381 | pLoop->railInUse |= mask; |
| 382 | } |
| 383 | } |
| 384 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 385 | } |
| 386 | } |
| 387 | |
| 388 |