Fossil SCM
Tweaks to the graph layout algorithm to try to get better graphs for individual file histories.
Commit
1d2608b7f4d748632ab0068f51e81e7b33bee058
Parent
251fd001a8c6e7a…
1 file changed
+15
-8
+15
-8
| --- 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 | */ |
| @@ -218,11 +222,11 @@ | ||
| 218 | 222 | |
| 219 | 223 | /* |
| 220 | 224 | ** Compute the complete graph |
| 221 | 225 | */ |
| 222 | 226 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 223 | - GraphRow *pRow, *pDesc; | |
| 227 | + GraphRow *pRow, *pDesc, *pDup; | |
| 224 | 228 | int i; |
| 225 | 229 | u32 mask; |
| 226 | 230 | u32 inUse; |
| 227 | 231 | |
| 228 | 232 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| @@ -232,11 +236,14 @@ | ||
| 232 | 236 | p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
| 233 | 237 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 234 | 238 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 235 | 239 | pRow->iRail = -1; |
| 236 | 240 | pRow->mergeOut = -1; |
| 237 | - hashInsert(p, pRow); | |
| 241 | + if( (pDup = hashFind(p, pRow->rid))!=0 ){ | |
| 242 | + pDup->isDup = 1; | |
| 243 | + } | |
| 244 | + hashInsert(p, pRow, 1); | |
| 238 | 245 | } |
| 239 | 246 | p->mxRail = -1; |
| 240 | 247 | |
| 241 | 248 | /* Purge merge-parents that are out-of-graph |
| 242 | 249 | */ |
| @@ -254,11 +261,11 @@ | ||
| 254 | 261 | */ |
| 255 | 262 | memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); |
| 256 | 263 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; |
| 257 | 264 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 258 | 265 | GraphRow *pParent; |
| 259 | - hashInsert(p, pRow); | |
| 266 | + hashInsert(p, pRow, 0); | |
| 260 | 267 | if( pRow->nParent>0 |
| 261 | 268 | && (pParent = hashFind(p, pRow->aParent[0]))!=0 |
| 262 | 269 | && pRow->zBranch==pParent->zBranch |
| 263 | 270 | ){ |
| 264 | 271 | pParent->isLeaf = 0; |
| @@ -296,11 +303,11 @@ | ||
| 296 | 303 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 297 | 304 | int parentRid; |
| 298 | 305 | if( pRow->iRail>=0 ) continue; |
| 299 | 306 | assert( pRow->nParent>0 ); |
| 300 | 307 | parentRid = pRow->aParent[0]; |
| 301 | - for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; pDesc=pDesc->pNext){} | |
| 308 | + pDesc = hashFind(p, parentRid); | |
| 302 | 309 | if( pDesc==0 ){ |
| 303 | 310 | /* Time skew */ |
| 304 | 311 | pRow->iRail = ++p->mxRail; |
| 305 | 312 | pRow->railInUse = 1<<pRow->iRail; |
| 306 | 313 | continue; |
| 307 | 314 |
| --- 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 | */ |
| @@ -218,11 +222,11 @@ | |
| 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; |
| @@ -232,11 +236,14 @@ | |
| 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 | */ |
| @@ -254,11 +261,11 @@ | |
| 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; |
| @@ -296,11 +303,11 @@ | |
| 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 |
| --- 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 | */ |
| @@ -218,11 +222,11 @@ | |
| 222 | |
| 223 | /* |
| 224 | ** Compute the complete graph |
| 225 | */ |
| 226 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 227 | GraphRow *pRow, *pDesc, *pDup; |
| 228 | int i; |
| 229 | u32 mask; |
| 230 | u32 inUse; |
| 231 | |
| 232 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| @@ -232,11 +236,14 @@ | |
| 236 | p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash ); |
| 237 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 238 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 239 | pRow->iRail = -1; |
| 240 | pRow->mergeOut = -1; |
| 241 | if( (pDup = hashFind(p, pRow->rid))!=0 ){ |
| 242 | pDup->isDup = 1; |
| 243 | } |
| 244 | hashInsert(p, pRow, 1); |
| 245 | } |
| 246 | p->mxRail = -1; |
| 247 | |
| 248 | /* Purge merge-parents that are out-of-graph |
| 249 | */ |
| @@ -254,11 +261,11 @@ | |
| 261 | */ |
| 262 | memset(p->apHash, 0, sizeof(p->apHash[0])*p->nHash); |
| 263 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev) pRow->isLeaf = 1; |
| 264 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 265 | GraphRow *pParent; |
| 266 | hashInsert(p, pRow, 0); |
| 267 | if( pRow->nParent>0 |
| 268 | && (pParent = hashFind(p, pRow->aParent[0]))!=0 |
| 269 | && pRow->zBranch==pParent->zBranch |
| 270 | ){ |
| 271 | pParent->isLeaf = 0; |
| @@ -296,11 +303,11 @@ | |
| 303 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 304 | int parentRid; |
| 305 | if( pRow->iRail>=0 ) continue; |
| 306 | assert( pRow->nParent>0 ); |
| 307 | parentRid = pRow->aParent[0]; |
| 308 | pDesc = hashFind(p, parentRid); |
| 309 | if( pDesc==0 ){ |
| 310 | /* Time skew */ |
| 311 | pRow->iRail = ++p->mxRail; |
| 312 | pRow->railInUse = 1<<pRow->iRail; |
| 313 | continue; |
| 314 |