www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can't call splitter with range struct

reply David Skluzacek <david.skluzacek gmail.com> writes:
I came across this problem as I was trying to see if could write 
a quick range-based solution with std.zlib to do what was asked 
about in a different Learn forum post - read a gzipped file.

This seems like it should work:

import std.stdio, std.algorithm, std.zlib;
import std.range.primitives;

void main(string[] args)
{
     auto f = GZippedFile(File(args[1], "rb"));
     f.splitter("\n").each!writeln;
}

struct GZippedFile
{
     File file;
     UnCompress uncompressor;
     ubyte[] readBuffer;
     const(char)[] buffer;

     this(File f) {
         file = f;
         uncompressor = new UnCompress(HeaderFormat.gzip);
         readBuffer = new ubyte[4096];
     }

     dchar front() const {
         return buffer.front;
     }

     void popFront() {
         if (buffer.empty) {
             buffer = cast(const(char)[])
                 uncompressor.uncompress(file.rawRead(readBuffer));
         }
         else {
             buffer.popFront();
         }
     }

     bool empty() {
         return buffer.empty && file.eof();
     }
}

But I get:

Error: template std.algorithm.iteration.splitter cannot deduce 
function from argument types !()(GZippedFile, string), candidates 
are:
/usr/include/dlang/dmd/std/algorithm/iteration.d(4678):        
splitter(alias pred = "a == b", Range, Separator)(Range r, 
Separator s)
   with pred = "a == b",
        Range = GZippedFile,
        Separator = string
   must satisfy the following constraint:
        is(typeof(binaryFun!pred(r.front, s)) : bool)
(...)

If I change the newline separator to a character literal, I get:

(...)
/usr/include/dlang/dmd/std/algorithm/iteration.d(5055):        
splitter(alias pred = "a == b", Range, Separator)(Range r, 
Separator s)
   with pred = "a == b",
        Range = GZippedFile,
        Separator = char
   must satisfy the following constraint:
        is(typeof(binaryFun!pred(r.front, s.front)) : bool)

It seems like "\n" should pass the second constraint and '\n' 
should pass the first.  Using a dchar or dstring makes no 
difference. Adding  property to front makes no difference. Is 
this a bug?
Mar 15 2021
parent reply drug <drug2004 bk.ru> writes:
On 3/16/21 1:58 AM, David Skluzacek wrote:
 Error: template std.algorithm.iteration.splitter cannot deduce 
function from argument types !()(GZippedFile, string), candidates are:
 /usr/include/dlang/dmd/std/algorithm/iteration.d(4678): 
splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
    with pred = "a == b",
         Range = GZippedFile,
         Separator = string
    must satisfy the following constraint:
         is(typeof(binaryFun!pred(r.front, s)) : bool)
That means that you should be able to call your predicate ("a == b") with GZippedFile.front and separator as arguments (they are dchar and string respectively)
 (...)

 If I change the newline separator to a character literal, I get:

 (...)
 /usr/include/dlang/dmd/std/algorithm/iteration.d(5055): 
splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
    with pred = "a == b",
         Range = GZippedFile,
         Separator = char
    must satisfy the following constraint:
         is(typeof(binaryFun!pred(r.front, s.front)) : bool)

 It seems like "\n" should pass the second constraint and '\n' should 
pass the first. Using a dchar or dstring makes no difference. Adding property to front makes no difference. Is this a bug?

Also there are other constraints (see https://run.dlang.io/is/rcSJJf)
like:
/dlang/ldc-1.25.1/bin/../import/std/algorithm/iteration.d(5055): 
splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s)
   with pred = "a == b",
        Range = GZippedFile,
        Separator = string
   must satisfy one of the following constraints:
        hasSlicing!Range
        isNarrowString!Range

That means that you GZippedRange should provide opSlice operator and 
should be a narrow string (string of char or wchar)
Mar 16 2021
parent David Skluzacek <david.skluzacek gmail.com> writes:
On Tuesday, 16 March 2021 at 07:43:18 UTC, drug wrote:
 That means that you GZippedRange should provide opSlice 
 operator and should be a narrow string (string of char or wchar)
Yes, I should have looked more carefully at the doc, I was assuming splitter would accept a simple input range, but it doesn't. I really didn't want to provide opSlice because then if it were called with an index higher than the length of the buffer I'd have to read more data and allocate memory to hold it. I'm not actually trying to do this any more though. Thanks.
Mar 16 2021