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