Skip to content

Commit 98f6e40

Browse files
committed
Auto merge of #26050 - bluss:linked-list, r=Gankro
The recent bug that was found in LinkedList reminded me of some general cleanup that's been waiting for some time. - Use a loop from the front in Drop, it works just as well and without an unsafe block - Change Rawlink methods to use `unsafe` in an idiomatic way. This does mean that we need an unsafe block for each dereference of a raw link. Even then, the extent of unsafe-critical code is even larger of course, since safety depends on the whole data structure's integrity. This is a general problem we are aware of. - Some cleanup just to try to decrease the amount of Rawlink handling.
2 parents bfd072d + 32037a5 commit 98f6e40

File tree

1 file changed

+132
-83
lines changed

1 file changed

+132
-83
lines changed

src/libcollections/linked_list.rs

Lines changed: 132 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,23 @@ impl<T> Rawlink<T> {
104104
}
105105

106106
/// Convert the `Rawlink` into an Option value
107-
fn resolve_immut<'a>(&self) -> Option<&'a T> {
108-
unsafe {
109-
self.p.as_ref()
110-
}
107+
///
108+
/// **unsafe** because:
109+
///
110+
/// - Dereference of raw pointer.
111+
/// - Returns reference of arbitrary lifetime.
112+
unsafe fn resolve<'a>(&self) -> Option<&'a T> {
113+
self.p.as_ref()
111114
}
112115

113116
/// Convert the `Rawlink` into an Option value
114-
fn resolve<'a>(&mut self) -> Option<&'a mut T> {
115-
unsafe {
116-
self.p.as_mut()
117-
}
117+
///
118+
/// **unsafe** because:
119+
///
120+
/// - Dereference of raw pointer.
121+
/// - Returns reference of arbitrary lifetime.
122+
unsafe fn resolve_mut<'a>(&mut self) -> Option<&'a mut T> {
123+
self.p.as_mut()
118124
}
119125

120126
/// Return the `Rawlink` and replace with `Rawlink::none()`
@@ -123,6 +129,15 @@ impl<T> Rawlink<T> {
123129
}
124130
}
125131

132+
impl<'a, T> From<&'a mut Link<T>> for Rawlink<Node<T>> {
133+
fn from(node: &'a mut Link<T>) -> Self {
134+
match node.as_mut() {
135+
None => Rawlink::none(),
136+
Some(ptr) => Rawlink::some(ptr),
137+
}
138+
}
139+
}
140+
126141
impl<T> Clone for Rawlink<T> {
127142
#[inline]
128143
fn clone(&self) -> Rawlink<T> {
@@ -134,12 +149,21 @@ impl<T> Node<T> {
134149
fn new(v: T) -> Node<T> {
135150
Node{value: v, next: None, prev: Rawlink::none()}
136151
}
152+
153+
/// Update the `prev` link on `next`, then set self's next pointer.
154+
///
155+
/// `self.next` should be `None` when you call this
156+
/// (otherwise a Node is probably being dropped by mistake).
157+
fn set_next(&mut self, mut next: Box<Node<T>>) {
158+
debug_assert!(self.next.is_none());
159+
next.prev = Rawlink::some(self);
160+
self.next = Some(next);
161+
}
137162
}
138163

139-
/// Set the .prev field on `next`, then return `Some(next)`
140-
fn link_with_prev<T>(mut next: Box<Node<T>>, prev: Rawlink<Node<T>>)
141-
-> Link<T> {
142-
next.prev = prev;
164+
/// Clear the .prev field on `next`, then return `Some(next)`
165+
fn link_no_prev<T>(mut next: Box<Node<T>>) -> Link<T> {
166+
next.prev = Rawlink::none();
143167
Some(next)
144168
}
145169

@@ -150,8 +174,8 @@ impl<T> LinkedList<T> {
150174
fn push_front_node(&mut self, mut new_head: Box<Node<T>>) {
151175
match self.list_head {
152176
None => {
153-
self.list_tail = Rawlink::some(&mut *new_head);
154-
self.list_head = link_with_prev(new_head, Rawlink::none());
177+
self.list_head = link_no_prev(new_head);
178+
self.list_tail = Rawlink::from(&mut self.list_head);
155179
}
156180
Some(ref mut head) => {
157181
new_head.prev = Rawlink::none();
@@ -169,7 +193,7 @@ impl<T> LinkedList<T> {
169193
self.list_head.take().map(|mut front_node| {
170194
self.length -= 1;
171195
match front_node.next.take() {
172-
Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
196+
Some(node) => self.list_head = link_no_prev(node),
173197
None => self.list_tail = Rawlink::none()
174198
}
175199
front_node
@@ -178,12 +202,12 @@ impl<T> LinkedList<T> {
178202

179203
/// Add a Node last in the list
180204
#[inline]
181-
fn push_back_node(&mut self, mut new_tail: Box<Node<T>>) {
182-
match self.list_tail.resolve() {
205+
fn push_back_node(&mut self, new_tail: Box<Node<T>>) {
206+
match unsafe { self.list_tail.resolve_mut() } {
183207
None => return self.push_front_node(new_tail),
184208
Some(tail) => {
185-
self.list_tail = Rawlink::some(&mut *new_tail);
186-
tail.next = link_with_prev(new_tail, Rawlink::some(tail));
209+
tail.set_next(new_tail);
210+
self.list_tail = Rawlink::from(&mut tail.next);
187211
}
188212
}
189213
self.length += 1;
@@ -192,14 +216,16 @@ impl<T> LinkedList<T> {
192216
/// Remove the last Node and return it, or None if the list is empty
193217
#[inline]
194218
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
195-
self.list_tail.resolve().map_or(None, |tail| {
196-
self.length -= 1;
197-
self.list_tail = tail.prev;
198-
match tail.prev.resolve() {
199-
None => self.list_head.take(),
200-
Some(tail_prev) => tail_prev.next.take()
201-
}
202-
})
219+
unsafe {
220+
self.list_tail.resolve_mut().and_then(|tail| {
221+
self.length -= 1;
222+
self.list_tail = tail.prev;
223+
match tail.prev.resolve_mut() {
224+
None => self.list_head.take(),
225+
Some(tail_prev) => tail_prev.next.take()
226+
}
227+
})
228+
}
203229
}
204230
}
205231

@@ -246,7 +272,7 @@ impl<T> LinkedList<T> {
246272
/// ```
247273
#[stable(feature = "rust1", since = "1.0.0")]
248274
pub fn append(&mut self, other: &mut LinkedList<T>) {
249-
match self.list_tail.resolve() {
275+
match unsafe { self.list_tail.resolve_mut() } {
250276
None => {
251277
self.length = other.length;
252278
self.list_head = other.list_head.take();
@@ -259,7 +285,7 @@ impl<T> LinkedList<T> {
259285
match other.list_head.take() {
260286
None => return,
261287
Some(node) => {
262-
tail.next = link_with_prev(node, self.list_tail);
288+
tail.set_next(node);
263289
self.list_tail = o_tail;
264290
self.length += o_length;
265291
}
@@ -280,13 +306,9 @@ impl<T> LinkedList<T> {
280306
#[inline]
281307
#[stable(feature = "rust1", since = "1.0.0")]
282308
pub fn iter_mut(&mut self) -> IterMut<T> {
283-
let head_raw = match self.list_head {
284-
Some(ref mut h) => Rawlink::some(&mut **h),
285-
None => Rawlink::none(),
286-
};
287-
IterMut{
309+
IterMut {
288310
nelem: self.len(),
289-
head: head_raw,
311+
head: Rawlink::from(&mut self.list_head),
290312
tail: self.list_tail,
291313
list: self
292314
}
@@ -433,7 +455,9 @@ impl<T> LinkedList<T> {
433455
#[inline]
434456
#[stable(feature = "rust1", since = "1.0.0")]
435457
pub fn back(&self) -> Option<&T> {
436-
self.list_tail.resolve_immut().as_ref().map(|tail| &tail.value)
458+
unsafe {
459+
self.list_tail.resolve().map(|tail| &tail.value)
460+
}
437461
}
438462

439463
/// Provides a mutable reference to the back element, or `None` if the list
@@ -460,7 +484,9 @@ impl<T> LinkedList<T> {
460484
#[inline]
461485
#[stable(feature = "rust1", since = "1.0.0")]
462486
pub fn back_mut(&mut self) -> Option<&mut T> {
463-
self.list_tail.resolve().map(|tail| &mut tail.value)
487+
unsafe {
488+
self.list_tail.resolve_mut().map(|tail| &mut tail.value)
489+
}
464490
}
465491

466492
/// Adds an element first in the list.
@@ -603,44 +629,42 @@ impl<T> LinkedList<T> {
603629
iter.tail
604630
};
605631

606-
let mut splitted_list = LinkedList {
607-
list_head: None,
632+
// The split node is the new tail node of the first part and owns
633+
// the head of the second part.
634+
let mut second_part_head;
635+
636+
unsafe {
637+
second_part_head = split_node.resolve_mut().unwrap().next.take();
638+
match second_part_head {
639+
None => {}
640+
Some(ref mut head) => head.prev = Rawlink::none(),
641+
}
642+
}
643+
644+
let second_part = LinkedList {
645+
list_head: second_part_head,
608646
list_tail: self.list_tail,
609647
length: len - at
610648
};
611649

612-
// Swap split_node.next with list_head (which is None), nulling out split_node.next,
613-
// as it is the new tail.
614-
mem::swap(&mut split_node.resolve().unwrap().next, &mut splitted_list.list_head);
615-
// Null out list_head.prev. Note this `unwrap` won't fail because if at == len
616-
// we already branched out at the top of the fn to return the empty list.
617-
splitted_list.list_head.as_mut().unwrap().prev = Rawlink::none();
618-
// Fix the tail ptr
650+
// Fix the tail ptr of the first part
619651
self.list_tail = split_node;
620652
self.length = at;
621653

622-
splitted_list
654+
second_part
623655
}
624656
}
625657

626658
#[stable(feature = "rust1", since = "1.0.0")]
627659
impl<T> Drop for LinkedList<T> {
628660
fn drop(&mut self) {
629-
// Dissolve the linked_list in backwards direction
661+
// Dissolve the linked_list in a loop.
630662
// Just dropping the list_head can lead to stack exhaustion
631663
// when length is >> 1_000_000
632-
let mut tail = self.list_tail;
633-
loop {
634-
match tail.resolve() {
635-
None => break,
636-
Some(prev) => {
637-
prev.next.take(); // release Box<Node<T>>
638-
tail = prev.prev;
639-
}
640-
}
664+
while let Some(mut head_) = self.list_head.take() {
665+
self.list_head = head_.next.take();
641666
}
642667
self.length = 0;
643-
self.list_head = None;
644668
self.list_tail = Rawlink::none();
645669
}
646670
}
@@ -674,11 +698,13 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> {
674698
if self.nelem == 0 {
675699
return None;
676700
}
677-
self.tail.resolve_immut().as_ref().map(|prev| {
678-
self.nelem -= 1;
679-
self.tail = prev.prev;
680-
&prev.value
681-
})
701+
unsafe {
702+
self.tail.resolve().map(|prev| {
703+
self.nelem -= 1;
704+
self.tail = prev.prev;
705+
&prev.value
706+
})
707+
}
682708
}
683709
}
684710

@@ -693,14 +719,13 @@ impl<'a, A> Iterator for IterMut<'a, A> {
693719
if self.nelem == 0 {
694720
return None;
695721
}
696-
self.head.resolve().map(|next| {
697-
self.nelem -= 1;
698-
self.head = match next.next {
699-
Some(ref mut node) => Rawlink::some(&mut **node),
700-
None => Rawlink::none(),
701-
};
702-
&mut next.value
703-
})
722+
unsafe {
723+
self.head.resolve_mut().map(|next| {
724+
self.nelem -= 1;
725+
self.head = Rawlink::from(&mut next.next);
726+
&mut next.value
727+
})
728+
}
704729
}
705730

706731
#[inline]
@@ -716,11 +741,13 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> {
716741
if self.nelem == 0 {
717742
return None;
718743
}
719-
self.tail.resolve().map(|prev| {
720-
self.nelem -= 1;
721-
self.tail = prev.prev;
722-
&mut prev.value
723-
})
744+
unsafe {
745+
self.tail.resolve_mut().map(|prev| {
746+
self.nelem -= 1;
747+
self.tail = prev.prev;
748+
&mut prev.value
749+
})
750+
}
724751
}
725752
}
726753

@@ -734,16 +761,16 @@ impl<'a, A> IterMut<'a, A> {
734761
// previously yielded element and self.head.
735762
//
736763
// The inserted node will not appear in further iteration.
737-
match self.head.resolve() {
764+
match unsafe { self.head.resolve_mut() } {
738765
None => { self.list.push_back_node(ins_node); }
739766
Some(node) => {
740-
let prev_node = match node.prev.resolve() {
767+
let prev_node = match unsafe { node.prev.resolve_mut() } {
741768
None => return self.list.push_front_node(ins_node),
742769
Some(prev) => prev,
743770
};
744771
let node_own = prev_node.next.take().unwrap();
745-
ins_node.next = link_with_prev(node_own, Rawlink::some(&mut *ins_node));
746-
prev_node.next = link_with_prev(ins_node, Rawlink::some(prev_node));
772+
ins_node.set_next(node_own);
773+
prev_node.set_next(ins_node);
747774
self.list.length += 1;
748775
}
749776
}
@@ -803,7 +830,9 @@ impl<'a, A> IterMut<'a, A> {
803830
if self.nelem == 0 {
804831
return None
805832
}
806-
self.head.resolve().map(|head| &mut head.value)
833+
unsafe {
834+
self.head.resolve_mut().map(|head| &mut head.value)
835+
}
807836
}
808837
}
809838

@@ -933,7 +962,7 @@ impl<A: Hash> Hash for LinkedList<A> {
933962
#[cfg(test)]
934963
mod tests {
935964
use std::clone::Clone;
936-
use std::iter::{Iterator, IntoIterator};
965+
use std::iter::{Iterator, IntoIterator, Extend};
937966
use std::option::Option::{Some, None, self};
938967
use std::__rand::{thread_rng, Rng};
939968
use std::thread;
@@ -955,7 +984,7 @@ mod tests {
955984
Some(ref node) => node_ptr = &**node,
956985
}
957986
loop {
958-
match (last_ptr, node_ptr.prev.resolve_immut()) {
987+
match unsafe { (last_ptr, node_ptr.prev.resolve()) } {
959988
(None , None ) => {}
960989
(None , _ ) => panic!("prev link for list_head"),
961990
(Some(p), Some(pptr)) => {
@@ -1101,6 +1130,26 @@ mod tests {
11011130
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
11021131
}
11031132

1133+
#[test]
1134+
fn test_split_off() {
1135+
let mut v1 = LinkedList::new();
1136+
v1.push_front(1u8);
1137+
v1.push_front(1u8);
1138+
v1.push_front(1u8);
1139+
v1.push_front(1u8);
1140+
1141+
// test all splits
1142+
for ix in 0..1 + v1.len() {
1143+
let mut a = v1.clone();
1144+
let b = a.split_off(ix);
1145+
check_links(&a);
1146+
check_links(&b);
1147+
a.extend(b);
1148+
assert_eq!(v1, a);
1149+
}
1150+
}
1151+
1152+
11041153
#[cfg(test)]
11051154
fn fuzz_test(sz: i32) {
11061155
let mut m: LinkedList<_> = LinkedList::new();

0 commit comments

Comments
 (0)