Getting a range over a const Container
Artur Skawina
art.08.09 at gmail.com
Thu Jul 19 02:51:08 PDT 2012
On 07/19/12 06:39, Francisco Soulignac wrote:
> it's been a while since this question, and I don't know how to solve
> it either. The following code passes all the test using the last
> version of dmd (2.059).
>
> import std.container, std.algorithm;
>
> //non const case
> void assertequal(T)(SList!(T) l, int[] r) {
> assert(equal(l[], r));
> }
>
> //const case
> void const_assertequal(T)(const SList!(T) l, int[] r) {
> assert(equal(l[], r));
> }
>
> unittest{
> SList!(int) l;
> l.insertFront(2);
> l.insertFront(1);
> assertequal (l, [1,2]);
> assert(!__traits(compiles, const_assertequal(l, [1,2])));
> }
>
> The conflict with the last assertion is that opSplice can't be
> applied to const. So, I looked at the container module, and made a
> minimal example of a list myself (emulating SList).
>
> struct List {
> struct Node {
> Node* next;
> int val;
> }
>
> private Node* first;
>
> struct Range {
> //sorry about "actual", it should have been current
> private Node* actual;
> this(Node* first) {actual = first;}
> @property front() {return actual.val;}
> @property empty() const {return !actual;}
> void popFront() {assert(!empty); actual = actual.next;}
> Range save() {return this;}
> }
> unittest{static assert(isForwardRange!(Range));}
>
> void add(int v) {
> Node * next = first;
> first = new Node;
> first.val = v;
> first.next = next;
> }
>
> Range opSlice() {
> return Range(first);
> }
>
> }
>
> void assertequal(L : List)(L l, int[] r) {
> assert(equal(l[], r));
> }
>
> void assertequal_const(L : List)(L l, int[] r) {
> assert(equal(l[], r));
> }
>
> unittest{
> List l;
> l.add(2);
> l.add(1);
> assert(equal(l[], [1,2]));
> assertequal (l, [1,2]);
> assert(!__traits(compiles, const_assertequal(l, [1,2])));
> }
>
> As far as I know, the problem comes with the transitivity of const.
> In assertequal_const, l.first has type const(Node*), thus it can't
> be converted to Node* in Range's constructor. I can't manage to
> find a workaround here, because l.first will always have type
> const(Node*), but for traversing the list I require to copy l.first
> into some node, say actual, whose type is Node* so that I can move
> it doing actual = actual.next. I would be happy to do
>
> actual = cast(Node*)(l.first)
> actual = actual.next;
>
> but that code is suppose to be undefined, isn't it?
> (http://dlang.org/const3.html : Removing Immutable With A Cast).
>
> So, my question is how can I (correctly) traverse a const SList,
> const DList, etc?
import std.algorithm, std.range;
struct List {
static struct Node {
Node* next;
int val;
}
private Node* first;
static struct Range(E) {
private E* current;
this(FE:const E)(FE* first) {current = first;}
@property front() {return current.val;}
@property empty() const {return !current;}
void popFront() {assert(!empty); current = current.next;}
@property Range save() {return this;}
}
static assert(isForwardRange!(Range!Node));
void add(int v) {
Node * next = first;
first = new Node;
first.val = v;
first.next = next;
}
Range!Node opSlice() { return Range!Node(first); }
Range!(const Node) opSlice() const { return Range!(const Node)(first); }
}
void assertequal(L : List)(L l, int[] r) {
assert(equal(l[], r));
}
void assertequal_const(L : List)(const L l, int[] r) {
assert(equal(l[], r));
}
void main() {
List l;
l.add(2);
l.add(1);
assert(equal(l[], [1,2]));
assertequal (l, [1,2]);
assertequal_const(l, [1,2]);
}
artur
More information about the Digitalmars-d-learn
mailing list