Thread overview
Can't call splitter with range struct
Mar 15, 2021
David Skluzacek
Mar 16, 2021
drug
Mar 16, 2021
David Skluzacek
March 15, 2021
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?

March 16, 2021
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)
March 16, 2021
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.