Skip to content

Commit 78d0cf1

Browse files
author
blake2-ppc
committed
dlist: Factor out pop and push operations by list node
Factor out internal methods for pop/push ~Node<T>, This allows moving nodes instead of destructuring and allocating new. Make use of this in .merge() so that it requires no allocations when merging two DList.
1 parent 5336bdc commit 78d0cf1

File tree

1 file changed

+104
-54
lines changed

1 file changed

+104
-54
lines changed

src/libextra/dlist.rs

Lines changed: 104 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ impl<T> Clone for Rawlink<T> {
102102
}
103103
}
104104

105+
impl<T> Node<T> {
106+
fn new(v: T) -> Node<T> {
107+
Node{value: v, next: None, prev: Rawlink::none()}
108+
}
109+
}
110+
105111
/// Set the .prev field on `next`, then return `Some(next)`
106112
fn link_with_prev<T>(mut next: ~Node<T>, prev: Rawlink<Node<T>>) -> Link<T> {
107113
next.prev = prev;
@@ -131,6 +137,66 @@ impl<T> Mutable for DList<T> {
131137
}
132138
}
133139

140+
// private methods
141+
impl<T> DList<T> {
142+
/// Add a Node first in the list
143+
#[inline]
144+
fn push_front_node(&mut self, mut new_head: ~Node<T>) {
145+
match self.list_head {
146+
None => {
147+
self.list_tail = Rawlink::some(new_head);
148+
self.list_head = link_with_prev(new_head, Rawlink::none());
149+
}
150+
Some(ref mut head) => {
151+
new_head.prev = Rawlink::none();
152+
head.prev = Rawlink::some(new_head);
153+
util::swap(head, &mut new_head);
154+
head.next = Some(new_head);
155+
}
156+
}
157+
self.length += 1;
158+
}
159+
160+
/// Remove the first Node and return it, or None if the list is empty
161+
#[inline]
162+
fn pop_front_node(&mut self) -> Option<~Node<T>> {
163+
do self.list_head.take().map_consume |mut front_node| {
164+
self.length -= 1;
165+
match front_node.next.take() {
166+
Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
167+
None => self.list_tail = Rawlink::none()
168+
}
169+
front_node
170+
}
171+
}
172+
173+
/// Add a Node last in the list
174+
#[inline]
175+
fn push_back_node(&mut self, mut new_tail: ~Node<T>) {
176+
match self.list_tail.resolve() {
177+
None => return self.push_front_node(new_tail),
178+
Some(tail) => {
179+
self.list_tail = Rawlink::some(new_tail);
180+
tail.next = link_with_prev(new_tail, Rawlink::some(tail));
181+
}
182+
}
183+
self.length += 1;
184+
}
185+
186+
/// Remove the last Node and return it, or None if the list is empty
187+
#[inline]
188+
fn pop_back_node(&mut self) -> Option<~Node<T>> {
189+
do self.list_tail.resolve().map_consume |tail| {
190+
self.length -= 1;
191+
self.list_tail = tail.prev;
192+
match tail.prev.resolve() {
193+
None => self.list_head.take_unwrap(),
194+
Some(tail_prev) => tail_prev.next.take_unwrap()
195+
}
196+
}
197+
}
198+
}
199+
134200
impl<T> Deque<T> for DList<T> {
135201
/// Provide a reference to the front element, or None if the list is empty
136202
#[inline]
@@ -156,66 +222,32 @@ impl<T> Deque<T> for DList<T> {
156222
self.list_tail.resolve().map_mut(|tail| &mut tail.value)
157223
}
158224

159-
/// Add an element last in the list
225+
/// Add an element first in the list
160226
///
161227
/// O(1)
162-
fn push_back(&mut self, elt: T) {
163-
match self.list_tail.resolve() {
164-
None => return self.push_front(elt),
165-
Some(tail) => {
166-
let mut new_tail = ~Node{value: elt, next: None, prev: self.list_tail};
167-
self.list_tail = Rawlink::some(new_tail);
168-
tail.next = Some(new_tail);
169-
}
170-
}
171-
self.length += 1;
228+
fn push_front(&mut self, elt: T) {
229+
self.push_front_node(~Node::new(elt))
172230
}
173231

174-
/// Remove the last element and return it, or None if the list is empty
232+
/// Remove the first element and return it, or None if the list is empty
175233
///
176234
/// O(1)
177-
fn pop_back(&mut self) -> Option<T> {
178-
do self.list_tail.resolve().map_consume |tail| {
179-
self.length -= 1;
180-
self.list_tail = tail.prev;
181-
match tail.prev.resolve() {
182-
None => self.list_head.take_unwrap().value,
183-
Some(tail_prev) => tail_prev.next.take_unwrap().value
184-
}
185-
}
235+
fn pop_front(&mut self) -> Option<T> {
236+
self.pop_front_node().map_consume(|~Node{value, _}| value)
186237
}
187238

188-
/// Add an element first in the list
239+
/// Add an element last in the list
189240
///
190241
/// O(1)
191-
fn push_front(&mut self, elt: T) {
192-
let mut new_head = ~Node{value: elt, next: None, prev: Rawlink::none()};
193-
match self.list_head {
194-
None => {
195-
self.list_tail = Rawlink::some(new_head);
196-
self.list_head = Some(new_head);
197-
}
198-
Some(ref mut head) => {
199-
head.prev = Rawlink::some(new_head);
200-
util::swap(head, &mut new_head);
201-
head.next = Some(new_head);
202-
}
203-
}
204-
self.length += 1;
242+
fn push_back(&mut self, elt: T) {
243+
self.push_back_node(~Node::new(elt))
205244
}
206245

207-
/// Remove the first element and return it, or None if the list is empty
246+
/// Remove the last element and return it, or None if the list is empty
208247
///
209248
/// O(1)
210-
fn pop_front(&mut self) -> Option<T> {
211-
do self.list_head.take().map_consume |~Node{value, next, _}| {
212-
self.length -= 1;
213-
match next {
214-
Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
215-
None => self.list_tail = Rawlink::none()
216-
}
217-
value
218-
}
249+
fn pop_back(&mut self) -> Option<T> {
250+
self.pop_back_node().map_consume(|~Node{value, _}| value)
219251
}
220252
}
221253

@@ -289,7 +321,7 @@ impl<T> DList<T> {
289321
if take_a {
290322
it.next();
291323
} else {
292-
it.insert_next(other.pop_front().unwrap());
324+
it.insert_next_node(other.pop_front_node().unwrap());
293325
}
294326
}
295327
}
@@ -433,25 +465,34 @@ pub trait ListInsertion<A> {
433465
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A>;
434466
}
435467

436-
impl<'self, A> ListInsertion<A> for MutDListIterator<'self, A> {
437-
fn insert_next(&mut self, elt: A) {
438-
// Insert an element before `self.head` so that it is between the
468+
// private methods for MutDListIterator
469+
impl<'self, A> MutDListIterator<'self, A> {
470+
fn insert_next_node(&mut self, mut ins_node: ~Node<A>) {
471+
// Insert before `self.head` so that it is between the
439472
// previously yielded element and self.head.
473+
//
474+
// The inserted node will not appear in further iteration.
440475
match self.head.resolve() {
441-
None => { self.list.push_back(elt); }
476+
None => { self.list.push_back_node(ins_node); }
442477
Some(node) => {
443478
let prev_node = match node.prev.resolve() {
444-
None => return self.list.push_front(elt),
479+
None => return self.list.push_front_node(ins_node),
445480
Some(prev) => prev,
446481
};
447-
let mut ins_node = ~Node{value: elt, next: None, prev: Rawlink::none()};
448482
let node_own = prev_node.next.take_unwrap();
449483
ins_node.next = link_with_prev(node_own, Rawlink::some(ins_node));
450484
prev_node.next = link_with_prev(ins_node, Rawlink::some(prev_node));
451485
self.list.length += 1;
452486
}
453487
}
454488
}
489+
}
490+
491+
impl<'self, A> ListInsertion<A> for MutDListIterator<'self, A> {
492+
#[inline]
493+
fn insert_next(&mut self, elt: A) {
494+
self.insert_next_node(~Node::new(elt))
495+
}
455496

456497
#[inline]
457498
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A> {
@@ -929,7 +970,6 @@ mod tests {
929970
m.push(0);
930971
}
931972
}
932-
933973
#[bench]
934974
fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
935975
let mut m = DList::new::<int>();
@@ -947,6 +987,16 @@ mod tests {
947987
}
948988
}
949989

990+
#[bench]
991+
fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
992+
let mut m = DList::new::<int>();
993+
do b.iter {
994+
m.push_front(0);
995+
m.pop_front();
996+
}
997+
}
998+
999+
9501000
#[bench]
9511001
fn bench_iter(b: &mut test::BenchHarness) {
9521002
let v = &[0, ..128];

0 commit comments

Comments
 (0)