digitalmars.D.learn - Creating InputRanges from strings, files etc.
- Vinay Sajip (9/9) Nov 08 2018 Excuse my ignorance, but from looking at the documentation on
- rikki cattermole (22/30) Nov 08 2018 TLDR of how to write an input range:
- Paul Backus (13/22) Nov 08 2018 You can iterate through a file one ubyte at a time using
- Vinay Sajip (2/14) Nov 08 2018 Aha - inputRangeObject was the thing I was missing. Thanks!
- Vinay Sajip (31/35) Nov 08 2018 I did a bit more digging, and it seems to work for strings but
- Alex (7/43) Nov 08 2018 you could use a template for somefn definition:
- Steven Schveighoffer (19/62) Nov 08 2018 A cool feature of D is to have it tell you something about your code at
- Vinay Sajip (3/20) Nov 08 2018 Thanks, guys, those are helpful pointers.
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.
Nov 08 2018
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); } }
Nov 08 2018
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);
Nov 08 2018
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!
Nov 08 2018
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?
Nov 08 2018
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:you could use a template for somefn definition: ´´´ void somefn(T)(T r) { writeln(format!"%s"(r)); } ´´´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?
Nov 08 2018
On 11/8/18 11:15 AM, Vinay Sajip wrote:On Thursday, 8 November 2018 at 14:38:37 UTC, Paul Backus wrote: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 -SteveTo 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?
Nov 08 2018
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 -SteveThanks, guys, those are helpful pointers.
Nov 08 2018