Fossil SCM
Performance optimization in the internal printf() implementation.
Commit
008fc9290cbbaa57ffdfab939d0cbced32c4971bbf1fdbab25cd323f0b54ee18
Parent
87c4b7c48c12a84…
2 files changed
+1
+25
-8
+1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -673,10 +673,11 @@ | ||
| 673 | 673 | #endif |
| 674 | 674 | } |
| 675 | 675 | } |
| 676 | 676 | #endif |
| 677 | 677 | |
| 678 | + fossil_printf_selfcheck(); | |
| 678 | 679 | fossil_limit_memory(1); |
| 679 | 680 | if( sqlite3_libversion_number()<3034000 ){ |
| 680 | 681 | fossil_panic("Unsuitable SQLite version %s, must be at least 3.34.0", |
| 681 | 682 | sqlite3_libversion()); |
| 682 | 683 | } |
| 683 | 684 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -673,10 +673,11 @@ | |
| 673 | #endif |
| 674 | } |
| 675 | } |
| 676 | #endif |
| 677 | |
| 678 | fossil_limit_memory(1); |
| 679 | if( sqlite3_libversion_number()<3034000 ){ |
| 680 | fossil_panic("Unsuitable SQLite version %s, must be at least 3.34.0", |
| 681 | sqlite3_libversion()); |
| 682 | } |
| 683 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -673,10 +673,11 @@ | |
| 673 | #endif |
| 674 | } |
| 675 | } |
| 676 | #endif |
| 677 | |
| 678 | fossil_printf_selfcheck(); |
| 679 | fossil_limit_memory(1); |
| 680 | if( sqlite3_libversion_number()<3034000 ){ |
| 681 | fossil_panic("Unsuitable SQLite version %s, must be at least 3.34.0", |
| 682 | sqlite3_libversion()); |
| 683 | } |
| 684 |
+25
-8
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -134,13 +134,17 @@ | ||
| 134 | 134 | |
| 135 | 135 | |
| 136 | 136 | /* |
| 137 | 137 | ** The following table is searched linearly, so it is good to put the |
| 138 | 138 | ** most frequently used conversion types first. |
| 139 | +** | |
| 140 | +** NB: When modifying this table is it vital that you also update the fmtchr[] | |
| 141 | +** variable to match!!! | |
| 139 | 142 | */ |
| 140 | 143 | static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; |
| 141 | 144 | static const char aPrefix[] = "-x0\000X0"; |
| 145 | +static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$"; | |
| 142 | 146 | static const et_info fmtinfo[] = { |
| 143 | 147 | { 'd', 10, 1, etRADIX, 0, 0 }, |
| 144 | 148 | { 's', 0, 4, etSTRING, 0, 0 }, |
| 145 | 149 | { 'g', 0, 1, etGENERIC, 30, 0 }, |
| 146 | 150 | { 'z', 0, 6, etDYNSTRING, 0, 0 }, |
| @@ -172,10 +176,23 @@ | ||
| 172 | 176 | { 'p', 16, 0, etPOINTER, 0, 1 }, |
| 173 | 177 | { '/', 0, 0, etPATH, 0, 0 }, |
| 174 | 178 | { '$', 0, 0, etSHELLESC, 0, 0 }, |
| 175 | 179 | }; |
| 176 | 180 | #define etNINFO count(fmtinfo) |
| 181 | + | |
| 182 | +/* | |
| 183 | +** Verify that the fmtchr[] and fmtinfo[] arrays are in agreement. | |
| 184 | +** | |
| 185 | +** This routine is a defense against programming errors. | |
| 186 | +*/ | |
| 187 | +void fossil_printf_selfcheck(void){ | |
| 188 | + int i; | |
| 189 | + for(i=0; fmtchr[i]; i++){ | |
| 190 | + assert( fmtchr[i]==fmtinfo[i].fmttype ); | |
| 191 | + } | |
| 192 | +} | |
| 193 | + | |
| 177 | 194 | |
| 178 | 195 | /* |
| 179 | 196 | ** "*val" is a double such that 0.1 <= *val < 10.0 |
| 180 | 197 | ** Return the ascii code for the leading digit of *val, then |
| 181 | 198 | ** multiply "*val" by 10.0 to renormalize. |
| @@ -306,10 +323,11 @@ | ||
| 306 | 323 | double rounder; /* Used for rounding floating point values */ |
| 307 | 324 | etByte flag_dp; /* True if decimal point should be shown */ |
| 308 | 325 | etByte flag_rtz; /* True if trailing zeros should be removed */ |
| 309 | 326 | etByte flag_exp; /* True to force display of the exponent */ |
| 310 | 327 | int nsd; /* Number of significant digits returned */ |
| 328 | + char *zFmtLookup; | |
| 311 | 329 | |
| 312 | 330 | count = length = 0; |
| 313 | 331 | bufpt = 0; |
| 314 | 332 | for(; (c=(*fmt))!=0; ++fmt){ |
| 315 | 333 | if( c!='%' ){ |
| @@ -390,18 +408,17 @@ | ||
| 390 | 408 | } |
| 391 | 409 | }else{ |
| 392 | 410 | flag_long = flag_longlong = 0; |
| 393 | 411 | } |
| 394 | 412 | /* Fetch the info entry for the field */ |
| 395 | - infop = 0; | |
| 396 | - xtype = etERROR; | |
| 397 | - for(idx=0; idx<etNINFO; idx++){ | |
| 398 | - if( c==fmtinfo[idx].fmttype ){ | |
| 399 | - infop = &fmtinfo[idx]; | |
| 400 | - xtype = infop->type; | |
| 401 | - break; | |
| 402 | - } | |
| 413 | + zFmtLookup = strchr(fmtchr,c); | |
| 414 | + if( zFmtLookup ){ | |
| 415 | + infop = &fmtinfo[zFmtLookup-fmtchr]; | |
| 416 | + xtype = infop->type; | |
| 417 | + }else{ | |
| 418 | + infop = 0; | |
| 419 | + xtype = etERROR; | |
| 403 | 420 | } |
| 404 | 421 | zExtra = 0; |
| 405 | 422 | |
| 406 | 423 | /* Limit the precision to prevent overflowing buf[] during conversion */ |
| 407 | 424 | if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ |
| 408 | 425 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -134,13 +134,17 @@ | |
| 134 | |
| 135 | |
| 136 | /* |
| 137 | ** The following table is searched linearly, so it is good to put the |
| 138 | ** most frequently used conversion types first. |
| 139 | */ |
| 140 | static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; |
| 141 | static const char aPrefix[] = "-x0\000X0"; |
| 142 | static const et_info fmtinfo[] = { |
| 143 | { 'd', 10, 1, etRADIX, 0, 0 }, |
| 144 | { 's', 0, 4, etSTRING, 0, 0 }, |
| 145 | { 'g', 0, 1, etGENERIC, 30, 0 }, |
| 146 | { 'z', 0, 6, etDYNSTRING, 0, 0 }, |
| @@ -172,10 +176,23 @@ | |
| 172 | { 'p', 16, 0, etPOINTER, 0, 1 }, |
| 173 | { '/', 0, 0, etPATH, 0, 0 }, |
| 174 | { '$', 0, 0, etSHELLESC, 0, 0 }, |
| 175 | }; |
| 176 | #define etNINFO count(fmtinfo) |
| 177 | |
| 178 | /* |
| 179 | ** "*val" is a double such that 0.1 <= *val < 10.0 |
| 180 | ** Return the ascii code for the leading digit of *val, then |
| 181 | ** multiply "*val" by 10.0 to renormalize. |
| @@ -306,10 +323,11 @@ | |
| 306 | double rounder; /* Used for rounding floating point values */ |
| 307 | etByte flag_dp; /* True if decimal point should be shown */ |
| 308 | etByte flag_rtz; /* True if trailing zeros should be removed */ |
| 309 | etByte flag_exp; /* True to force display of the exponent */ |
| 310 | int nsd; /* Number of significant digits returned */ |
| 311 | |
| 312 | count = length = 0; |
| 313 | bufpt = 0; |
| 314 | for(; (c=(*fmt))!=0; ++fmt){ |
| 315 | if( c!='%' ){ |
| @@ -390,18 +408,17 @@ | |
| 390 | } |
| 391 | }else{ |
| 392 | flag_long = flag_longlong = 0; |
| 393 | } |
| 394 | /* Fetch the info entry for the field */ |
| 395 | infop = 0; |
| 396 | xtype = etERROR; |
| 397 | for(idx=0; idx<etNINFO; idx++){ |
| 398 | if( c==fmtinfo[idx].fmttype ){ |
| 399 | infop = &fmtinfo[idx]; |
| 400 | xtype = infop->type; |
| 401 | break; |
| 402 | } |
| 403 | } |
| 404 | zExtra = 0; |
| 405 | |
| 406 | /* Limit the precision to prevent overflowing buf[] during conversion */ |
| 407 | if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ |
| 408 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -134,13 +134,17 @@ | |
| 134 | |
| 135 | |
| 136 | /* |
| 137 | ** The following table is searched linearly, so it is good to put the |
| 138 | ** most frequently used conversion types first. |
| 139 | ** |
| 140 | ** NB: When modifying this table is it vital that you also update the fmtchr[] |
| 141 | ** variable to match!!! |
| 142 | */ |
| 143 | static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; |
| 144 | static const char aPrefix[] = "-x0\000X0"; |
| 145 | static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$"; |
| 146 | static const et_info fmtinfo[] = { |
| 147 | { 'd', 10, 1, etRADIX, 0, 0 }, |
| 148 | { 's', 0, 4, etSTRING, 0, 0 }, |
| 149 | { 'g', 0, 1, etGENERIC, 30, 0 }, |
| 150 | { 'z', 0, 6, etDYNSTRING, 0, 0 }, |
| @@ -172,10 +176,23 @@ | |
| 176 | { 'p', 16, 0, etPOINTER, 0, 1 }, |
| 177 | { '/', 0, 0, etPATH, 0, 0 }, |
| 178 | { '$', 0, 0, etSHELLESC, 0, 0 }, |
| 179 | }; |
| 180 | #define etNINFO count(fmtinfo) |
| 181 | |
| 182 | /* |
| 183 | ** Verify that the fmtchr[] and fmtinfo[] arrays are in agreement. |
| 184 | ** |
| 185 | ** This routine is a defense against programming errors. |
| 186 | */ |
| 187 | void fossil_printf_selfcheck(void){ |
| 188 | int i; |
| 189 | for(i=0; fmtchr[i]; i++){ |
| 190 | assert( fmtchr[i]==fmtinfo[i].fmttype ); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | |
| 195 | /* |
| 196 | ** "*val" is a double such that 0.1 <= *val < 10.0 |
| 197 | ** Return the ascii code for the leading digit of *val, then |
| 198 | ** multiply "*val" by 10.0 to renormalize. |
| @@ -306,10 +323,11 @@ | |
| 323 | double rounder; /* Used for rounding floating point values */ |
| 324 | etByte flag_dp; /* True if decimal point should be shown */ |
| 325 | etByte flag_rtz; /* True if trailing zeros should be removed */ |
| 326 | etByte flag_exp; /* True to force display of the exponent */ |
| 327 | int nsd; /* Number of significant digits returned */ |
| 328 | char *zFmtLookup; |
| 329 | |
| 330 | count = length = 0; |
| 331 | bufpt = 0; |
| 332 | for(; (c=(*fmt))!=0; ++fmt){ |
| 333 | if( c!='%' ){ |
| @@ -390,18 +408,17 @@ | |
| 408 | } |
| 409 | }else{ |
| 410 | flag_long = flag_longlong = 0; |
| 411 | } |
| 412 | /* Fetch the info entry for the field */ |
| 413 | zFmtLookup = strchr(fmtchr,c); |
| 414 | if( zFmtLookup ){ |
| 415 | infop = &fmtinfo[zFmtLookup-fmtchr]; |
| 416 | xtype = infop->type; |
| 417 | }else{ |
| 418 | infop = 0; |
| 419 | xtype = etERROR; |
| 420 | } |
| 421 | zExtra = 0; |
| 422 | |
| 423 | /* Limit the precision to prevent overflowing buf[] during conversion */ |
| 424 | if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){ |
| 425 |