| Thread overview | |||||||||
|---|---|---|---|---|---|---|---|---|---|
|
September 05, 2020 chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
The following code won't compile:
----
import std.algorithm;
import std.range;
import std.stdio;
void main() {
auto v = [2,4,8,3,6,9,1,5,7];
foreach(i; 2..4) {
writeln(v.myChunkBy!((a,b)=>a%i==b%i));
}
}
----
/opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main
----
Is this expected behavior?
I can get it to run as expected by modifying the source of chunkBy as follows:
----
import std.range;
import std.stdio;
import std.traits;
import std.functional;
private template ChunkByImplIsUnary(alias pred, Range)
{
alias e = lvalueOf!(ElementType!Range);
static if (is(typeof(binaryFun!pred(e, e)) : bool))
enum ChunkByImplIsUnary = false;
else static if (is(typeof(unaryFun!pred(e) == unaryFun!pred(e)) : bool))
enum ChunkByImplIsUnary = true;
else
static assert(0, "chunkBy expects either a binary predicate or "~
"a unary predicate on range elements of type: "~
ElementType!Range.stringof);
}
// Outer range
struct Impl(Range)
{
size_t groupNum;
Range current;
Range next;
}
// Inner range
struct Group(alias eq, Range)
{
import std.typecons : RefCounted;
private size_t groupNum;
private Range start;
private Range current;
private RefCounted!(Impl!Range) mothership;
this(RefCounted!(Impl!Range) origin)
{
groupNum = origin.groupNum;
start = origin.current.save;
current = origin.current.save;
assert(!start.empty, "Passed range 'r' must not be empty");
mothership = origin;
// Note: this requires reflexivity.
assert(eq(start.front, current.front),
"predicate is not reflexive");
}
@property bool empty() { return groupNum == size_t.max; }
@property auto ref front() { return current.front; }
void popFront()
{
current.popFront();
// Note: this requires transitivity.
if (current.empty || !eq(start.front, current.front))
{
if (groupNum == mothership.groupNum)
{
// If parent range hasn't moved on yet, help it along by
// saving location of start of next Group.
mothership.next = current.save;
}
groupNum = size_t.max;
}
}
@property auto save()
{
auto copy = this;
copy.current = current.save;
return copy;
}
}
private struct ChunkByImpl(alias pred, Range)
if (isForwardRange!Range)
{
import std.typecons : RefCounted;
enum bool isUnary = ChunkByImplIsUnary!(pred, Range);
static if (isUnary)
alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b));
else
alias eq = binaryFun!pred;
static assert(isForwardRange!(Group!(eq,Range)));
private RefCounted!(Impl!Range) impl;
this(Range r)
{
impl = RefCounted!(Impl!Range)(0, r, r.save);
}
@property bool empty() { return impl.current.empty; }
@property auto front()
{
static if (isUnary)
{
import std.typecons : tuple;
return tuple(unaryFun!pred(impl.current.front), Group(impl));
}
else
{
return Group!(eq,Range)(impl);
}
}
void popFront()
{
// Scan for next group. If we're lucky, one of our Groups would have
// already set .next to the start of the next group, in which case the
// loop is skipped.
while (!impl.next.empty && eq(impl.current.front, impl.next.front))
{
impl.next.popFront();
}
impl.current = impl.next.save;
// Indicate to any remaining Groups that we have moved on.
impl.groupNum++;
}
@property auto save()
{
// Note: the new copy of the range will be detached from any existing
// satellite Groups, and will not benefit from the .next acceleration.
return typeof(this)(impl.current.save);
}
static assert(isForwardRange!(typeof(this)), typeof(this).stringof
~ " must be a forward range");
}
auto chunkBy(alias pred, Range)(Range r)
if (isInputRange!Range)
{
return ChunkByImpl!(pred, Range)(r);
}
void main() {
auto v = [2,4,8,3,6,9,1,5,7];
foreach(i; 2..4) {
writeln(v.chunkBy!((a,b)=>a%i==b%i));
}
}
---
| ||||
September 05, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JG | Sorry for posting to general. I meant to post to learn. | |||
September 04, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JG | On Sat, Sep 05, 2020 at 03:30:33AM +0000, JG via Digitalmars-d wrote:
> The following code won't compile:
> ----
> import std.algorithm;
> import std.range;
> import std.stdio;
>
> void main() {
> auto v = [2,4,8,3,6,9,1,5,7];
> foreach(i; 2..4) {
> writeln(v.myChunkBy!((a,b)=>a%i==b%i));
> }
> }
> ----
> /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function
> tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot
> access frame of function D main
> ----
[...]
Are you using LDC? IIRC there was a recent bug fixed in dmd that fixes this problem in some cases, but LDC still has this bug. Maybe try with dmd to see if it works?
--T
| |||
September 05, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Saturday, 5 September 2020 at 04:10:58 UTC, H. S. Teoh wrote:
> On Sat, Sep 05, 2020 at 03:30:33AM +0000, JG via Digitalmars-d wrote:
>> The following code won't compile:
>> ----
>> import std.algorithm;
>> import std.range;
>> import std.stdio;
>>
>> void main() {
>> auto v = [2,4,8,3,6,9,1,5,7];
>> foreach(i; 2..4) {
>> writeln(v.myChunkBy!((a,b)=>a%i==b%i));
>> }
>> }
>> ----
>> /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function
>> tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot
>> access frame of function D main
>> ----
> [...]
>
> Are you using LDC? IIRC there was a recent bug fixed in dmd that fixes this problem in some cases, but LDC still has this bug. Maybe try with dmd to see if it works?
>
>
> --T
Thanks for your reply. I was getting the same error with both dmd and ldc, I will try updating. For clarity do you know what precisely is causing the problem? My "fix" was to un-nest the structs used in chunkBy. Was the bug in dmd, something to do with nested structs?
| |||
September 06, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JG | On Sat, Sep 05, 2020 at 11:14:08AM +0000, JG via Digitalmars-d wrote: [...] > Thanks for your reply. I was getting the same error with both dmd and ldc, I will try updating. For clarity do you know what precisely is causing the problem? My "fix" was to un-nest the structs used in chunkBy. Was the bug in dmd, something to do with nested structs? The problem was caused by nested structs needing a context pointer, and an alias function parameter also needing a context pointer. Older versions of dmd could only handle 1 context pointer at a time, so was unable to handle this case. T -- Some ideas are so stupid that only intellectuals could believe them. -- George Orwell | |||
September 06, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to JG | On Saturday, 5 September 2020 at 03:30:33 UTC, JG wrote: > The following code won't compile: > ---- > import std.algorithm; > import std.range; > import std.stdio; > > void main() { > auto v = [2,4,8,3,6,9,1,5,7]; > foreach(i; 2..4) { > writeln(v.myChunkBy!((a,b)=>a%i==b%i)); > } > } > ---- > /opt/local/include/phobos/std/algorithm/iteration.d(2009): Error: function tmp.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access frame of function D main > ---- > > Is this expected behavior? No. > I can get it to run as expected by modifying the source of chunkBy as follows: It's hard to read this and compare against the original implementation here. If this issue still persists with master, why don't you simply open a PR for Phobos? Bug fixes are always welcome! | |||
September 07, 2020 Re: chunkBy bug? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Seb | On Sunday, 6 September 2020 at 17:08:06 UTC, Seb wrote: > It's hard to read this and compare against the original implementation here. > If this issue still persists with master, why don't you simply open a PR for Phobos? > Bug fixes are always welcome! I compiled dmd and phobos from source. Using the same code as before: ---- import std.algorithm; import std.range; import std.stdio; void main() { auto v = [2,4,8,3,6,9,1,5,7]; foreach(i; 2..4) { writeln(v.myChunkBy!((a,b)=>a%i==b%i)); } } ---- and compiling with the new version of dmd produces: ../../dlang/dmd/generated/osx/release/64/../../../../../phobos/std/algorithm/iteration.d(2058): Error: function chunkByFix.main.ChunkByImpl!(__lambda1, int[]).ChunkByImpl.Group.popFront cannot access delegate __lambda1 in frame of function D main I will see if I can figure out how to attempt a PR for phobos. | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply