Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
November 08, 2018 Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Excuse my ignorance, but from looking at the documentation on std.range and a quick skim of the guides mentioned there near the top, I can't see what the simple way is of creating an InputRange!(ubyte) from strings, files etc. I would have expected to find something in the DLang Tour about this, but couldn't find anything. Please can someone tell me how to do it? Just to be clear, I want to create an object which is an InputRange!(ubyte) and pass that around, rather than e.g. iterate over a string or a file. |
November 09, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vinay Sajip | On 09/11/2018 2:58 AM, Vinay Sajip wrote:
> Excuse my ignorance, but from looking at the documentation on std.range and a quick skim of the guides mentioned there near the top, I can't see what the simple way is of creating an InputRange!(ubyte) from strings, files etc. I would have expected to find something in the DLang Tour about this, but couldn't find anything. Please can someone tell me how to do it? Just to be clear, I want to create an object which is an InputRange!(ubyte) and pass that around, rather than e.g. iterate over a string or a file.
TLDR of how to write an input range:
struct MyInputRange {
ubyte[] input;
@property {
ubyte front() {
return this.input[0];
}
bool empty() {
return this.input.length == 0;
}
}
void popFront() {
this.input = this.input[1 .. $];
}
}
import std.stdio;
void main() {
foreach(b; MyInputRange([1, 2, 3])) {
writeln(b);
}
}
|
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vinay Sajip | On Thursday, 8 November 2018 at 13:58:55 UTC, Vinay Sajip wrote:
> Excuse my ignorance, but from looking at the documentation on std.range and a quick skim of the guides mentioned there near the top, I can't see what the simple way is of creating an InputRange!(ubyte) from strings, files etc. I would have expected to find something in the DLang Tour about this, but couldn't find anything. Please can someone tell me how to do it? Just to be clear, I want to create an object which is an InputRange!(ubyte) and pass that around, rather than e.g. iterate over a string or a file.
You can iterate through a file one ubyte at a time using `byChunk` and `joiner`:
auto r1 = stdin.byChunk(1024).joiner;
assert(is(typeof(r1.front) == ubyte));
You can iterate through a string one ubyte at a time using `representation`:
auto r2 = "To be or not to be".representation;
assert(is(typeof(r2.front) == immutable(ubyte)));
To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them:
InputRange!ubyte r3 = inputRangeObject(r1);
InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2);
|
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote:
> You can iterate through a file one ubyte at a time using `byChunk` and `joiner`:
>
> auto r1 = stdin.byChunk(1024).joiner;
> assert(is(typeof(r1.front) == ubyte));
>
> You can iterate through a string one ubyte at a time using `representation`:
>
> auto r2 = "To be or not to be".representation;
> assert(is(typeof(r2.front) == immutable(ubyte)));
>
> To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them:
>
> InputRange!ubyte r3 = inputRangeObject(r1);
> InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2);
Aha - inputRangeObject was the thing I was missing. Thanks!
|
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote: > To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them: > > InputRange!ubyte r3 = inputRangeObject(r1); > InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2); I did a bit more digging, and it seems to work for strings but not for files: The program import std.algorithm.iteration; import std.format; import std.range; import std.stdio; import std.string; void somefn(InputRange!(immutable(ubyte)) r) { writeln(format!"%s"(r)); } void main() { auto a = "Hello, world!"; auto b = inputRangeObject(a.representation); somefn(b); auto c = stdin.byChunk(1024).joiner; auto d = inputRangeObject(c); //somefn(d); } compiles as given above, but if the somefn(d) line is uncommented, I get an error: function onlineapp.somefn(InputRange!(immutable(ubyte)) r) is not callable using argument types (InputRangeObject!(Result)) onlineapp.d(18): cannot pass argument d of type std.range.interfaces.InputRangeObject!(Result) to parameter InputRange!(immutable(ubyte)) r Do I need to do an explicit cast? If so, can someone tell me the precise incantation? How come it doesn't figure out that the underlying range is a ubyte range, or is it to do with immutability, or something else altogether? |
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vinay Sajip | On Thursday, 8 November 2018 at 16:15:25 UTC, Vinay Sajip wrote:
> On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote:
>> To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them:
>>
>> InputRange!ubyte r3 = inputRangeObject(r1);
>> InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2);
>
> I did a bit more digging, and it seems to work for strings but not for files: The program
>
> import std.algorithm.iteration;
> import std.format;
> import std.range;
> import std.stdio;
> import std.string;
>
> void somefn(InputRange!(immutable(ubyte)) r) {
> writeln(format!"%s"(r));
> }
>
> void main()
> {
> auto a = "Hello, world!";
> auto b = inputRangeObject(a.representation);
> somefn(b);
> auto c = stdin.byChunk(1024).joiner;
> auto d = inputRangeObject(c);
> //somefn(d);
> }
>
> compiles as given above, but if the somefn(d) line is uncommented, I get an error:
>
> function onlineapp.somefn(InputRange!(immutable(ubyte)) r) is not callable using argument types (InputRangeObject!(Result))
> onlineapp.d(18): cannot pass argument d of type std.range.interfaces.InputRangeObject!(Result) to parameter InputRange!(immutable(ubyte)) r
>
> Do I need to do an explicit cast? If so, can someone tell me the precise incantation? How come it doesn't figure out that the underlying range is a ubyte range, or is it to do with immutability, or something else altogether?
you could use a template for somefn definition:
´´´
void somefn(T)(T r) {
writeln(format!"%s"(r));
}
´´´
|
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vinay Sajip | On 11/8/18 11:15 AM, Vinay Sajip wrote: > On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote: >> To pass these ranges around using the `InputRange` interface, use `inputRangeObject` to wrap them: >> >> InputRange!ubyte r3 = inputRangeObject(r1); >> InputRange!(immutable(ubyte)) r4 = inputRangeObject(r2); > > I did a bit more digging, and it seems to work for strings but not for files: The program > > import std.algorithm.iteration; > import std.format; > import std.range; > import std.stdio; > import std.string; > > void somefn(InputRange!(immutable(ubyte)) r) { > writeln(format!"%s"(r)); > } > > void main() > { > auto a = "Hello, world!"; > auto b = inputRangeObject(a.representation); > somefn(b); > auto c = stdin.byChunk(1024).joiner; > auto d = inputRangeObject(c); > //somefn(d); > } > > compiles as given above, but if the somefn(d) line is uncommented, I get an error: > > function onlineapp.somefn(InputRange!(immutable(ubyte)) r) is not callable using argument types (InputRangeObject!(Result)) > onlineapp.d(18): cannot pass argument d of type std.range.interfaces.InputRangeObject!(Result) to parameter InputRange!(immutable(ubyte)) r > > Do I need to do an explicit cast? If so, can someone tell me the precise incantation? How come it doesn't figure out that the underlying range is a ubyte range, or is it to do with immutability, or something else altogether? A cool feature of D is to have it tell you something about your code at compile time. I did this in a run.dlang.org playground: pragma(msg, ElementType!(typeof(b))); pragma(msg, ElementType!(typeof(d))); I get: immutable(ubyte) ubyte Which means they aren't the same type, and they don't define the same interface (InputRange!(ubyte) is not the same as InputRange!(immutable(ubyte)) ). Other than simply using compile-time functions, and dropping the object interface as Alex suggests, the easiest thing I can recommend is wrapping representation into a casting input range such as map: auto b = inputRangeObject(a.representation.map!(b => ubyte(b))); You can see all this here: https://run.dlang.io/is/1E6Uqj -Steve |
November 08, 2018 Re: Creating InputRanges from strings, files etc. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Thursday, 8 November 2018 at 16:41:50 UTC, Steven Schveighoffer wrote:
> I did this in a run.dlang.org playground:
>
> pragma(msg, ElementType!(typeof(b)));
> pragma(msg, ElementType!(typeof(d)));
>
> I get:
> immutable(ubyte)
> ubyte
>
> Which means they aren't the same type, and they don't define the same interface (InputRange!(ubyte) is not the same as InputRange!(immutable(ubyte)) ).
>
> Other than simply using compile-time functions, and dropping the object interface as Alex suggests, the easiest thing I can recommend is wrapping representation into a casting input range such as map:
>
> auto b = inputRangeObject(a.representation.map!(b => ubyte(b)));
>
> You can see all this here:
>
> https://run.dlang.io/is/1E6Uqj
>
> -Steve
Thanks, guys, those are helpful pointers.
|
Copyright © 1999-2021 by the D Language Foundation