On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:
It basically steps through in a stride and sets the checkpoints to false.

C++:
template <typename /*RandomAccessIterator*/ It, int /*Integer*/ N>
void mark(It begin, It end, N step) {
  assert(begin != end)
  *begin = false;
  while (end - begin > step) {
    begin = begin + step;
    *begin = false;
  }
}

what is N here? You're declaring it to be an int value in the template<> definition, and then use it as a type in the function definition.



For D this is what I figured would be the way?

void mark(R, N)(auto ref R range, N step)
if (
  /* 1 */ isIntegral!N
  /* 2 */ && isRandomAccessRange!R
  /* 3 */ && is(ElementType!R == bool)
  /* 4 */ && hasAssignableElements!R
) {
  range.front = false;
  while (!range.empty) {
    range.popFrontN(N);
    range.front = false;
  }
}

Not exactly. range.front will assert after the last popFrontN (since the range is empty).

You'll need something like this:

void main(R, N)(R range, N step)
if (isIntegral!N &&
    isRandomAccessRange!R &&
    is(ElementType!R == bool) &&
    hasAssignableElements!R)
{
    if (range.empty) return;
    do
    {
        range.front = false;
        range.popFrontN(N);
    } while (!range.empty);
}


1) I've seen some phobos code checking for assignability like this:

  is(typeof(range.front = false))

... is that an advantage of that over hasAssignableElements? Or is that just basically combining constraints 3 and 4 which I have above?

It's trying to combine 3 and 4 I think, but it fails because this is allowed in D:

int a;
a = false;


2) Say I wanted to restrict to only lvalue ranges passed in as inputs. Does that mean I use hasLvalueElements as a constraint or is remove the "auto" and just have a ref parameter sufficient?

You'll want to pass the range as ref. hasLvalueElements checks if the elements have lvalue semantics, not if the range itself does. Here's a range that has lvalue elements, for which passing it as ref or non-ref makes a huge difference:

import std.range;

struct R {
    int[3] elements;
    int index;

    ref auto front() {
        return elements[index];
    }

    void popFront() {
        ++index;
    }

    bool empty() {
        return index >= elements.length;
    }
}

unittest {
    assert(hasLvalueElements!(R));
    auto a = R([1,2,3], 0);
    auto b = a;
    b.front = 4;
    assert(a.elements == [1,2,3]);
    assert(b.elements == [4,2,3]);
}

As we can see, b is a complete copy of a, and changing b does not change a. The exact same behavior would occur if a was passed by value to a function.

--
  Simen

Reply via email to