diff --git a/std/format.d b/std/format.d index 450e927e54f..52eebf0fcae 100644 --- a/std/format.d +++ b/std/format.d @@ -1489,9 +1489,8 @@ unittest assert(w.data == "1337"); } -private void formatIntegral(Writer, T, Char)(Writer w, const(T) val, ref FormatSpec!Char f, uint base, ulong mask) +private void formatIntegral(Writer, T, Char)(Writer w, const(T) val, const ref FormatSpec!Char fs, uint base, ulong mask) { - FormatSpec!Char fs = f; // fs is copy for change its values. T arg = val; bool negative = (base == 10 && arg < 0); @@ -1507,105 +1506,93 @@ private void formatIntegral(Writer, T, Char)(Writer w, const(T) val, ref FormatS formatUnsigned(w, (cast(ulong) arg) & mask, fs, base, negative); } -private void formatUnsigned(Writer, T, Char)(Writer w, T arg, ref FormatSpec!Char fs, uint base, bool negative) +private void formatUnsigned(Writer, T, Char)(Writer w, T arg, const ref FormatSpec!Char fs, uint base, bool negative) { - if (fs.precision == fs.UNSPECIFIED) - { - // default precision for integrals is 1 - fs.precision = 1; - } - else + /* Write string: + * leftpad prefix1 prefix2 zerofill digits rightpad + */ + + /* Convert arg to digits[]. + * Note that 0 becomes an empty digits[] + */ + char[64] buffer = void; // 64 bits in base 2 at most + char[] digits; { - // if a precision is specified, the '0' flag is ignored. - fs.flZero = false; + size_t i = buffer.length; + while (arg) + { + --i; + char c = cast(char) (arg % base); + arg /= base; + if (c < 10) + buffer[i] = cast(char)(c + '0'); + else + buffer[i] = cast(char)(c + (fs.spec == 'x' ? 'a' - 10 : 'A' - 10)); + } + digits = buffer[i .. $]; // got the digits without the sign } - char leftPad = void; - if (!fs.flDash && !fs.flZero) - leftPad = ' '; - else if (!fs.flDash && fs.flZero) - leftPad = '0'; - else - leftPad = 0; - // figure out sign and continue in unsigned mode - char forcedPrefix = void; - if (fs.flPlus) forcedPrefix = '+'; - else if (fs.flSpace) forcedPrefix = ' '; - else forcedPrefix = 0; - if (base != 10) + int precision = (fs.precision == fs.UNSPECIFIED) ? 1 : fs.precision; + + char padChar = 0; + if (!fs.flDash) { - // non-10 bases are always unsigned - forcedPrefix = 0; + padChar = (fs.flZero && fs.precision == fs.UNSPECIFIED) ? '0' : ' '; } - else if (negative) + + // Compute prefix1 and prefix2 + char prefix1 = 0; + char prefix2 = 0; + if (base == 10) { - // argument is signed - forcedPrefix = '-'; + if (negative) + prefix1 = '-'; + else if (fs.flPlus) + prefix1 = '+'; + else if (fs.flSpace) + prefix1 = ' '; } - // fill the digits - char[64] buffer; // 64 bits in base 2 at most - char[] digits; + else if (base == 16 && fs.flHash && digits.length) { - uint i = buffer.length; - auto n = arg; - do - { - --i; - buffer[i] = cast(char) (n % base); - n /= base; - if (buffer[i] < 10) buffer[i] += '0'; - else buffer[i] += (fs.spec == 'x' ? 'a' : 'A') - 10; - } while (n); - digits = buffer[i .. $]; // got the digits without the sign + prefix1 = '0'; + prefix2 = fs.spec == 'x' ? 'x' : 'X'; } // adjust precision to print a '0' for octal if alternate format is on - if (base == 8 && fs.flHash - && (fs.precision <= digits.length)) // too low precision - { - //fs.precision = digits.length + (arg != 0); - forcedPrefix = '0'; - } - // write left pad; write sign; write 0x or 0X; write digits; - // write right pad - // Writing left pad - ptrdiff_t spacesToPrint = - fs.width // start with the minimum width - - digits.length // take away digits to print - - (forcedPrefix != 0) // take away the sign if any - - (base == 16 && fs.flHash && arg ? 2 : 0); // 0x or 0X - const ptrdiff_t delta = fs.precision - digits.length; - if (delta > 0) spacesToPrint -= delta; + else if (base == 8 && fs.flHash && + (precision <= 1 || precision <= digits.length)) // too low precision + prefix1 = '0'; + + size_t zerofill = precision > digits.length ? precision - digits.length : 0; + size_t leftpad = 0; + size_t rightpad = 0; + + ptrdiff_t spacesToPrint = fs.width - ((prefix1 != 0) + (prefix2 != 0) + zerofill + digits.length); if (spacesToPrint > 0) // need to do some padding { - if (leftPad == '0') - { - // pad with zeros + if (padChar == '0') + zerofill += spacesToPrint; + else if (padChar) + leftpad = spacesToPrint; + else + rightpad = spacesToPrint; + } - fs.precision = - cast(typeof(fs.precision)) (spacesToPrint + digits.length); - //to!(typeof(fs.precision))(spacesToPrint + digits.length); - } - else if (leftPad) foreach (i ; 0 .. spacesToPrint) put(w, ' '); - } - // write sign - if (forcedPrefix) put(w, forcedPrefix); - // write 0x or 0X - if (base == 16 && fs.flHash && arg) { - // @@@ overcome bug in dmd; - //w.write(fs.spec == 'x' ? "0x" : "0X"); //crashes the compiler + /**** Print ****/ + + foreach (i ; 0 .. leftpad) + put(w, ' '); + + if (prefix1) put(w, prefix1); + if (prefix2) put(w, prefix2); + + foreach (i ; 0 .. zerofill) put(w, '0'); - put(w, fs.spec == 'x' ? 'x' : 'X'); // x or X - } - // write the digits - if (arg || fs.precision) - { - ptrdiff_t zerosToPrint = fs.precision - digits.length; - foreach (i ; 0 .. zerosToPrint) put(w, '0'); - put(w, digits); - } - // write the spaces to the right if left-align - if (!leftPad) foreach (i ; 0 .. spacesToPrint) put(w, ' '); + + put(w, digits); + + foreach (i ; 0 .. rightpad) + put(w, ' '); } @safe pure unittest