Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
January 26, 2018 Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
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; } } 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; } } I have a more specific question too: 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? 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? Cheers |
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:
> range.front = false;
> while (!range.empty) {
> range.popFrontN(N);
> range.front = false;
> }
> }
Oops, this should be:
while (!range.empty) {
range.front = false;
range.popFrontN(N);
}
|
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:
> 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?
Where did you see this? That's got to be some very old code; I can't think of any instance where you would not want to use `hasAssignableElements` instead.
|
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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 |
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Friday, 26 January 2018 at 14:59:09 UTC, Simen Kjærås wrote: > 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. Oops again :) Should've been typename N (where N is some integral type). > Not exactly. range.front will assert after the last popFrontN (since the range is empty). Ya, sorry, realized this a bit after I posted. > It's trying to combine 3 and 4 I think, but it fails because this is allowed in D: > > int a; > a = false; Ah true, so it's more of a is(ElementType!R : bool) check? > > You'll want to pass the range as ref. hasLvalueElements checks if the elements have lvalue semantics Doh, of course. It's in the name even! > 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 Thanks for the input! |
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Friday, 26 January 2018 at 14:35:25 UTC, Meta wrote: > On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote: >> 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? > > Where did you see this? That's got to be some very old code; I can't think of any instance where you would not want to use `hasAssignableElements` instead. Seems to occur in https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d eg: https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d#L555 |
January 26, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Friday, 26 January 2018 at 15:33:03 UTC, aliak wrote:
> On Friday, 26 January 2018 at 14:35:25 UTC, Meta wrote:
>> On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:
>>> 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?
>>
>> Where did you see this? That's got to be some very old code; I can't think of any instance where you would not want to use `hasAssignableElements` instead.
>
> Seems to occur in https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d
>
> eg: https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d#L555
The function is called fill, and assigns a value to every element in the range. If a[0] = false compiles, we also want a.fill(false) to compile. It's simply testing that, rather than caring about the exact type of the elements.
--
Simen
|
January 27, 2018 Re: Rewriting a c++ template to D (replacing iterator with ranges "properly") | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Friday, 26 January 2018 at 23:15:41 UTC, Simen Kjærås wrote:
>
> The function is called fill, and assigns a value to every element in the range. If a[0] = false compiles, we also want a.fill(false) to compile. It's simply testing that, rather than caring about the exact type of the elements.
>
> --
> Simen
I see. Yes that makes sense. Thank you.
|
Copyright © 1999-2021 by the D Language Foundation