Skip to content

Commit 9939897

Browse files
authored
Merge pull request #4912 from RazvanN7/bootcamp_fixes
Issue 5236 - raw reading for integers and a few refactorings
2 parents 9046849 + 050781d commit 9939897

File tree

1 file changed

+76
-35
lines changed

1 file changed

+76
-35
lines changed

std/format.d

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,10 +4300,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
43004300
{
43014301
import std.algorithm.searching : find;
43024302
import std.conv : parse, text;
4303-
if (spec.spec == 's')
4304-
{
4305-
return parse!T(input);
4306-
}
4303+
4304+
if (spec.spec == 's') return parse!T(input);
4305+
43074306
enforce(find(acceptedSpecs!long, spec.spec).length,
43084307
text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));
43094308

@@ -4362,14 +4361,58 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
43624361
return parse!T(input);
43634362
}
43644363

4364+
/**
4365+
* Function that performs raw reading. Used by unformatValue
4366+
* for integral and float types.
4367+
*/
4368+
private T rawRead(T, Range)(ref Range input)
4369+
if (is(Unqual!(ElementEncodingType!Range) == char)
4370+
|| is(Unqual!(ElementEncodingType!Range) == byte)
4371+
|| is(Unqual!(ElementEncodingType!Range) == ubyte))
4372+
{
4373+
union X
4374+
{
4375+
ubyte[T.sizeof] raw;
4376+
T typed;
4377+
}
4378+
X x;
4379+
foreach (i; 0 .. T.sizeof)
4380+
{
4381+
static if (isSomeString!Range)
4382+
{
4383+
x.raw[i] = input[0];
4384+
input = input[1 .. $];
4385+
}
4386+
else
4387+
{
4388+
// TODO: recheck this
4389+
x.raw[i] = input.front;
4390+
input.popFront();
4391+
}
4392+
}
4393+
return x.typed;
4394+
}
4395+
43654396
/**
43664397
Reads an integral value and returns it.
43674398
*/
43684399
T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
4369-
if (isInputRange!Range && isIntegral!T && !is(T == enum))
4400+
if (isInputRange!Range && isIntegral!T && !is(T == enum) && isSomeChar!(ElementType!Range))
43704401
{
4402+
43714403
import std.algorithm.searching : find;
43724404
import std.conv : parse, text;
4405+
4406+
if (spec.spec == 'r')
4407+
{
4408+
static if (is(Unqual!(ElementEncodingType!Range) == char)
4409+
|| is(Unqual!(ElementEncodingType!Range) == byte)
4410+
|| is(Unqual!(ElementEncodingType!Range) == ubyte))
4411+
return rawRead!T(input);
4412+
else
4413+
throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes.");
4414+
}
4415+
43734416
enforce(find(acceptedSpecs!T, spec.spec).length,
43744417
text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));
43754418

@@ -4381,54 +4424,52 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
43814424
spec.spec == 'b' ? 2 :
43824425
spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0;
43834426
assert(base != 0);
4427+
43844428
return parse!T(input, base);
4429+
4430+
}
4431+
4432+
unittest
4433+
{
4434+
union B
4435+
{
4436+
char[int.sizeof] untyped;
4437+
int typed;
4438+
}
4439+
B b;
4440+
b.typed = 5;
4441+
char[] input = b.untyped[];
4442+
int witness;
4443+
formattedRead(input, "%r", &witness);
4444+
assert(witness == b.typed);
43854445
}
43864446

43874447
/**
43884448
Reads a floating-point value and returns it.
43894449
*/
43904450
T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
4391-
if (isFloatingPoint!T && !is(T == enum))
4451+
if (isFloatingPoint!T && !is(T == enum) && isInputRange!Range && isSomeChar!(ElementType!Range) && !is(Range == enum))
43924452
{
43934453
import std.algorithm.searching : find;
43944454
import std.conv : parse, text;
4455+
43954456
if (spec.spec == 'r')
43964457
{
4397-
// raw read
4398-
//enforce(input.length >= T.sizeof);
4399-
enforce(
4400-
isSomeString!Range || ElementType!(Range).sizeof == 1,
4401-
"Cannot parse input of type %s".format(Range.stringof)
4402-
);
4403-
union X
4404-
{
4405-
ubyte[T.sizeof] raw;
4406-
T typed;
4407-
}
4408-
X x;
4409-
foreach (i; 0 .. T.sizeof)
4410-
{
4411-
static if (isSomeString!Range)
4412-
{
4413-
x.raw[i] = input[0];
4414-
input = input[1 .. $];
4415-
}
4416-
else
4417-
{
4418-
// TODO: recheck this
4419-
x.raw[i] = cast(ubyte) input.front;
4420-
input.popFront();
4421-
}
4422-
}
4423-
return x.typed;
4458+
static if (is(Unqual!(ElementEncodingType!Range) == char)
4459+
|| is(Unqual!(ElementEncodingType!Range) == byte)
4460+
|| is(Unqual!(ElementEncodingType!Range) == ubyte))
4461+
return rawRead!T(input);
4462+
else
4463+
throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes.");
44244464
}
4465+
44254466
enforce(find(acceptedSpecs!T, spec.spec).length,
44264467
text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));
44274468

44284469
return parse!T(input);
44294470
}
44304471

4431-
version(none)unittest
4472+
unittest
44324473
{
44334474
union A
44344475
{
@@ -4470,7 +4511,7 @@ version(none)unittest
44704511
* Reads one character and returns it.
44714512
*/
44724513
T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec)
4473-
if (isInputRange!Range && isSomeChar!T && !is(T == enum))
4514+
if (isInputRange!Range && isSomeChar!T && !is(T == enum) && isSomeChar!(ElementType!Range))
44744515
{
44754516
import std.algorithm.searching : find;
44764517
import std.conv : to, text;

0 commit comments

Comments
 (0)