Skip to content

RFC: Replace DList with an owned doubly-linked list, Add trait Deque #7652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed

Conversation

bluss
Copy link
Member

@bluss bluss commented Jul 8, 2013

This is a new doubly-linked list using owned nodes. In the forward direction, the list is linked with owned pointers, and the backwards direction is linked with &'static Node pointers.

This intends to replace the previous extra::DList that was using managed nodes and also featured freestanding nodes. The new List does not give access to the nodes, but means to implement all relevant linked-list methods.

The list supports pop_back, push_back, pop_front, push_front, front, back, iter, mut_iter, +more iterators, append, insert_ordered, and merge.

  • Add a trait Deque for double ended sequences.
  • Both List and Deque implement this trait. Rename Deque to ArrayDeque.

The text has been updated to summarize resolved items

RFC Topics

Resolved

  • Should be in extra
  • Representation for the backlinks

Container Method Names and Trait Names and Type Names

  • Location and name of trait extra::collection::Deque?
  • Name of the ring buffer extra::deque::ArrayDeque ?
  • Name of the doubly linked list extra::dlist::List ?

For container methods I think we have two options:

Should we use pop_front() -> Option<T> or pop_front() -> T ?

Benchmarks

Some basic bench numbers for List vs. Vec, Deque and old DList

This List implementation's performance is dominated by the allocation of Nodes required when pushing.

Iterate (by-ref) collection of 128 elements

test test_bench::bench_iter ... bench: 198 ns/iter (+/- 0)
test test_bench::bench_iter_mut ... bench: 294 ns/iter (+/- 0)
test test_bench::bench_iter_rev ... bench: 198 ns/iter (+/- 0)
test test_bench::bench_iter_mut_rev ... bench: 198 ns/iter (+/- 3)

test test_bench::bench_iter_vec ... bench: 101 ns/iter (+/- 0)
test test_bench::bench_iter_deque ... bench: 581 ns/iter (+/- 0)
test test_bench::bench_iter_dlist ... bench: 9262 ns/iter (+/- 273)

Sequence of .push(elt), .pop() or equivalent at the tail end

test test_bench::bench_push_back_pop_back ... bench: 72 ns/iter (+/- 0)

test test_bench::bench_push_back_pop_back_vec ... bench: 5 ns/iter (+/- 0)
test test_bench::bench_push_back_pop_back_deque ... bench: 15 ns/iter (+/- 0)
test test_bench::bench_push_back_pop_back_dlist ... bench: 234 ns/iter (+/- 0)

@thestinger
Copy link
Contributor

Using &'static Node pointers for backlinks creates an infinite loop when you use fmt!("%?"). Using raw pointers is just as easy, but Option<*Node> is 16 bytes while Option<&'static Node> is only 8.

You can use *Node, the reason it's 16 bytes is that it's already nullable. It's okay if %? is broken though because it shouldn't be usable on private fields without unsafe, and it's already broken on managed pointer graphs with cycles.

@brson
Copy link
Contributor

brson commented Jul 8, 2013

IMO, Not std. The bar for std is high. If something can live outside it, it should.

}
}

#[cfg(test)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are traditionally all placed inside of a #[cfg(test)] module. This allows things like unused imports for the normal code, but used in tests, to be coralled into one area.

@bluss
Copy link
Member Author

bluss commented Jul 10, 2013

Added the trait Deque that fits both the list and Deque. The problem arises that should the type or the trait have that name?

blake2-ppc added 12 commits July 11, 2013 15:52
This is an owned sendable linked list which allows insertion and
deletion at both ends, with fast traversal through iteration, and fast
append/prepend.

It is indended to replace the previous managed DList with exposed list
nodes. It does not match it feature by feature, but DList could grow
more methods if needed.
Rawlink<T> holds a *mut T pointer and can convert itself to Option<&mut T>.
The null pointer is of course None.
The exception is the function check_links which needs access to struct
Node (which is not pub).
An iterator that allows mutating the list is very useful but needs care
to not be unsound. ListIteration exposes only insert_before (used for
insert_ordered) and peek_next so far.
Let RingBuf have a logical name for a concrete type, and Deque is
used for the Deque trait (implemented by RingBuf and dlist).
@bluss
Copy link
Member Author

bluss commented Jul 11, 2013

Rebased (conflict with the minor change in uint::max -> num::max).

Thanks to @alexcrichton for the useful comments that should all be resolved. There was a reason given for the single test function outside the test module — it needs to use struct Node which is not pub.

Now ready for review & merge.

We have

  • trait extra::collection::Deque
  • extra::ringbuf::RingBuf is the new name of former deque::Deque
  • extra::dlist::DList is the new owned doubly-linked list.

bors added a commit that referenced this pull request Jul 11, 2013
This is a new doubly-linked list using owned nodes. In the forward direction, the list is linked with owned pointers, and the backwards direction is linked with &'static Node pointers.

This intends to replace the previous extra::DList that was using managed nodes and also featured freestanding nodes.  The new List does not give access to the nodes, but means to implement all relevant linked-list methods.
 
The list supports pop_back, push_back, pop_front, push_front, front, back, iter, mut_iter, +more iterators,  append, insert_ordered, and merge.

* Add a trait Deque for double ended sequences.

* Both List and Deque implement this trait. Rename Deque to ArrayDeque.

*The text has been updated to summarize resolved items*

## RFC Topics

### Resolved

* Should be in extra
* Representation for the backlinks

### Container Method Names and Trait Names and Type Names

* Location and name of trait `extra::collection::Deque`?
* Name of the ring buffer `extra::deque::ArrayDeque` ?
* Name of the doubly linked list `extra::dlist::List` ?

For container methods I think we have two options:

* Align with the existing methods on the vector. That would be `.push()`, `.pop()`, `.shift()`, `.unshift()`.
* Use the API described in https://github.com/mozilla/rust/wiki/Containers   Obviously that's the way List is written right now.

Should we use `pop_front() -> Option<T>` or `pop_front() -> T` ?

### Benchmarks

Some basic bench numbers for List vs. Vec, Deque and *old DList*

This List implementation's performance is dominated by the allocation of Nodes required when pushing. 

Iterate (by-ref) collection of 128 elements

    test test_bench::bench_iter ... bench: 198 ns/iter (+/- 0)
    test test_bench::bench_iter_mut ... bench: 294 ns/iter (+/- 0)
    test test_bench::bench_iter_rev ... bench: 198 ns/iter (+/- 0)
    test test_bench::bench_iter_mut_rev ... bench: 198 ns/iter (+/- 3)

    test test_bench::bench_iter_vec ... bench: 101 ns/iter (+/- 0)
    test test_bench::bench_iter_deque ... bench: 581 ns/iter (+/- 0)
    test test_bench::bench_iter_dlist ... bench: 9262 ns/iter (+/- 273)

Sequence of `.push(elt)`, `.pop()` or equivalent at the tail end

    test test_bench::bench_push_back_pop_back ... bench: 72 ns/iter (+/- 0)

    test test_bench::bench_push_back_pop_back_vec ... bench: 5 ns/iter (+/- 0)
    test test_bench::bench_push_back_pop_back_deque ... bench: 15 ns/iter (+/- 0)
    test test_bench::bench_push_back_pop_back_dlist ... bench: 234 ns/iter (+/- 0)
@bors bors closed this Jul 11, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants