From 6d13f6685556d633ed0801cd638bc5d96fa69a71 Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Tue, 1 Nov 2016 13:58:07 +0200 Subject: [PATCH 1/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 104 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 36 deletions(-) diff --git a/std/format.d b/std/format.d index fa1a11690ec..cfd4cbf1d4c 100644 --- a/std/format.d +++ b/std/format.d @@ -4302,7 +4302,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) import std.conv : parse, text; if (spec.spec == 's') { - return parse!T(input); + static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } enforce(find(acceptedSpecs!long, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4359,7 +4359,38 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - return parse!T(input); + static if(__traits(compiles, parse!T(input)) ) return parse!T(input); +} + +private T rawReadWrapper(T, Range)(ref Range input) +{ + enforce( + isSomeString!Range || ElementType!(Range).sizeof == 1, + "Cannot parse input of type %s".format(Range.stringof) + ); + union X + { + ubyte[T.sizeof] raw; + T typed; + } + X x; + foreach (i; 0 .. T.sizeof) + { + static if (isSomeString!Range) + { + x.raw[i] = input[0]; + input = input[1 .. $]; + } + else + { + // TODO: recheck this + x.raw[i] = cast(ubyte) input.front; + input.popFront(); + } + } + + return x.typed; + } /** @@ -4368,6 +4399,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isIntegral!T && !is(T == enum)) { + import std.algorithm.searching : find; import std.conv : parse, text; enforce(find(acceptedSpecs!T, spec.spec).length, @@ -4381,7 +4413,31 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) spec.spec == 'b' ? 2 : spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0; assert(base != 0); - return parse!T(input, base); + + // raw read + //enforce(input.length >= T.sizeof); + if (spec.spec == 'r') return rawReadWrapper!T(input); + + enforce(find(acceptedSpecs!T, spec.spec).length, + text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); + + static if(__traits(compiles, parse!T(input, base)) ) return parse!T(input, base); + +} + +version(none)unittest +{ + union B + { + char[int.sizeof] untyped; + int typed; + } + B b; + b.typed = 5; + char[] input = b.untyped[]; + int witness; + formattedRead(input, "%r", &witness); + assert(witness == b.typed); } /** @@ -4392,40 +4448,16 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) { import std.algorithm.searching : find; import std.conv : parse, text; - if (spec.spec == 'r') - { - // raw read - //enforce(input.length >= T.sizeof); - enforce( - isSomeString!Range || ElementType!(Range).sizeof == 1, - "Cannot parse input of type %s".format(Range.stringof) - ); - union X - { - ubyte[T.sizeof] raw; - T typed; - } - X x; - foreach (i; 0 .. T.sizeof) - { - static if (isSomeString!Range) - { - x.raw[i] = input[0]; - input = input[1 .. $]; - } - else - { - // TODO: recheck this - x.raw[i] = cast(ubyte) input.front; - input.popFront(); - } - } - return x.typed; - } + + + // raw read + //enforce(input.length >= T.sizeof); + if (spec.spec == 'r') return rawReadWrapper!T(input); + enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - return parse!T(input); + static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } version(none)unittest @@ -4600,7 +4632,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - return parse!T(input); + static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } @system pure unittest @@ -4694,7 +4726,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - return parse!T(input); + static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } @system pure unittest From ddc63be000232977e4ba4c8a3e3e7b0066eb85ad Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 2 Nov 2016 16:21:49 +0200 Subject: [PATCH 2/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/format.d b/std/format.d index cfd4cbf1d4c..5455ab440bd 100644 --- a/std/format.d +++ b/std/format.d @@ -4388,7 +4388,7 @@ private T rawReadWrapper(T, Range)(ref Range input) input.popFront(); } } - + return x.typed; } From 3ab55e96e1691b1fa72e3695fcf71f7e393f62b1 Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Mon, 7 Nov 2016 10:56:43 +0200 Subject: [PATCH 3/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 66 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/std/format.d b/std/format.d index 5455ab440bd..a2700823937 100644 --- a/std/format.d +++ b/std/format.d @@ -4362,34 +4362,34 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } -private T rawReadWrapper(T, Range)(ref Range input) +private T rawRead(T, Range)(ref Range input) { - enforce( + enforce( isSomeString!Range || ElementType!(Range).sizeof == 1, "Cannot parse input of type %s".format(Range.stringof) ); - union X - { - ubyte[T.sizeof] raw; - T typed; - } + union X + { + ubyte[T.sizeof] raw; + T typed; + } X x; - foreach (i; 0 .. T.sizeof) - { - static if (isSomeString!Range) - { - x.raw[i] = input[0]; - input = input[1 .. $]; - } - else - { - // TODO: recheck this - x.raw[i] = cast(ubyte) input.front; - input.popFront(); - } - } + foreach (i; 0 .. T.sizeof) + { + static if (isSomeString!Range) + { + x.raw[i] = input[0]; + input = input[1 .. $]; + } + else + { + // TODO: recheck this + x.raw[i] = cast(ubyte) input.front; + input.popFront(); + } + } - return x.typed; + return x.typed; } @@ -4399,7 +4399,7 @@ private T rawReadWrapper(T, Range)(ref Range input) T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isIntegral!T && !is(T == enum)) { - + import std.algorithm.searching : find; import std.conv : parse, text; enforce(find(acceptedSpecs!T, spec.spec).length, @@ -4413,16 +4413,16 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) spec.spec == 'b' ? 2 : spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0; assert(base != 0); - + // raw read - //enforce(input.length >= T.sizeof); - if (spec.spec == 'r') return rawReadWrapper!T(input); + //enforce(input.length >= T.sizeof); + if (spec.spec == 'r') return rawRead!T(input); - enforce(find(acceptedSpecs!T, spec.spec).length, - text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); + enforce(find(acceptedSpecs!T, spec.spec).length, + text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); + + static if(__traits(compiles, parse!T(input, base)) ) return parse!T(input, base); - static if(__traits(compiles, parse!T(input, base)) ) return parse!T(input, base); - } version(none)unittest @@ -4451,9 +4451,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) // raw read - //enforce(input.length >= T.sizeof); - if (spec.spec == 'r') return rawReadWrapper!T(input); - + //enforce(input.length >= T.sizeof); + if (spec.spec == 'r') return rawRead!T(input); + enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); From 58374ac540420f2d9af3a5f5def4dbc8374043cf Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 16 Nov 2016 11:14:14 +0200 Subject: [PATCH 4/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 58 ---------------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/std/format.d b/std/format.d index a2700823937..88e5f8a0a64 100644 --- a/std/format.d +++ b/std/format.d @@ -4362,37 +4362,6 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) static if(__traits(compiles, parse!T(input)) ) return parse!T(input); } -private T rawRead(T, Range)(ref Range input) -{ - enforce( - isSomeString!Range || ElementType!(Range).sizeof == 1, - "Cannot parse input of type %s".format(Range.stringof) - ); - union X - { - ubyte[T.sizeof] raw; - T typed; - } - X x; - foreach (i; 0 .. T.sizeof) - { - static if (isSomeString!Range) - { - x.raw[i] = input[0]; - input = input[1 .. $]; - } - else - { - // TODO: recheck this - x.raw[i] = cast(ubyte) input.front; - input.popFront(); - } - } - - return x.typed; - -} - /** Reads an integral value and returns it. */ @@ -4414,32 +4383,10 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0; assert(base != 0); - // raw read - //enforce(input.length >= T.sizeof); - if (spec.spec == 'r') return rawRead!T(input); - - enforce(find(acceptedSpecs!T, spec.spec).length, - text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if(__traits(compiles, parse!T(input, base)) ) return parse!T(input, base); } -version(none)unittest -{ - union B - { - char[int.sizeof] untyped; - int typed; - } - B b; - b.typed = 5; - char[] input = b.untyped[]; - int witness; - formattedRead(input, "%r", &witness); - assert(witness == b.typed); -} - /** Reads a floating-point value and returns it. */ @@ -4449,11 +4396,6 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) import std.algorithm.searching : find; import std.conv : parse, text; - - // raw read - //enforce(input.length >= T.sizeof); - if (spec.spec == 'r') return rawRead!T(input); - enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); From f5bece91ab50edbee200368016908bbac8924e0d Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 16 Nov 2016 17:49:20 +0200 Subject: [PATCH 5/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/format.d b/std/format.d index 88e5f8a0a64..3034571b99d 100644 --- a/std/format.d +++ b/std/format.d @@ -4300,9 +4300,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) { import std.algorithm.searching : find; import std.conv : parse, text; - if (spec.spec == 's') + static if (is(typeof(parse!T(input)) == T)) { - static if(__traits(compiles, parse!T(input)) ) return parse!T(input); + if (spec.spec == `s`) return parse!T(input); } enforce(find(acceptedSpecs!long, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4359,7 +4359,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if(__traits(compiles, parse!T(input)) ) return parse!T(input); + return parse!T(input); } /** From bacddb87ff2fa9db635562f0bf17c2ed10d3ab5d Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Fri, 18 Nov 2016 14:51:41 +0200 Subject: [PATCH 6/8] Issue 5236 - [patch] std.format.formattedRead/unformatValue does not support the raw reading of integer types --- std/format.d | 58 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/std/format.d b/std/format.d index 3034571b99d..b77c70cdc12 100644 --- a/std/format.d +++ b/std/format.d @@ -4302,7 +4302,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) import std.conv : parse, text; static if (is(typeof(parse!T(input)) == T)) { - if (spec.spec == `s`) return parse!T(input); + if (spec.spec == 's') return parse!T(input); } enforce(find(acceptedSpecs!long, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4362,6 +4362,32 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) return parse!T(input); } +private T rawRead(T, Range)(ref Range input) + if (isSomeString!Range || ElementType!(Range).sizeof == 1) +{ + union X + { + ubyte[T.sizeof] raw; + T typed; + } + X x; + foreach (i; 0 .. T.sizeof) + { + static if (isSomeString!Range) + { + x.raw[i] = input[0]; + input = input[1 .. $]; + } + else + { + // TODO: recheck this + x.raw[i] = cast(ubyte) input.front; + input.popFront(); + } + } + return x.typed; +} + /** Reads an integral value and returns it. */ @@ -4371,6 +4397,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) import std.algorithm.searching : find; import std.conv : parse, text; + + if (spec.spec == 'r') return rawRead!T(input); + enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4383,8 +4412,23 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0; assert(base != 0); - static if(__traits(compiles, parse!T(input, base)) ) return parse!T(input, base); + return parse!T(input, base); + +} +unittest +{ + union B + { + char[int.sizeof] untyped; + int typed; + } + B b; + b.typed = 5; + char[] input = b.untyped[]; + int witness; + formattedRead(input, "%r", &witness); + assert(witness == b.typed); } /** @@ -4396,13 +4440,15 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) import std.algorithm.searching : find; import std.conv : parse, text; + if (spec.spec == 'r') return rawRead!T(input); + enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if(__traits(compiles, parse!T(input)) ) return parse!T(input); + return parse!T(input); } -version(none)unittest +unittest { union A { @@ -4574,7 +4620,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if(__traits(compiles, parse!T(input)) ) return parse!T(input); + return parse!T(input); } @system pure unittest @@ -4668,7 +4714,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); - static if(__traits(compiles, parse!T(input)) ) return parse!T(input); + return parse!T(input); } @system pure unittest From 5498a70f0e3749dc420d185f143963b33bd75d2c Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 23 Nov 2016 12:02:24 +0200 Subject: [PATCH 7/8] Applied review feedback --- std/format.d | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/std/format.d b/std/format.d index b77c70cdc12..60c33960026 100644 --- a/std/format.d +++ b/std/format.d @@ -4300,10 +4300,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) { import std.algorithm.searching : find; import std.conv : parse, text; - static if (is(typeof(parse!T(input)) == T)) - { - if (spec.spec == 's') return parse!T(input); - } + + if (spec.spec == 's') return parse!T(input); + enforce(find(acceptedSpecs!long, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4363,7 +4362,9 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) } private T rawRead(T, Range)(ref Range input) - if (isSomeString!Range || ElementType!(Range).sizeof == 1) + if (is(Unqual!(ElementEncodingType!Range) == char) + || is(Unqual!(ElementEncodingType!Range) == byte) + || is(Unqual!(ElementEncodingType!Range) == ubyte)) { union X { @@ -4381,7 +4382,7 @@ private T rawRead(T, Range)(ref Range input) else { // TODO: recheck this - x.raw[i] = cast(ubyte) input.front; + x.raw[i] = input.front; input.popFront(); } } @@ -4392,13 +4393,21 @@ private T rawRead(T, Range)(ref Range input) Reads an integral value and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) - if (isInputRange!Range && isIntegral!T && !is(T == enum)) + if (isInputRange!Range && isIntegral!T && !is(T == enum) && isSomeChar!(ElementType!Range)) { import std.algorithm.searching : find; import std.conv : parse, text; - if (spec.spec == 'r') return rawRead!T(input); + if (spec.spec == 'r') + { + static if (is(Unqual!(ElementEncodingType!Range) == char) + || is(Unqual!(ElementEncodingType!Range) == byte) + || is(Unqual!(ElementEncodingType!Range) == ubyte)) + return rawRead!T(input); + else + throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes."); + } enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4435,12 +4444,20 @@ unittest Reads a floating-point value and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) - if (isFloatingPoint!T && !is(T == enum)) + if (isFloatingPoint!T && !is(T == enum) && isInputRange!Range && isSomeChar!(ElementType!Range) && !is(Range == enum)) { import std.algorithm.searching : find; import std.conv : parse, text; - if (spec.spec == 'r') return rawRead!T(input); + if (spec.spec == 'r') + { + static if (is(Unqual!(ElementEncodingType!Range) == char) + || is(Unqual!(ElementEncodingType!Range) == byte) + || is(Unqual!(ElementEncodingType!Range) == ubyte)) + return rawRead!T(input); + else + throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes."); + } enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); @@ -4490,7 +4507,7 @@ unittest * Reads one character and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) - if (isInputRange!Range && isSomeChar!T && !is(T == enum)) + if (isInputRange!Range && isSomeChar!T && !is(T == enum) && isSomeChar!(ElementType!Range)) { import std.algorithm.searching : find; import std.conv : to, text; From 050781da6104a3f93e1994df08be3726c266b49a Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Tue, 6 Dec 2016 12:57:35 +0200 Subject: [PATCH 8/8] Added proper indentation --- std/format.d | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/std/format.d b/std/format.d index 60c33960026..13aa93511ba 100644 --- a/std/format.d +++ b/std/format.d @@ -4361,6 +4361,10 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) return parse!T(input); } +/** + * Function that performs raw reading. Used by unformatValue + * for integral and float types. + */ private T rawRead(T, Range)(ref Range input) if (is(Unqual!(ElementEncodingType!Range) == char) || is(Unqual!(ElementEncodingType!Range) == byte) @@ -4404,7 +4408,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) static if (is(Unqual!(ElementEncodingType!Range) == char) || is(Unqual!(ElementEncodingType!Range) == byte) || is(Unqual!(ElementEncodingType!Range) == ubyte)) - return rawRead!T(input); + return rawRead!T(input); else throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes."); } @@ -4454,7 +4458,7 @@ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) static if (is(Unqual!(ElementEncodingType!Range) == char) || is(Unqual!(ElementEncodingType!Range) == byte) || is(Unqual!(ElementEncodingType!Range) == ubyte)) - return rawRead!T(input); + return rawRead!T(input); else throw new Exception("The raw read specifier %r may only be used with narrow strings and ranges of bytes."); }