On Saturday, November 07, 2015 13:52:26 Spacen Jasset via Digitalmars-d-learn wrote: > Thanks Jonathan. I don't quite see what I want to do though. > > In order to abstract the file aspect of things away, and deal > with a stream of chars that could be from a file, or some some > other source would I use a range? > > what I am after is a replacement for InputStream, I don't really > want to directly use File in most places. > > So far I have this, and it seems to work, but it doesn't seem > right: > > this(InputRange)(InputRange input) > { > > int line_no = 1; > foreach (char[] line; input.byLine()) { > ... > > I have a used a template, because I cannot directly use the > InputRange(char) interface as a type, and auto won't work either, > so is there another parameter type I can use, such that I can > have the concept of an abstract stream of bytes.
If your function accepts a range, then it's pretty much a guarantee that it's going to be templated. std.range does define interfaces for the basic types of ranges, but almost all ranges are structs, and what range types typically look like when you start chaining them means that you pretty much never want to type them out (or they're Voldemort types, in which case you _can't_ type them out). typeof can be used to get around that, but it's still ugly. So, you're not normally going to have non-templated code accepting a range type which could come from who-knows-where. Rather, you'd do something like auto myFunc(R)(R range) if(isInputRange!R && is(ElementType!R == dchar)) { } in which case the function will accept any range of dchar without caring where it came from. But it does mean that the function is templated. If you want a range of characters from a file, you have the three options that I listed before. 1. You can use std.stdio.File. Nothing from it will give you a range of characters directly (rather, it's going to give you a range of lines or chunks), but you can get a range of charaters from that. e.g. auto file = File("myfile.txt"); auto range = file.byLineCopy(KeepTerminator.yes).joiner(); The result is a range of dchar that can be passed to any function that accepts a range of dchar, and those functions won't care about where those characters came from - but they will need to be templated. Note that you'd want byLineCopy, not byLine, since you're not using it in a for loop, and byLine reuses its buffer, which doesn't usually work very well with anything other than a for loop. 2. You can use std.file.read or std.file.readText. e.g. string text = std.file.readText("myfile.txt"); This will read the entire file in at once (so if you were looking for streams, this probably isn't what you want), but you do then have a string that you can pass to any code that accepts a string or a range of dchar without caring about where that string came from, and it does mean that you can avoid templating your code and just have it accept string if that's what you'd prefer. 3. You can use std.mmfile.MmFile to mmap the file. e.g. auto mmFile = new MmFile("foo.txt"); auto text = cast(const(char)[])mmFile[]; This will only read the file into memory as you read the memory that now refers to it, but you have an array to process like you'd get with readText. So, it can be used as a range of dchar (though not a string, since the data isn't actually immutable - even though the file is opened as read-only by default - since another process could edit the file while you're reading it). https://en.wikipedia.org/wiki/Mmap Whether mmap or byLineCopy would be faster probably depends on what you're doing, whereas readText is the easiest to use but does require that you read the whole file in at once. - Jonathan M Davis