Skip to content

Commit

Permalink
std.format.formatUnsigned: refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Jul 4, 2015
1 parent 67a08f1 commit f4e37c3
Showing 1 changed file with 72 additions and 85 deletions.
157 changes: 72 additions & 85 deletions std/format.d
Expand Up @@ -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);
Expand All @@ -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
Expand Down

0 comments on commit f4e37c3

Please sign in to comment.