mirror of
https://github.com/dlang/phobos.git
synced 2025-04-27 13:40:20 +03:00
Add 'std.format.read.formattedRead' overloads to return a Tuple with values read (#8647)
* refactor(formattedRead): add not is type validation to template argument 'fmt' Signed-off-by: João Lourenço <jlourenco5691@gmail.com> * feat(formattedRead): add overloads to return a tuple with the read values Signed-off-by: João Lourenço <jlourenco5691@gmail.com> * test(formattedRead): add unnittests for the tuple return type overloads Signed-off-by: João Lourenço <jlourenco5691@gmail.com> * chore(changelog): add a changelog formattedRead entry Signed-off-by: João Lourenço <jlourenco5691@gmail.com> --------- Signed-off-by: João Lourenço <jlourenco5691@gmail.com>
This commit is contained in:
parent
5d16dafff0
commit
6b666971bc
2 changed files with 143 additions and 2 deletions
30
changelog/formatted_read_tuple_return.dd
Normal file
30
changelog/formatted_read_tuple_return.dd
Normal file
|
@ -0,0 +1,30 @@
|
|||
Extend the functionality of formattedRead to permit a std.file.slurp like execution.
|
||||
|
||||
Template argument types can now be passed to formattedRead along with a
|
||||
format string to parse and read the input range as a Tuple of those arguments.
|
||||
All arguments must be read successfully, otherwise, and unlike std.file.slurp
|
||||
which has non exhaustive option for partial reads, it'll throw a std.format.FormatException.
|
||||
|
||||
---
|
||||
import std.exception : assertThrown;
|
||||
import std.format : FormatException;
|
||||
import std.typecons : tuple;
|
||||
|
||||
@safe pure unittest
|
||||
{
|
||||
auto complete = "hello!34.5:124".formattedRead!(string, double, int)("%s!%s:%s");
|
||||
assert(complete == tuple("hello", 34.5, 124));
|
||||
|
||||
assertThrown!FormatException("hello!34.5:".formattedRead!(string, double, int)("%s!%s:%s"));
|
||||
}
|
||||
|
||||
/// The format string can be checked at compile-time:
|
||||
@safe pure unittest
|
||||
{
|
||||
auto expected = tuple("hello", 124, 34.5);
|
||||
auto result = "hello!124:34.5".formattedRead!("%s!%s:%s", string, int, double);
|
||||
assert(result == expected);
|
||||
|
||||
assertThrown!FormatException("hello!34.5:".formattedRead!("%s!%s:%s", string, double, int));
|
||||
}
|
||||
---
|
|
@ -198,7 +198,8 @@ module std.format.read;
|
|||
|
||||
import std.format.spec : FormatSpec;
|
||||
import std.format.internal.read;
|
||||
import std.traits : isSomeString;
|
||||
import std.meta : allSatisfy;
|
||||
import std.traits : isSomeString, isType;
|
||||
|
||||
/**
|
||||
Reads an input range according to a format string and stores the read
|
||||
|
@ -300,7 +301,7 @@ uint formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, au
|
|||
|
||||
/// ditto
|
||||
uint formattedRead(alias fmt, Range, Args...)(auto ref Range r, auto ref Args args)
|
||||
if (isSomeString!(typeof(fmt)))
|
||||
if (!isType!fmt && isSomeString!(typeof(fmt)))
|
||||
{
|
||||
import std.format : checkFormatException;
|
||||
import std.meta : staticMap;
|
||||
|
@ -692,6 +693,116 @@ if (isSomeString!(typeof(fmt)))
|
|||
assert(aa2 == ["hello":1, "world":2]);
|
||||
}
|
||||
|
||||
/**
|
||||
Reads an input range according to a format string and returns a tuple of Args
|
||||
with the read values.
|
||||
|
||||
Format specifiers with format character $(B 'd'), $(B 'u') and $(B
|
||||
'c') can take a $(B '*') parameter for skipping values.
|
||||
|
||||
The second version of `formattedRead` takes the format string as
|
||||
template argument. In this case, it is checked for consistency at
|
||||
compile-time.
|
||||
|
||||
Params:
|
||||
Args = a variadic list of types of the arguments
|
||||
*/
|
||||
template formattedRead(Args...)
|
||||
if (Args.length && allSatisfy!(isType, Args))
|
||||
{
|
||||
import std.typecons : Tuple;
|
||||
|
||||
/**
|
||||
Params:
|
||||
r = an $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
|
||||
where the formatted input is read from
|
||||
fmt = a $(MREF_ALTTEXT format string, std,format)
|
||||
Range = the type of the input range `r`
|
||||
Char = the character type used for `fmt`
|
||||
|
||||
Returns:
|
||||
A Tuple!Args with the elements filled.
|
||||
|
||||
Throws:
|
||||
A $(REF_ALTTEXT FormatException, FormatException, std, format)
|
||||
if reading did not succeed.
|
||||
*/
|
||||
Tuple!Args formattedRead(Range, Char)(auto ref Range r, const(Char)[] fmt)
|
||||
{
|
||||
import core.lifetime : forward;
|
||||
import std.format : enforceFmt;
|
||||
|
||||
Tuple!Args args;
|
||||
const numArgsFilled = .formattedRead(forward!r, fmt, args.expand);
|
||||
enforceFmt(numArgsFilled == Args.length, "Failed reading into all format arguments");
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@safe pure unittest
|
||||
{
|
||||
import std.exception : assertThrown;
|
||||
import std.format : FormatException;
|
||||
import std.typecons : tuple;
|
||||
|
||||
auto complete = "hello!34.5:124".formattedRead!(string, double, int)("%s!%s:%s");
|
||||
assert(complete == tuple("hello", 34.5, 124));
|
||||
|
||||
// reading ends early
|
||||
assertThrown!FormatException("hello!34.5:".formattedRead!(string, double, int)("%s!%s:%s"));
|
||||
}
|
||||
|
||||
/// Skipping values
|
||||
@safe pure unittest
|
||||
{
|
||||
import std.format : FormatException;
|
||||
import std.typecons : tuple;
|
||||
|
||||
auto result = "orange: (12%) 15.25".formattedRead!(string, double)("%s: (%*d%%) %f");
|
||||
assert(result == tuple("orange", 15.25));
|
||||
}
|
||||
|
||||
/// ditto
|
||||
template formattedRead(alias fmt, Args...)
|
||||
if (!isType!fmt && isSomeString!(typeof(fmt)) && Args.length && allSatisfy!(isType, Args))
|
||||
{
|
||||
import std.typecons : Flag, Tuple, Yes;
|
||||
Tuple!Args formattedRead(Range)(auto ref Range r)
|
||||
{
|
||||
import core.lifetime : forward;
|
||||
import std.format : enforceFmt;
|
||||
|
||||
Tuple!Args args;
|
||||
const numArgsFilled = .formattedRead!fmt(forward!r, args.expand);
|
||||
enforceFmt(numArgsFilled == Args.length, "Failed reading into all format arguments");
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
/// The format string can be checked at compile-time
|
||||
@safe pure unittest
|
||||
{
|
||||
import std.exception : assertThrown;
|
||||
import std.format : FormatException;
|
||||
import std.typecons : tuple;
|
||||
|
||||
auto expected = tuple("hello", 124, 34.5);
|
||||
auto result = "hello!124:34.5".formattedRead!("%s!%s:%s", string, int, double);
|
||||
assert(result == expected);
|
||||
|
||||
assertThrown!FormatException("hello!34.5:".formattedRead!("%s!%s:%s", string, double, int));
|
||||
}
|
||||
|
||||
/// Compile-time consistency check
|
||||
@safe pure unittest
|
||||
{
|
||||
import std.format : FormatException;
|
||||
import std.typecons : tuple;
|
||||
|
||||
static assert(!__traits(compiles, "orange: (12%) 15.25".formattedRead!("%s: (%*d%%) %f", string, double)));
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a value from the given _input range and converts it according to a
|
||||
format specifier.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue