Merge pull request #3470 from WalterBright/betterFormatU

std.format.formatUnsigned: refactor
This commit is contained in:
Hara Kenji 2015-07-04 14:36:23 +09:00
commit c3a39c5461

View file

@ -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
{
// if a precision is specified, the '0' flag is ignored.
fs.flZero = false;
}
/* Write string:
* leftpad prefix1 prefix2 zerofill digits rightpad
*/
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)
{
// non-10 bases are always unsigned
forcedPrefix = 0;
}
else if (negative)
{
// argument is signed
forcedPrefix = '-';
}
// fill the digits
char[64] buffer; // 64 bits in base 2 at most
/* Convert arg to digits[].
* Note that 0 becomes an empty digits[]
*/
char[64] buffer = void; // 64 bits in base 2 at most
char[] digits;
{
uint i = buffer.length;
auto n = arg;
do
size_t i = buffer.length;
while (arg)
{
--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);
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
}
// 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
int precision = (fs.precision == fs.UNSPECIFIED) ? 1 : fs.precision;
char padChar = 0;
if (!fs.flDash)
{
//fs.precision = digits.length + (arg != 0);
forcedPrefix = '0';
padChar = (fs.flZero && fs.precision == fs.UNSPECIFIED) ? '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;
// Compute prefix1 and prefix2
char prefix1 = 0;
char prefix2 = 0;
if (base == 10)
{
if (negative)
prefix1 = '-';
else if (fs.flPlus)
prefix1 = '+';
else if (fs.flSpace)
prefix1 = ' ';
}
else if (base == 16 && fs.flHash && digits.length)
{
prefix1 = '0';
prefix2 = fs.spec == 'x' ? 'x' : 'X';
}
// adjust precision to print a '0' for octal if alternate format is on
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