From d59e9b40a3712fa29e59b17cc2a9a10549cae79f Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 11 Jan 2020 16:56:21 +0800 Subject: [PATCH 01/12] Implement Cursor for linked lists. (RFC 2570). --- src/liballoc/collections/linked_list.rs | 457 +++++++++++++++++- src/liballoc/collections/linked_list/tests.rs | 98 ++++ 2 files changed, 531 insertions(+), 24 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 29bf2fdb30cf7..d0ad1ec283942 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -242,6 +242,88 @@ impl LinkedList { self.len -= 1; } + + /// Splices a series of nodes between two existing nodes. + /// + /// Warning: this will not check that the provided node belongs to the two existing lists. + #[inline] + unsafe fn splice_nodes( + &mut self, + existing_prev: Option>>, + existing_next: Option>>, + splice_start: NonNull>, + splice_end: NonNull>, + splice_length: usize, + ) { + // This method takes care not to create multiple mutable references to whole nodes at the same time, + // to maintain validity of aliasing pointers into `element`. + if let Some(mut existing_prev) = existing_prev { + existing_prev.as_mut().next = Some(splice_start); + } else { + self.head = Some(splice_start); + } + if let Some(mut existing_next) = existing_next { + existing_next.as_mut().prev = Some(splice_end); + } else { + self.tail = Some(splice_end); + } + let mut splice_start = splice_start; + splice_start.as_mut().prev = existing_prev; + let mut splice_end = splice_end; + splice_end.as_mut().next = existing_next; + + self.len += splice_length; + } + + /// Detaches all nodes from a linked list as a series of nodes. + #[inline] + fn detach_all_nodes(mut self) -> Option<(NonNull>, NonNull>, usize)> { + let head = self.head.take(); + let tail = self.tail.take(); + let len = mem::replace(&mut self.len, 0); + if let Some(head) = head { + let tail = tail.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() }); + Some((head, tail, len)) + } else { + None + } + } + + #[inline] + unsafe fn split_off_after_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self { + // The split node is the new tail node of the first part and owns + // the head of the second part. + if let Some(mut split_node) = split_node { + let second_part_head; + let second_part_tail; + second_part_head = split_node.as_mut().next.take(); + if let Some(mut head) = second_part_head { + head.as_mut().prev = None; + second_part_tail = self.tail; + } else { + second_part_tail = None; + } + + let second_part = LinkedList { + head: second_part_head, + tail: second_part_tail, + len: self.len - at, + marker: PhantomData, + }; + + // Fix the tail ptr of the first part + self.tail = Some(split_node); + self.len = at; + + second_part + } else { + mem::replace(self, LinkedList::new()) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -319,6 +401,27 @@ impl LinkedList { } } + /// Moves all elements from `other` to the begin of the list. + #[unstable(feature = "linked_list_prepend", issue = "none")] + pub fn prepend(&mut self, other: &mut Self) { + match self.head { + None => mem::swap(self, other), + Some(mut head) => { + // `as_mut` is okay here because we have exclusive access to the entirety + // of both lists. + if let Some(mut other_tail) = other.tail.take() { + unsafe { + head.as_mut().prev = Some(other_tail); + other_tail.as_mut().next = Some(head); + } + + self.head = other.head.take(); + self.len += mem::replace(&mut other.len, 0); + } + } + } + } + /// Provides a forward iterator. /// /// # Examples @@ -373,6 +476,20 @@ impl LinkedList { IterMut { head: self.head, tail: self.tail, len: self.len, list: self } } + /// Provides a cursor. + #[inline] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor(&self) -> Cursor<'_, T> { + Cursor { index: 0, current: self.head, list: self } + } + + /// Provides a cursor with editing operations. + #[inline] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_mut(&mut self) -> CursorMut<'_, T> { + CursorMut { index: 0, current: self.head, list: self } + } + /// Returns `true` if the `LinkedList` is empty. /// /// This operation should compute in O(1) time. @@ -703,30 +820,7 @@ impl LinkedList { } iter.tail }; - - // The split node is the new tail node of the first part and owns - // the head of the second part. - let second_part_head; - - unsafe { - second_part_head = split_node.unwrap().as_mut().next.take(); - if let Some(mut head) = second_part_head { - head.as_mut().prev = None; - } - } - - let second_part = LinkedList { - head: second_part_head, - tail: self.tail, - len: len - at, - marker: PhantomData, - }; - - // Fix the tail ptr of the first part - self.tail = split_node; - self.len = at; - - second_part + unsafe { self.split_off_after_node(split_node, at) } } /// Creates an iterator which uses a closure to determine if an element should be removed. @@ -986,6 +1080,321 @@ impl IterMut<'_, T> { } } +/// A cursor over a `LinkedList`. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the list during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying list. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +/// +/// When created, cursors start at the front of the list, or the ghost element if the list is empty. +#[unstable(feature = "linked_list_cursors", issue = "58533")] +pub struct Cursor<'a, T: 'a> { + index: usize, + current: Option>>, + list: &'a LinkedList, +} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +impl fmt::Debug for Cursor<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Cursor").field(&self.list).field(&self.index).finish() + } +} + +/// A cursor over a `LinkedList` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the list during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying list. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +/// +/// When created, cursors start at the front of the list, or the ghost element if the list is empty. +#[unstable(feature = "linked_list_cursors", issue = "58533")] +pub struct CursorMut<'a, T: 'a> { + index: usize, + current: Option>>, + list: &'a mut LinkedList, +} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +impl fmt::Debug for CursorMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CursorMut").field(&self.list).field(&self.index).finish() + } +} + +impl<'a, T> Cursor<'a, T> { + /// Move to the subsequent element of the list if it exists or the empty + /// element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_next(&mut self) { + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + self.current = self.list.head; + self.index = 0; + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + self.current = current.as_ref().next; + self.index += 1; + }, + } + } + + /// Move to the previous element of the list + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_prev(&mut self) { + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + self.current = self.list.tail; + self.index = self.list.len().checked_sub(1).unwrap_or(0); + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + self.current = current.as_ref().prev; + self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + }, + } + } + + /// Get the current element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn current(&self) -> Option<&'a T> { + unsafe { self.current.map(|current| &(*current.as_ptr()).element) } + } + + /// Get the next element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_next(&self) -> Option<&'a T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &(*next.as_ptr()).element) + } + } + + /// Get the previous element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_prev(&self) -> Option<&'a T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &(*prev.as_ptr()).element) + } + } +} + +impl<'a, T> CursorMut<'a, T> { + /// Move to the subsequent element of the list if it exists or the empty + /// element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_next(&mut self) { + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + self.current = self.list.head; + self.index = 0; + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + self.current = current.as_ref().next; + self.index += 1; + }, + } + } + + /// Move to the previous element of the list + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_prev(&mut self) { + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + self.current = self.list.tail; + self.index = self.list.len().checked_sub(1).unwrap_or(0); + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + self.current = current.as_ref().prev; + self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + }, + } + } + + /// Get the current element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn current(&mut self) -> Option<&mut T> { + unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) } + } + + /// Get the next element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_next(&mut self) -> Option<&mut T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &mut (*next.as_ptr()).element) + } + } + + /// Get the previous element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_prev(&mut self) -> Option<&mut T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &mut (*prev.as_ptr()).element) + } + } + + /// Get an immutable cursor at the current element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_cursor<'cm>(&'cm self) -> Cursor<'cm, T> { + Cursor { list: self.list, current: self.current, index: self.index } + } +} + +// Now the list editing operations + +impl<'a, T> CursorMut<'a, T> { + /// Insert `item` after the cursor + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn insert_after(&mut self, item: T) { + unsafe { + let spliced_node = Box::into_raw_non_null(Box::new(Node::new(item))); + let (node, node_next) = match self.current { + None => (None, self.list.head), + Some(node) => { + let node_next = node.as_ref().next; + (Some(node), node_next) + } + }; + self.list.splice_nodes(node, node_next, spliced_node, spliced_node, 1); + if self.current.is_none() { + // The ghost element's index has increased by 1. + self.index += 1; + } + } + } + + /// Insert `item` before the cursor + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn insert_before(&mut self, item: T) { + unsafe { + let spliced_node = Box::into_raw_non_null(Box::new(Node::new(item))); + let (node_prev, node) = match self.current { + None => (self.list.tail, None), + Some(node) => { + let node_prev = node.as_ref().prev; + (node_prev, Some(node)) + } + }; + self.list.splice_nodes(node_prev, node, spliced_node, spliced_node, 1); + self.index += 1; + } + } + + /// Remove and return the current item, moving the cursor to the next item + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn remove(&mut self) -> Option { + let unlinked_node = self.current?; + unsafe { + self.current = unlinked_node.as_ref().next; + self.list.unlink_node(unlinked_node); + let unlinked_node = Box::from_raw(unlinked_node.as_ptr()); + Some((*unlinked_node).element) + } + } + + /// Insert `list` between the current element and the next + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_after(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let (node, node_next) = match self.current { + None => (None, self.list.head), + Some(node) => { + let node_next = node.as_ref().next; + (Some(node), node_next) + } + }; + self.list.splice_nodes(node, node_next, splice_head, splice_tail, splice_len); + if self.current.is_none() { + // The ghost element's index has increased by `splice_len`. + self.index += splice_len; + } + } + } + + /// Insert `list` between the previous element and current + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_before(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let (node_prev, node) = match self.current { + None => (self.list.tail, None), + Some(node) => { + let node_prev = node.as_ref().prev; + (node_prev, Some(node)) + } + }; + self.list.splice_nodes(node_prev, node, splice_head, splice_tail, splice_len); + self.index += splice_len; + } + } + + /// Split the list in two after the current element + /// The returned list consists of all elements following the current one. + // note: consuming the cursor is not necessary here, but it makes sense + // given the interface + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn split_after(self) -> LinkedList { + let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; + unsafe { + let split_off_node = self.current; + self.list.split_off_after_node(split_off_node, split_off_idx) + } + } + /// Split the list in two before the current element + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn split_before(self) -> LinkedList { + let split_off_idx = self.index; + unsafe { + let split_off_node = match self.current { + Some(node) => node.as_ref().prev, + None => self.list.tail, + }; + self.list.split_off_after_node(split_off_node, split_off_idx) + } + } +} + /// An iterator produced by calling `drain_filter` on LinkedList. #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] pub struct DrainFilter<'a, T: 'a, F: 'a> diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs index 1b1d8eab39bfc..51b23e23cd276 100644 --- a/src/liballoc/collections/linked_list/tests.rs +++ b/src/liballoc/collections/linked_list/tests.rs @@ -304,3 +304,101 @@ fn drain_to_empty_test() { assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]); assert_eq!(m.into_iter().collect::>(), &[]); } + +#[test] +fn test_cursor_move_peek() { + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor(); + assert_eq!(cursor.current(), Some(&1)); + assert_eq!(cursor.peek_next(), Some(&2)); + assert_eq!(cursor.peek_prev(), None); + cursor.move_prev(); + assert_eq!(cursor.current(), None); + assert_eq!(cursor.peek_next(), Some(&1)); + assert_eq!(cursor.peek_prev(), Some(&6)); + cursor.move_next(); + cursor.move_next(); + assert_eq!(cursor.current(), Some(&2)); + assert_eq!(cursor.peek_next(), Some(&3)); + assert_eq!(cursor.peek_prev(), Some(&1)); + + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor_mut(); + assert_eq!(cursor.current(), Some(&mut 1)); + assert_eq!(cursor.peek_next(), Some(&mut 2)); + assert_eq!(cursor.peek_prev(), None); + cursor.move_prev(); + assert_eq!(cursor.current(), None); + assert_eq!(cursor.peek_next(), Some(&mut 1)); + assert_eq!(cursor.peek_prev(), Some(&mut 6)); + cursor.move_next(); + cursor.move_next(); + assert_eq!(cursor.current(), Some(&mut 2)); + assert_eq!(cursor.peek_next(), Some(&mut 3)); + assert_eq!(cursor.peek_prev(), Some(&mut 1)); + let mut cursor2 = cursor.as_cursor(); + assert_eq!(cursor2.current(), Some(&2)); + cursor2.move_next(); + assert_eq!(cursor2.current(), Some(&3)); + assert_eq!(cursor.current(), Some(&mut 2)); +} + +#[test] +fn test_cursor_mut_insert() { + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor_mut(); + cursor.insert_before(7); + cursor.insert_after(8); + check_links(&m); + assert_eq!(m.iter().cloned().collect::>(), &[7, 1, 8, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor_mut(); + cursor.move_prev(); + cursor.insert_before(9); + cursor.insert_after(10); + check_links(&m); + assert_eq!(m.iter().cloned().collect::>(), &[10, 7, 1, 8, 2, 3, 4, 5, 6, 9]); + let mut cursor = m.cursor_mut(); + cursor.move_prev(); + assert_eq!(cursor.remove(), None); + cursor.move_next(); + cursor.move_next(); + assert_eq!(cursor.remove(), Some(7)); + cursor.move_prev(); + cursor.move_prev(); + cursor.move_prev(); + assert_eq!(cursor.remove(), Some(9)); + cursor.move_next(); + assert_eq!(cursor.remove(), Some(10)); + check_links(&m); + assert_eq!(m.iter().cloned().collect::>(), &[1, 8, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor_mut(); + let mut p: LinkedList = LinkedList::new(); + p.extend(&[100, 101, 102, 103]); + let mut q: LinkedList = LinkedList::new(); + q.extend(&[200, 201, 202, 203]); + cursor.splice_after(p); + cursor.splice_before(q); + check_links(&m); + assert_eq!( + m.iter().cloned().collect::>(), + &[200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6] + ); + let mut cursor = m.cursor_mut(); + cursor.move_prev(); + let tmp = cursor.split_before(); + assert_eq!(tmp.into_iter().collect::>(), &[]); + let mut cursor = m.cursor_mut(); + cursor.move_next(); + cursor.move_next(); + cursor.move_next(); + cursor.move_next(); + cursor.move_next(); + cursor.move_next(); + let tmp = cursor.split_after(); + assert_eq!(tmp.into_iter().collect::>(), &[102, 103, 8, 2, 3, 4, 5, 6]); + check_links(&m); + assert_eq!(m.iter().cloned().collect::>(), &[200, 201, 202, 203, 1, 100, 101]); +} From 091ba6daa0a0a528b5d9fc816529a9bb25503960 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 12 Jan 2020 13:15:00 +0800 Subject: [PATCH 02/12] Address review comments. --- src/liballoc/collections/linked_list.rs | 233 ++++++++++++------ src/liballoc/collections/linked_list/tests.rs | 11 +- 2 files changed, 161 insertions(+), 83 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index d0ad1ec283942..3524c6e9817e1 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -251,8 +251,8 @@ impl LinkedList { &mut self, existing_prev: Option>>, existing_next: Option>>, - splice_start: NonNull>, - splice_end: NonNull>, + mut splice_start: NonNull>, + mut splice_end: NonNull>, splice_length: usize, ) { // This method takes care not to create multiple mutable references to whole nodes at the same time, @@ -267,9 +267,7 @@ impl LinkedList { } else { self.tail = Some(splice_end); } - let mut splice_start = splice_start; splice_start.as_mut().prev = existing_prev; - let mut splice_end = splice_end; splice_end.as_mut().next = existing_next; self.len += splice_length; @@ -289,6 +287,41 @@ impl LinkedList { } } + #[inline] + unsafe fn split_off_before_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self { + // The split node is the new head node of the second part + if let Some(mut split_node) = split_node { + let first_part_head; + let first_part_tail; + first_part_tail = split_node.as_mut().prev.take(); + if let Some(mut tail) = first_part_tail { + tail.as_mut().next = None; + first_part_head = self.head; + } else { + first_part_head = None; + } + + let first_part = LinkedList { + head: first_part_head, + tail: first_part_tail, + len: at, + marker: PhantomData, + }; + + // Fix the head ptr of the second part + self.head = Some(split_node); + self.len = self.len - at; + + first_part + } else { + mem::replace(self, LinkedList::new()) + } + } + #[inline] unsafe fn split_off_after_node( &mut self, @@ -1082,16 +1115,13 @@ impl IterMut<'_, T> { /// A cursor over a `LinkedList`. /// -/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can -/// safely mutate the list during iteration. This is because the lifetime of its yielded -/// references is tied to its own lifetime, instead of just the underlying list. This means -/// cursors cannot yield multiple elements at once. +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. /// /// Cursors always rest between two elements in the list, and index in a logically circular way. /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and /// tail of the list. /// -/// When created, cursors start at the front of the list, or the ghost element if the list is empty. +/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub struct Cursor<'a, T: 'a> { index: usize, @@ -1117,7 +1147,7 @@ impl fmt::Debug for Cursor<'_, T> { /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and /// tail of the list. /// -/// When created, cursors start at the front of the list, or the ghost element if the list is empty. +/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub struct CursorMut<'a, T: 'a> { index: usize, @@ -1133,8 +1163,11 @@ impl fmt::Debug for CursorMut<'_, T> { } impl<'a, T> Cursor<'a, T> { - /// Move to the subsequent element of the list if it exists or the empty - /// element + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn move_next(&mut self) { match self.current.take() { @@ -1152,7 +1185,11 @@ impl<'a, T> Cursor<'a, T> { } } - /// Move to the previous element of the list + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn move_prev(&mut self) { match self.current.take() { @@ -1169,13 +1206,21 @@ impl<'a, T> Cursor<'a, T> { } } - /// Get the current element + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn current(&self) -> Option<&'a T> { unsafe { self.current.map(|current| &(*current.as_ptr()).element) } } - /// Get the next element + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_next(&self) -> Option<&'a T> { unsafe { @@ -1187,7 +1232,11 @@ impl<'a, T> Cursor<'a, T> { } } - /// Get the previous element + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_prev(&self) -> Option<&'a T> { unsafe { @@ -1201,8 +1250,11 @@ impl<'a, T> Cursor<'a, T> { } impl<'a, T> CursorMut<'a, T> { - /// Move to the subsequent element of the list if it exists or the empty - /// element + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn move_next(&mut self) { match self.current.take() { @@ -1220,7 +1272,11 @@ impl<'a, T> CursorMut<'a, T> { } } - /// Move to the previous element of the list + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn move_prev(&mut self) { match self.current.take() { @@ -1237,13 +1293,21 @@ impl<'a, T> CursorMut<'a, T> { } } - /// Get the current element + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn current(&mut self) -> Option<&mut T> { unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) } } - /// Get the next element + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_next(&mut self) -> Option<&mut T> { unsafe { @@ -1255,7 +1319,11 @@ impl<'a, T> CursorMut<'a, T> { } } - /// Get the previous element + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_prev(&mut self) -> Option<&mut T> { unsafe { @@ -1267,7 +1335,11 @@ impl<'a, T> CursorMut<'a, T> { } } - /// Get an immutable cursor at the current element + /// Returns a read-only cursor pointing to the current element. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn as_cursor<'cm>(&'cm self) -> Cursor<'cm, T> { Cursor { list: self.list, current: self.current, index: self.index } @@ -1277,56 +1349,65 @@ impl<'a, T> CursorMut<'a, T> { // Now the list editing operations impl<'a, T> CursorMut<'a, T> { - /// Insert `item` after the cursor + /// Inserts a new element into the `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the front of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_after(&mut self, item: T) { unsafe { let spliced_node = Box::into_raw_non_null(Box::new(Node::new(item))); - let (node, node_next) = match self.current { - None => (None, self.list.head), - Some(node) => { - let node_next = node.as_ref().next; - (Some(node), node_next) - } + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, }; - self.list.splice_nodes(node, node_next, spliced_node, spliced_node, 1); + self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1); if self.current.is_none() { - // The ghost element's index has increased by 1. - self.index += 1; + // The "ghost" non-element's index has changed. + self.index = self.list.len; } } } - /// Insert `item` before the cursor + /// Inserts a new element into the `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the end of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_before(&mut self, item: T) { unsafe { let spliced_node = Box::into_raw_non_null(Box::new(Node::new(item))); - let (node_prev, node) = match self.current { - None => (self.list.tail, None), - Some(node) => { - let node_prev = node.as_ref().prev; - (node_prev, Some(node)) - } + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, }; - self.list.splice_nodes(node_prev, node, spliced_node, spliced_node, 1); + self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1); self.index += 1; } } - /// Remove and return the current item, moving the cursor to the next item + /// Removes the current element from the `LinkedList`. + /// + /// The element that was removed is returned, and the cursor is + /// moved to point to the next element in the `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn remove(&mut self) -> Option { + pub fn remove_current(&mut self) -> Option { let unlinked_node = self.current?; unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); let unlinked_node = Box::from_raw(unlinked_node.as_ptr()); - Some((*unlinked_node).element) + Some(unlinked_node.element) } } - /// Insert `list` between the current element and the next + /// Inserts the elements from the given `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the start of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn splice_after(&mut self, list: LinkedList) { unsafe { @@ -1334,22 +1415,22 @@ impl<'a, T> CursorMut<'a, T> { Some(parts) => parts, _ => return, }; - let (node, node_next) = match self.current { - None => (None, self.list.head), - Some(node) => { - let node_next = node.as_ref().next; - (Some(node), node_next) - } + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, }; - self.list.splice_nodes(node, node_next, splice_head, splice_tail, splice_len); + self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); if self.current.is_none() { - // The ghost element's index has increased by `splice_len`. - self.index += splice_len; + // The "ghost" non-element's index has changed. + self.index = self.list.len; } } } - /// Insert `list` between the previous element and current + /// Inserts the elements from the given `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the end of the `LinkedList`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn splice_before(&mut self, list: LinkedList) { unsafe { @@ -1357,41 +1438,37 @@ impl<'a, T> CursorMut<'a, T> { Some(parts) => parts, _ => return, }; - let (node_prev, node) = match self.current { - None => (self.list.tail, None), - Some(node) => { - let node_prev = node.as_ref().prev; - (node_prev, Some(node)) - } + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, }; - self.list.splice_nodes(node_prev, node, splice_head, splice_tail, splice_len); + self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); self.index += splice_len; } } - /// Split the list in two after the current element - /// The returned list consists of all elements following the current one. - // note: consuming the cursor is not necessary here, but it makes sense - // given the interface + /// Splits the list into two after the current element. This will return a + /// new list consisting of everything after the cursor, with the original + /// list retaining everything before. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_after(self) -> LinkedList { let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; - unsafe { - let split_off_node = self.current; - self.list.split_off_after_node(split_off_node, split_off_idx) - } + unsafe { self.list.split_off_after_node(self.current, split_off_idx) } } - /// Split the list in two before the current element + + /// Splits the list into two before the current element. This will return a + /// new list consisting of everything before the cursor, with the original + /// list retaining everything after. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_before(self) -> LinkedList { let split_off_idx = self.index; - unsafe { - let split_off_node = match self.current { - Some(node) => node.as_ref().prev, - None => self.list.tail, - }; - self.list.split_off_after_node(split_off_node, split_off_idx) - } + unsafe { self.list.split_off_before_node(self.current, split_off_idx) } } } diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs index 51b23e23cd276..29eb1b4abd732 100644 --- a/src/liballoc/collections/linked_list/tests.rs +++ b/src/liballoc/collections/linked_list/tests.rs @@ -362,16 +362,16 @@ fn test_cursor_mut_insert() { assert_eq!(m.iter().cloned().collect::>(), &[10, 7, 1, 8, 2, 3, 4, 5, 6, 9]); let mut cursor = m.cursor_mut(); cursor.move_prev(); - assert_eq!(cursor.remove(), None); + assert_eq!(cursor.remove_current(), None); cursor.move_next(); cursor.move_next(); - assert_eq!(cursor.remove(), Some(7)); + assert_eq!(cursor.remove_current(), Some(7)); cursor.move_prev(); cursor.move_prev(); cursor.move_prev(); - assert_eq!(cursor.remove(), Some(9)); + assert_eq!(cursor.remove_current(), Some(9)); cursor.move_next(); - assert_eq!(cursor.remove(), Some(10)); + assert_eq!(cursor.remove_current(), Some(10)); check_links(&m); assert_eq!(m.iter().cloned().collect::>(), &[1, 8, 2, 3, 4, 5, 6]); let mut cursor = m.cursor_mut(); @@ -389,7 +389,8 @@ fn test_cursor_mut_insert() { let mut cursor = m.cursor_mut(); cursor.move_prev(); let tmp = cursor.split_before(); - assert_eq!(tmp.into_iter().collect::>(), &[]); + assert_eq!(m.into_iter().collect::>(), &[]); + m = tmp; let mut cursor = m.cursor_mut(); cursor.move_next(); cursor.move_next(); From d2c509a3c6b06ba02807bf94c00fad4c4a9262a5 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 12 Jan 2020 18:01:24 +0800 Subject: [PATCH 03/12] Address review comments. --- src/liballoc/collections/linked_list.rs | 26 +++++++++++++++++-- src/liballoc/collections/linked_list/tests.rs | 9 +++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 3524c6e9817e1..d7504b0b80bd9 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1132,7 +1132,7 @@ pub struct Cursor<'a, T: 'a> { #[unstable(feature = "linked_list_cursors", issue = "58533")] impl fmt::Debug for Cursor<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Cursor").field(&self.list).field(&self.index).finish() + f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish() } } @@ -1158,11 +1158,21 @@ pub struct CursorMut<'a, T: 'a> { #[unstable(feature = "linked_list_cursors", issue = "58533")] impl fmt::Debug for CursorMut<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("CursorMut").field(&self.list).field(&self.index).finish() + f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish() } } impl<'a, T> Cursor<'a, T> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + /// Moves the cursor to the next element of the `LinkedList`. /// /// If the cursor is pointing to the "ghost" non-element then this will move it to @@ -1250,6 +1260,16 @@ impl<'a, T> Cursor<'a, T> { } impl<'a, T> CursorMut<'a, T> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + /// Moves the cursor to the next element of the `LinkedList`. /// /// If the cursor is pointing to the "ghost" non-element then this will move it to @@ -1456,6 +1476,7 @@ impl<'a, T> CursorMut<'a, T> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_after(self) -> LinkedList { let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; + // no need to update `self.index` because the cursor is consumed. unsafe { self.list.split_off_after_node(self.current, split_off_idx) } } @@ -1468,6 +1489,7 @@ impl<'a, T> CursorMut<'a, T> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_before(self) -> LinkedList { let split_off_idx = self.index; + // no need to update `self.index` because the cursor is consumed. unsafe { self.list.split_off_before_node(self.current, split_off_idx) } } } diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs index 29eb1b4abd732..d223752c7f7ec 100644 --- a/src/liballoc/collections/linked_list/tests.rs +++ b/src/liballoc/collections/linked_list/tests.rs @@ -313,15 +313,18 @@ fn test_cursor_move_peek() { assert_eq!(cursor.current(), Some(&1)); assert_eq!(cursor.peek_next(), Some(&2)); assert_eq!(cursor.peek_prev(), None); + assert_eq!(cursor.index(), Some(0)); cursor.move_prev(); assert_eq!(cursor.current(), None); assert_eq!(cursor.peek_next(), Some(&1)); assert_eq!(cursor.peek_prev(), Some(&6)); + assert_eq!(cursor.index(), None); cursor.move_next(); cursor.move_next(); assert_eq!(cursor.current(), Some(&2)); assert_eq!(cursor.peek_next(), Some(&3)); assert_eq!(cursor.peek_prev(), Some(&1)); + assert_eq!(cursor.index(), Some(1)); let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); @@ -329,20 +332,26 @@ fn test_cursor_move_peek() { assert_eq!(cursor.current(), Some(&mut 1)); assert_eq!(cursor.peek_next(), Some(&mut 2)); assert_eq!(cursor.peek_prev(), None); + assert_eq!(cursor.index(), Some(0)); cursor.move_prev(); assert_eq!(cursor.current(), None); assert_eq!(cursor.peek_next(), Some(&mut 1)); assert_eq!(cursor.peek_prev(), Some(&mut 6)); + assert_eq!(cursor.index(), None); cursor.move_next(); cursor.move_next(); assert_eq!(cursor.current(), Some(&mut 2)); assert_eq!(cursor.peek_next(), Some(&mut 3)); assert_eq!(cursor.peek_prev(), Some(&mut 1)); + assert_eq!(cursor.index(), Some(1)); let mut cursor2 = cursor.as_cursor(); assert_eq!(cursor2.current(), Some(&2)); + assert_eq!(cursor2.index(), Some(1)); cursor2.move_next(); assert_eq!(cursor2.current(), Some(&3)); + assert_eq!(cursor2.index(), Some(2)); assert_eq!(cursor.current(), Some(&mut 2)); + assert_eq!(cursor.index(), Some(1)); } #[test] From b5214917b7b225e12289b81d8cb305fee4e51177 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 14 Jan 2020 00:42:19 +0100 Subject: [PATCH 04/12] Fix thumb target CI --- src/test/run-make/thumb-none-cortex-m/Makefile | 8 +++----- src/test/run-make/thumb-none-qemu/Makefile | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/test/run-make/thumb-none-cortex-m/Makefile b/src/test/run-make/thumb-none-cortex-m/Makefile index 6791c8ccdf138..36e51bcab6de2 100644 --- a/src/test/run-make/thumb-none-cortex-m/Makefile +++ b/src/test/run-make/thumb-none-cortex-m/Makefile @@ -10,10 +10,7 @@ # - thumbv7em-none-eabihf (Bare Cortex-M4F, M7F, FPU, hardfloat) # - thumbv7m-none-eabi (Bare Cortex-M3) -# only-thumbv6m-none-eabi -# only-thumbv7em-none-eabi -# only-thumbv7em-none-eabihf -# only-thumbv7m-none-eabi +# only-thumb # For cargo setting RUSTC := $(RUSTC_ORIGINAL) @@ -27,7 +24,8 @@ CRATE := cortex-m CRATE_URL := https://github.com/rust-embedded/cortex-m CRATE_SHA1 := a448e9156e2cb1e556e5441fd65426952ef4b927 # 0.5.0 -export RUSTFLAGS := --cap-lints=allow +# Don't make lints fatal, but they need to at least warn or they break Cargo's target info parsing. +export RUSTFLAGS := --cap-lints=warn all: env diff --git a/src/test/run-make/thumb-none-qemu/Makefile b/src/test/run-make/thumb-none-qemu/Makefile index cb1ff8591221e..ab8b90e154eab 100644 --- a/src/test/run-make/thumb-none-qemu/Makefile +++ b/src/test/run-make/thumb-none-qemu/Makefile @@ -1,7 +1,6 @@ -include ../../run-make-fulldeps/tools.mk -# only-thumbv7m-none-eabi -# only-thumbv6m-none-eabi +# only-thumb # How to run this # $ ./x.py clean From f37601a72ef2433bee7c3ad0309643a4b7d303e5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 14 Jan 2020 00:56:11 +0100 Subject: [PATCH 05/12] Account for run-make tests in `is_up_to_date` --- src/tools/compiletest/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index efa9d05f16c38..1f0b42d1786c1 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -624,7 +624,8 @@ fn is_up_to_date( // Check timestamps. let mut inputs = inputs.clone(); - inputs.add_path(&testpaths.file); + // Use `add_dir` to account for run-make tests, which use their individual directory + inputs.add_dir(&testpaths.file); for aux in &props.aux { let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); From 06b9a73cfa5ef1cb6fb9160d61f1beada2b81b79 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Tue, 14 Jan 2020 20:02:27 +0800 Subject: [PATCH 06/12] Update APIs according to RFC change suggestions. --- src/liballoc/collections/linked_list.rs | 43 +++++++++---- src/liballoc/collections/linked_list/tests.rs | 60 ++++++++++++++++--- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index d7504b0b80bd9..b88ca8a0fb0d1 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -509,20 +509,42 @@ impl LinkedList { IterMut { head: self.head, tail: self.tail, len: self.len, list: self } } - /// Provides a cursor. + /// Provides a cursor at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. #[inline] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor(&self) -> Cursor<'_, T> { + pub fn cursor_front(&self) -> Cursor<'_, T> { Cursor { index: 0, current: self.head, list: self } } - /// Provides a cursor with editing operations. + /// Provides a cursor with editing operations at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. #[inline] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor_mut(&mut self) -> CursorMut<'_, T> { + pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> { CursorMut { index: 0, current: self.head, list: self } } + /// Provides a cursor at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_back(&self) -> Cursor<'_, T> { + Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } + } + + /// Provides a cursor with editing operations at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> { + CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } + } + /// Returns `true` if the `LinkedList` is empty. /// /// This operation should compute in O(1) time. @@ -1146,8 +1168,6 @@ impl fmt::Debug for Cursor<'_, T> { /// Cursors always rest between two elements in the list, and index in a logically circular way. /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and /// tail of the list. -/// -/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub struct CursorMut<'a, T: 'a> { index: usize, @@ -1474,9 +1494,12 @@ impl<'a, T> CursorMut<'a, T> { /// If the cursor is pointing at the "ghost" non-element then the entire contents /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn split_after(self) -> LinkedList { + pub fn split_after(&mut self) -> LinkedList { let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; - // no need to update `self.index` because the cursor is consumed. + if self.index == self.list.len { + // The "ghost" non-element's index has changed to 0. + self.index = 0; + } unsafe { self.list.split_off_after_node(self.current, split_off_idx) } } @@ -1487,9 +1510,9 @@ impl<'a, T> CursorMut<'a, T> { /// If the cursor is pointing at the "ghost" non-element then the entire contents /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn split_before(self) -> LinkedList { + pub fn split_before(&mut self) -> LinkedList { let split_off_idx = self.index; - // no need to update `self.index` because the cursor is consumed. + self.index = 0; unsafe { self.list.split_off_before_node(self.current, split_off_idx) } } } diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs index d223752c7f7ec..085f734ed916a 100644 --- a/src/liballoc/collections/linked_list/tests.rs +++ b/src/liballoc/collections/linked_list/tests.rs @@ -309,7 +309,7 @@ fn drain_to_empty_test() { fn test_cursor_move_peek() { let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); - let mut cursor = m.cursor(); + let mut cursor = m.cursor_front(); assert_eq!(cursor.current(), Some(&1)); assert_eq!(cursor.peek_next(), Some(&2)); assert_eq!(cursor.peek_prev(), None); @@ -326,9 +326,26 @@ fn test_cursor_move_peek() { assert_eq!(cursor.peek_prev(), Some(&1)); assert_eq!(cursor.index(), Some(1)); + let mut cursor = m.cursor_back(); + assert_eq!(cursor.current(), Some(&6)); + assert_eq!(cursor.peek_next(), None); + assert_eq!(cursor.peek_prev(), Some(&5)); + assert_eq!(cursor.index(), Some(5)); + cursor.move_next(); + assert_eq!(cursor.current(), None); + assert_eq!(cursor.peek_next(), Some(&1)); + assert_eq!(cursor.peek_prev(), Some(&6)); + assert_eq!(cursor.index(), None); + cursor.move_prev(); + cursor.move_prev(); + assert_eq!(cursor.current(), Some(&5)); + assert_eq!(cursor.peek_next(), Some(&6)); + assert_eq!(cursor.peek_prev(), Some(&4)); + assert_eq!(cursor.index(), Some(4)); + let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); assert_eq!(cursor.current(), Some(&mut 1)); assert_eq!(cursor.peek_next(), Some(&mut 2)); assert_eq!(cursor.peek_prev(), None); @@ -352,24 +369,51 @@ fn test_cursor_move_peek() { assert_eq!(cursor2.index(), Some(2)); assert_eq!(cursor.current(), Some(&mut 2)); assert_eq!(cursor.index(), Some(1)); + + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let mut cursor = m.cursor_back_mut(); + assert_eq!(cursor.current(), Some(&mut 6)); + assert_eq!(cursor.peek_next(), None); + assert_eq!(cursor.peek_prev(), Some(&mut 5)); + assert_eq!(cursor.index(), Some(5)); + cursor.move_next(); + assert_eq!(cursor.current(), None); + assert_eq!(cursor.peek_next(), Some(&mut 1)); + assert_eq!(cursor.peek_prev(), Some(&mut 6)); + assert_eq!(cursor.index(), None); + cursor.move_prev(); + cursor.move_prev(); + assert_eq!(cursor.current(), Some(&mut 5)); + assert_eq!(cursor.peek_next(), Some(&mut 6)); + assert_eq!(cursor.peek_prev(), Some(&mut 4)); + assert_eq!(cursor.index(), Some(4)); + let mut cursor2 = cursor.as_cursor(); + assert_eq!(cursor2.current(), Some(&5)); + assert_eq!(cursor2.index(), Some(4)); + cursor2.move_prev(); + assert_eq!(cursor2.current(), Some(&4)); + assert_eq!(cursor2.index(), Some(3)); + assert_eq!(cursor.current(), Some(&mut 5)); + assert_eq!(cursor.index(), Some(4)); } #[test] fn test_cursor_mut_insert() { let mut m: LinkedList = LinkedList::new(); m.extend(&[1, 2, 3, 4, 5, 6]); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); cursor.insert_before(7); cursor.insert_after(8); check_links(&m); assert_eq!(m.iter().cloned().collect::>(), &[7, 1, 8, 2, 3, 4, 5, 6]); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); cursor.move_prev(); cursor.insert_before(9); cursor.insert_after(10); check_links(&m); assert_eq!(m.iter().cloned().collect::>(), &[10, 7, 1, 8, 2, 3, 4, 5, 6, 9]); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); cursor.move_prev(); assert_eq!(cursor.remove_current(), None); cursor.move_next(); @@ -383,7 +427,7 @@ fn test_cursor_mut_insert() { assert_eq!(cursor.remove_current(), Some(10)); check_links(&m); assert_eq!(m.iter().cloned().collect::>(), &[1, 8, 2, 3, 4, 5, 6]); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); let mut p: LinkedList = LinkedList::new(); p.extend(&[100, 101, 102, 103]); let mut q: LinkedList = LinkedList::new(); @@ -395,12 +439,12 @@ fn test_cursor_mut_insert() { m.iter().cloned().collect::>(), &[200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6] ); - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); cursor.move_prev(); let tmp = cursor.split_before(); assert_eq!(m.into_iter().collect::>(), &[]); m = tmp; - let mut cursor = m.cursor_mut(); + let mut cursor = m.cursor_front_mut(); cursor.move_next(); cursor.move_next(); cursor.move_next(); From d43615fb7c539e4b140bc446a542a8a1eb6c2120 Mon Sep 17 00:00:00 2001 From: SOFe Date: Wed, 15 Jan 2020 02:07:39 +0800 Subject: [PATCH 07/12] Use 3.6 instead of 3.5 in float fract() documentation It is not self-explanatory whether the fract() function inverts the fractional part of negative numbers. --- src/libstd/f32.rs | 8 ++++---- src/libstd/f64.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 267d7013b1e42..209eea4a5ff73 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -131,10 +131,10 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = 3.5_f32; - /// let y = -3.5_f32; - /// let abs_difference_x = (x.fract() - 0.5).abs(); - /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// let x = 3.6_f32; + /// let y = -3.6_f32; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); /// /// assert!(abs_difference_x <= f32::EPSILON); /// assert!(abs_difference_y <= f32::EPSILON); diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 61ce7b29e26fc..27f97a935a4d5 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -109,10 +109,10 @@ impl f64 { /// # Examples /// /// ``` - /// let x = 3.5_f64; - /// let y = -3.5_f64; + /// let x = 3.6_f64; + /// let y = -3.6_f64; /// let abs_difference_x = (x.fract() - 0.5).abs(); - /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); /// /// assert!(abs_difference_x < 1e-10); /// assert!(abs_difference_y < 1e-10); From 9f1452f6996935f796daadab05a956fd0ae69196 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:26:03 -0800 Subject: [PATCH 08/12] Update libssh2-sys to a version that can build for aarch64-pc-windows-msvc --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..202c297b82de2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1806,9 +1806,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" +checksum = "36aa6e813339d3a063292b77091dfbbb6152ff9006a459895fa5bebed7d34f10" dependencies = [ "cc", "libc", From 535fc9ce4c97598f7cc1a093c9cd506a81e22689 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:52:46 -0800 Subject: [PATCH 09/12] Update iovec to a version with no winapi dependency --- Cargo.lock | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..9eedab0a1d093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1581,12 +1581,11 @@ dependencies = [ [[package]] name = "iovec" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ "libc", - "winapi 0.2.8", ] [[package]] From 9febc2bc7a3a6397ca7e30155924d2d180a5e940 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 11:56:51 -0800 Subject: [PATCH 10/12] Update to a version of cmake with windows arm64 support --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..602e0ae150a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.38" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" +checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" dependencies = [ "cc", ] From 7d6271b76b7ee7a192e03933ed6b37e6e6385c08 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Fri, 10 Jan 2020 09:11:32 -0800 Subject: [PATCH 11/12] Better support for cross compilation on Windows. --- src/bootstrap/native.rs | 2 ++ src/librustc_llvm/build.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index ce977f1bbc44e..89e1a7319cf59 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -230,6 +230,8 @@ impl Step for Llvm { cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); } else if target.contains("freebsd") { cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); + } else if target.contains("windows") { + cfg.define("CMAKE_SYSTEM_NAME", "Windows"); } cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build")); diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index dff20f8741065..405ce0307cd82 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -215,12 +215,14 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg(llvm_link_arg).arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { - if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); - } else if is_crossed { - if lib.starts_with("-L") { + if is_crossed { + if lib.starts_with("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target)); + } else if lib.starts_with("-L") { println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); } + } else if lib.starts_with("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", &lib[9..]); } else if lib.starts_with("-l") { println!("cargo:rustc-link-lib={}", &lib[2..]); } else if lib.starts_with("-L") { From 106fe0b13a60c678c7a3372b8ef3f6160549ad5c Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 13:32:26 -0800 Subject: [PATCH 12/12] Update to a version of compiler_builtins with changes for fixes remainder for aarch64 windows --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4836e15cd799a..08b22e629d221 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,9 +570,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f083abf9bb9005a27d2da62706f661245278cb7096da37ab27410eaf60f2c1" +checksum = "b9975aefa63997ef75ca9cf013ff1bb81487aaa0b622c21053afd3b92979a7af" dependencies = [ "cc", "rustc-std-workspace-core",