[Issue 8556] Using take results in a corrupted call to opSlice

d-bugmail at puremagic.com d-bugmail at puremagic.com
Tue Oct 9 21:16:19 PDT 2012


http://d.puremagic.com/issues/show_bug.cgi?id=8556



--- Comment #4 from Jonathan M Davis <jmdavisProg at gmx.com> 2012-10-09 20:52:16 PDT ---
Okay. Here's a test case which does not rely on either take, takeExactly or
hasSlicing (since they will likely be changed soon so that they don't have a
circular dependency, fixing the immediate problem in Phobos but not fixing the
compiler bug):

import std.algorithm;
import std.range;
import std.stdio;
import std.string;
import std.traits;

template isSliceable(R)
{
    enum bool isSliceable = !isNarrowString!R && is(typeof(
    (inout int _dummy=0)
    {
        R r = void;
        auto s = r[1 .. 2];
        static assert(isInputRange!(typeof(s)));
    }));
}

struct Grab(Range)
if (isInputRange!(Unqual!Range)
        && !(isSliceable!(Unqual!Range) || is(Range T == Grab!T)))
{
    private alias Unqual!Range R;

    // User accessible in read and write
    public R source;

    private size_t _maxAvailable;
    private enum bool byRef = is(typeof(&_input.front) == ElementType!(R)*);

    alias R Source;

    @property bool empty()
    {
        return _maxAvailable == 0 || source.empty;
    }

    @property auto ref front()
    {
        assert(!empty,
            "Attempting to fetch the front of an empty "
            ~ Grab.stringof);
        return source.front;
    }

    void popFront()
    {
        assert(!empty,
            "Attempting to popFront() past the end of a "
            ~ Grab.stringof);
        source.popFront();
        --_maxAvailable;
    }

    static if (isForwardRange!R)
        @property Grab save()
        {
            return Grab(source.save, _maxAvailable);
        }


    static if (isInfinite!R)
    {
        @property size_t length() const
        {
            return _maxAvailable;
        }

        alias length opDollar;
    }
    else static if (hasLength!R)
    {
        @property size_t length()
        {
            return min(_maxAvailable, source.length);
        }

        alias length opDollar;
    }
}

Grab!R grab(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && isSliceable!(Unqual!R))
{
    static if (hasLength!R)
        return input[0 .. min(n, input.length)];
    else
        return input[0 .. n];
}

Grab!(R) grab(R)(R input, size_t n)
if (is(R T == Grab!T))
{
    return R(input.source, min(n, input._maxAvailable));
}

Grab!R grab(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && !isSliceable!(Unqual!R) && !is(R T == Grab!T))
{
    return Grab!R(input, n);
}

auto grabExactly(R)(R range, size_t n)
if (isInputRange!R && !isSliceable!R)
{
    static if (is(typeof(grabExactly(range._input, n)) == R))
    {
        range._n = n;
        return range;
    }
    else
    {
        static struct Result
        {
            R _input;
            private size_t _n;

            @property bool empty() const { return !_n; }
            @property auto ref front()
            {
                assert(_n > 0, "front() on an empty " ~ Result.stringof);
                return _input.front();
            }
            void popFront() { _input.popFront(); --_n; }
            @property size_t length() const { return _n; }
            alias length opDollar;

            static if (isForwardRange!R)
                @property auto save() { return this; }
        }

        return Result(range, n);
    }
}

auto grabExactly(R)(R range, size_t n)
if (isSliceable!R)
{
    return range[0 .. n];
}

struct Circle(Range)
if (isForwardRange!(Unqual!Range) && !isInfinite!(Unqual!Range))
{
    alias Unqual!Range R;

    R _original;
    size_t _index;

    this(R input, size_t index = 0) { _original = input; _index = index; }

    @property auto ref front()
    {
        return _original[_index % _original.length];
    }

    enum bool empty = false;

    void popFront() { ++_index; }

    auto opSlice(size_t i, size_t j)
    {
        assert(j >= i, format("%s %s %s", i, j, _index));
        writefln("%s %s %s", i, j, _index);
        return grabExactly(typeof(this)(_original.save, _index + i), j - i);
    }
}

Circle!R circle(R)(R input, size_t index = 0)
    if (isRandomAccessRange!(Unqual!R) && !isInfinite!(Unqual!R))
{
    return Circle!R(input, index);
}

void main()
{
    uint[] arr = [1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U];
    auto t = grab(circle(arr), 20);

    auto cx = circle(arr);
    auto slice = cx[23 .. 33];
    assert(equal(slice, [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]), format("%s",
array(slice)));
}

It can probably be reduced further, but that already reduces it a fair bit.
It's been copied from Phobos with the names being tweaked (hasSlicing ->
isSliceable, take -> grab, takeExactly -> grabExactly) and some of the
unnecessary parts stripped out. So, this should provide a reproducible test
case even once hasSlicing and take have been fixed. I believe that the key
thing is the circular dependencies involved.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list