www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - range properties that work in foreach

reply Michael Rynn <michaelrynn optusnet.com.au> writes:
On the D2 online pages 
(http://www.digitalmars.com/d/2.0/statement.html#ForeachStatement)there 
is 

Foreach over Structs and Classes with Ranges


My question is , is there a working example of  foreach ( e ; range )?


Iteration over struct and class objects can be done with ranges, which 
means the following properties must be defined:


Property		Purpose
.empty			returns true if no more elements
.next			move the left edge of the range right one
.retreat		move the right edge of the range left one
.head			return the leftmost element of the range
.toe			return the rightmost element of the range


So I tried this , but foreach did not work, but using 
the equivalent for loop code did.



List test;
/// this worked
for (auto __r = list.range ; !__r.empty; __r.next)
{   auto e = __r.head;
   ...
}

/// this didn't
foreach( e ; list.range (

Below is the template code , which otherwise worked.

Since I have had no advantage to using names head, toe, next, retreat 
(are these still supposedly the names to use?  "retreat" is a strange 
one.  Perhaps "runaway" would be better. ) I changed them. to front, 
back, popFront, popBack. 


struct linkrange(P) {
    P left_;
    P right_;

    this(P n)
    {
        left_ = n;
        right_ = (n !is null) ? n.prev_ : null;
    }

    /// Range property
     property bool empty()
    {
        return (left_ is null);
    }
    /// Range property
     property P front()
    {
        return left_;
    }
    /// Range property
     property P back()
    {
        return right_;
    }
    /// Range function
     property void popFront()
    {

        if (left_ == right_)
        {
            left_ = null;
            right_ = null;
        }
        else
            left_ = left_.next_;

    }
    /// Range function
     property void popBack()
    {

        if (right_ == left_)
        {
            left_ = null;
            right_ = null;
        }
        else
            right_ = right_.prev_;
    }
}


/// Embed this to provide the linked list manager.
struct linklist(P) {
    P  head_;
    size_t   linkct_;

    void clear()
    {
        head_ = null;
        linkct_ = 0;
    }


    ref linklist opAssign(ref linklist K)
    {
        head_ = K.head_;
        linkct_ = K.linkct_;
        return this;
    }

     property
    bool empty()
    {
        return (head_ is null);
    }

     property
    linkrange!(P) range()
    {
        return linkrange!(P)(head_);
    }

     property P front()
    {
        return head_;
    }

     property size_t length()
    {
        return linkct_;
    }

    private void linkFirst(P n)
    {
        head_ = n;
        n.next_ = n;
        n.prev_ = n;
    }
    private void linkBefore(P n, P f)
    {
        P last = f.prev_;
        n.next_ = f;
        n.prev_ = last;

        f.prev_ = n;
        last.next_ = n;

        linkct_++;
    }
    void putBack(P n)
    {
        if (head_ !is null)
            linkBefore(n, head_);
        else
            linkFirst(n);
    }

    void putFront(P n)
    {
        if (head_ !is null)
        {
            linkBefore(n, head_);
            head_ = n;
        }
        else{
            linkFirst(n);
        }
    }
    void popBack()
    {
        remove(head_.prev_);
    }

    void popFront()
    {
        remove(head_);
    }
    void remove(P n)
    {
        if (n == head_)
        {
            P test = n.next_;
            head_ = (head_ != test) ? test : null;
        }

        n.unlink();
    }
}

/// mixin this to provide the links.
/// A more advanced template might provide field naming suffix.

template links(P)
{
    P  prev_;
    P  next_;

    void unlink()
    {
        prev_.next_ = next_;
        next_.prev_ = prev_;
        next_ = null;
        prev_ = null;
    }
}



/// A linked list without embedding the pointers inside the object.

struct QueueList(P) {
    alias QElem* QElemPtr;

    struct QElem {
       this(P val)
       {
           value = val;
       }
       P   value;
       mixin links!(QElemPtr);
    }

    linklist!(QElemPtr) nodes;

     property
    bool empty()
    {
        return nodes.empty;
    }

     property
    P front()
    {
        return nodes.front.value;
    }

    void putFront(P val)
    {
        QElem* e = new QElem(val);
        nodes.putFront(e);
    }
    void putBack(P val)
    {
        QElem* e = new QElem(val);
        nodes.putBack(e);
    }

    void popFront()
    {
        nodes.popFront();
    }
}
Mar 06 2010
next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Michael Rynn wrote:
 On the D2 online pages 
 (http://www.digitalmars.com/d/2.0/statement.html#ForeachStatement)there 
 is 
 
 Foreach over Structs and Classes with Ranges
 
 
 My question is , is there a working example of  foreach ( e ; range )?
 
 
 Iteration over struct and class objects can be done with ranges, which 
 means the following properties must be defined:
 
 
 Property		Purpose
 .empty			returns true if no more elements
 .next			move the left edge of the range right one
 .retreat		move the right edge of the range left one
 .head			return the leftmost element of the range
 .toe			return the rightmost element of the range
 
 
 So I tried this , but foreach did not work, but using 
 the equivalent for loop code did.

Looks like you ran into a piece of hopelessly outdated documentation. The correct names are, in the same order: empty popFront popBack front back Those should work with foreach. -Lars
Mar 06 2010
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Lars T. Kyllingstad wrote:
 Michael Rynn wrote:
 On the D2 online pages 
 (http://www.digitalmars.com/d/2.0/statement.html#ForeachStatement)there 
 is
 Foreach over Structs and Classes with Ranges


 My question is , is there a working example of  foreach ( e ; range )?


 Iteration over struct and class objects can be done with ranges, which 
 means the following properties must be defined:


 Property        Purpose
 .empty            returns true if no more elements
 .next            move the left edge of the range right one
 .retreat        move the right edge of the range left one
 .head            return the leftmost element of the range
 .toe            return the rightmost element of the range


 So I tried this , but foreach did not work, but using the equivalent 
 for loop code did.

Looks like you ran into a piece of hopelessly outdated documentation. The correct names are, in the same order: empty popFront popBack front back Those should work with foreach.

Actually, when I think about it, I think foreach just needs empty, front, and popFront to work. back and popBack are needed for traversing a range in reverse: foreach (elem; retro(range)) { ... } -Lars -Lars
Mar 06 2010
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Lars T. Kyllingstad wrote:
 Looks like you ran into a piece of hopelessly outdated documentation. 
 The correct names are, in the same order:

Thanks, I'll fix.
Mar 07 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 07 Mar 2010 04:29:59 -0500, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Lars T. Kyllingstad wrote:
 Looks like you ran into a piece of hopelessly outdated documentation.  
 The correct names are, in the same order:

Thanks, I'll fix.

I saw you fixed the table, but the examples are still wrong -Steve
Mar 08 2010
prev sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Good range documentation comes from:

http://digitalmars.com/d/2.0/phobos/std_range.html

foreach only requires an Input Range.
Mar 06 2010