From 687cc292fd681be9739dc973acd5eaa5f73a5ce7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 18 Sep 2018 13:51:20 +1000 Subject: [PATCH] Remove `array_vec.rs`. `SparseBitSet` is the only remaining user of `ArrayVec`. This commit switches it to using `SmallVec`, and removes `array_vec.rs`. Why the switch? Although `SparseBitSet` is size-limited and doesn't need the ability to spill to the heap, `SmallVec` has many more features than `ArrayVec`. In particular, it's now possible to keep `SparseBitSet`'s elements in sorted order, which gives in-order iteration, which is a requirement for the next commit. --- src/librustc_data_structures/array_vec.rs | 305 ---------------------- src/librustc_data_structures/bit_set.rs | 37 +-- src/librustc_data_structures/lib.rs | 1 - 3 files changed, 21 insertions(+), 322 deletions(-) delete mode 100644 src/librustc_data_structures/array_vec.rs diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs deleted file mode 100644 index 45fb565706180..0000000000000 --- a/src/librustc_data_structures/array_vec.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A stack-allocated vector, allowing storage of N elements on the stack. - -use std::marker::Unsize; -use std::iter::Extend; -use std::ptr::{self, drop_in_place, NonNull}; -use std::ops::{Deref, DerefMut, Range}; -use std::hash::{Hash, Hasher}; -use std::slice; -use std::fmt; -use std::mem; -use std::mem::ManuallyDrop; -use std::ops::Bound::{Excluded, Included, Unbounded}; -use std::ops::RangeBounds; - -pub unsafe trait Array { - type Element; - type PartialStorage: Unsize<[ManuallyDrop]>; - const LEN: usize; -} - -unsafe impl Array for [T; 1] { - type Element = T; - type PartialStorage = [ManuallyDrop; 1]; - const LEN: usize = 1; -} - -unsafe impl Array for [T; 8] { - type Element = T; - type PartialStorage = [ManuallyDrop; 8]; - const LEN: usize = 8; -} - -unsafe impl Array for [T; 32] { - type Element = T; - type PartialStorage = [ManuallyDrop; 32]; - const LEN: usize = 32; -} - -pub struct ArrayVec { - count: usize, - values: A::PartialStorage -} - -impl Hash for ArrayVec - where A: Array, - A::Element: Hash { - fn hash(&self, state: &mut H) where H: Hasher { - (&self[..]).hash(state); - } -} - -impl Clone for ArrayVec - where A: Array, - A::Element: Clone { - fn clone(&self) -> Self { - let mut v = ArrayVec::new(); - v.extend(self.iter().cloned()); - v - } -} - -impl ArrayVec { - pub fn new() -> Self { - ArrayVec { - count: 0, - values: unsafe { ::std::mem::uninitialized() }, - } - } - - pub fn len(&self) -> usize { - self.count - } - - pub unsafe fn set_len(&mut self, len: usize) { - self.count = len; - } - - /// Panics when the stack vector is full. - pub fn push(&mut self, el: A::Element) { - let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop::new(el); - self.count += 1; - } - - pub fn pop(&mut self) -> Option { - if self.count > 0 { - let arr = &mut self.values as &mut [ManuallyDrop<_>]; - self.count -= 1; - unsafe { - let value = ptr::read(&*arr[self.count]); - Some(value) - } - } else { - None - } - } - - pub fn drain(&mut self, range: R) -> Drain - where R: RangeBounds - { - // Memory safety - // - // When the Drain is first created, it shortens the length of - // the source vector to make sure no uninitialized or moved-from elements - // are accessible at all if the Drain's destructor never gets to run. - // - // Drain will ptr::read out the values to remove. - // When finished, remaining tail of the vec is copied back to cover - // the hole, and the vector length is restored to the new length. - // - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - assert!(start <= end); - assert!(end <= len); - - unsafe { - // set self.vec length's to start, to be safe in case Drain is leaked - self.set_len(start); - // Use the borrow in the IterMut to indicate borrowing behavior of the - // whole Drain iterator (like &mut T). - let range_slice = { - let arr = &mut self.values as &mut [ManuallyDrop<::Element>]; - slice::from_raw_parts_mut(arr.as_mut_ptr().add(start), - end - start) - }; - Drain { - tail_start: end, - tail_len: len - end, - iter: range_slice.iter(), - array_vec: NonNull::from(self), - } - } - } -} - -impl Default for ArrayVec - where A: Array { - fn default() -> Self { - ArrayVec::new() - } -} - -impl fmt::Debug for ArrayVec - where A: Array, - A::Element: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self[..].fmt(f) - } -} - -impl Deref for ArrayVec { - type Target = [A::Element]; - fn deref(&self) -> &Self::Target { - unsafe { - slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count) - } - } -} - -impl DerefMut for ArrayVec { - fn deref_mut(&mut self) -> &mut [A::Element] { - unsafe { - slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count) - } - } -} - -impl Drop for ArrayVec { - fn drop(&mut self) { - unsafe { - drop_in_place(&mut self[..]) - } - } -} - -impl Extend for ArrayVec { - fn extend(&mut self, iter: I) where I: IntoIterator { - for el in iter { - self.push(el); - } - } -} - -pub struct Iter { - indices: Range, - store: A::PartialStorage, -} - -impl Drop for Iter { - fn drop(&mut self) { - self.for_each(drop); - } -} - -impl Iterator for Iter { - type Item = A::Element; - - fn next(&mut self) -> Option { - let arr = &self.store as &[ManuallyDrop<_>]; - unsafe { - self.indices.next().map(|i| ptr::read(&*arr[i])) - } - } - - fn size_hint(&self) -> (usize, Option) { - self.indices.size_hint() - } -} - -pub struct Drain<'a, A: Array> - where A::Element: 'a -{ - tail_start: usize, - tail_len: usize, - iter: slice::Iter<'a, ManuallyDrop>, - array_vec: NonNull>, -} - -impl<'a, A: Array> Iterator for Drain<'a, A> { - type Item = A::Element; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, A: Array> Drop for Drain<'a, A> { - fn drop(&mut self) { - // exhaust self first - self.for_each(drop); - - if self.tail_len > 0 { - unsafe { - let source_array_vec: &mut ArrayVec = self.array_vec.as_mut(); - // memmove back untouched tail, update to new length - let start = source_array_vec.len(); - let tail = self.tail_start; - { - let arr = - &mut source_array_vec.values as &mut [ManuallyDrop<::Element>]; - let src = arr.as_ptr().add(tail); - let dst = arr.as_mut_ptr().add(start); - ptr::copy(src, dst, self.tail_len); - }; - source_array_vec.set_len(start + self.tail_len); - } - } - } -} - -impl IntoIterator for ArrayVec { - type Item = A::Element; - type IntoIter = Iter; - fn into_iter(self) -> Self::IntoIter { - let store = unsafe { - ptr::read(&self.values) - }; - let indices = 0..self.count; - mem::forget(self); - Iter { - indices, - store, - } - } -} - -impl<'a, A: Array> IntoIterator for &'a ArrayVec { - type Item = &'a A::Element; - type IntoIter = slice::Iter<'a, A::Element>; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { - type Item = &'a mut A::Element; - type IntoIter = slice::IterMut<'a, A::Element>; - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} diff --git a/src/librustc_data_structures/bit_set.rs b/src/librustc_data_structures/bit_set.rs index 19a407b2a3bff..d9e928559322d 100644 --- a/src/librustc_data_structures/bit_set.rs +++ b/src/librustc_data_structures/bit_set.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use array_vec::ArrayVec; use indexed_vec::{Idx, IndexVec}; use rustc_serialize; +use smallvec::SmallVec; use std::fmt; use std::iter; use std::marker::PhantomData; @@ -320,16 +320,17 @@ fn bitwise(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool const SPARSE_MAX: usize = 8; /// A fixed-size bitset type with a sparse representation and a maximum of -/// SPARSE_MAX elements. The elements are stored as an unsorted vector with no -/// duplicates. +/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with +/// no duplicates; although `SmallVec` can spill its elements to the heap, that +/// never happens within this type because of the `SPARSE_MAX` limit. /// -/// This type is used by HybridBitSet; do not use directly. +/// This type is used by `HybridBitSet`; do not use directly. #[derive(Clone, Debug)] -pub struct SparseBitSet(ArrayVec<[T; SPARSE_MAX]>); +pub struct SparseBitSet(SmallVec<[T; SPARSE_MAX]>); impl SparseBitSet { fn new_empty() -> Self { - SparseBitSet(ArrayVec::new()) + SparseBitSet(SmallVec::new()) } fn len(&self) -> usize { @@ -341,10 +342,18 @@ impl SparseBitSet { } fn insert(&mut self, elem: T) -> bool { - // Ensure there are no duplicates. - if self.0.contains(&elem) { - false + assert!(self.len() < SPARSE_MAX); + if let Some(i) = self.0.iter().position(|&e| e >= elem) { + if self.0[i] == elem { + // `elem` is already in the set. + false + } else { + // `elem` is smaller than one or more existing elements. + self.0.insert(i, elem); + true + } } else { + // `elem` is larger than all existing elements. self.0.push(elem); true } @@ -352,10 +361,7 @@ impl SparseBitSet { fn remove(&mut self, elem: T) -> bool { if let Some(i) = self.0.iter().position(|&e| e == elem) { - // Swap the found element to the end, then pop it. - let len = self.0.len(); - self.0.swap(i, len - 1); - self.0.pop(); + self.0.remove(i); true } else { false @@ -396,8 +402,8 @@ impl SubtractFromBitSet for SparseBitSet { } /// A fixed-size bitset type with a hybrid representation: sparse when there -/// are up to a SPARSE_MAX elements in the set, but dense when there are more -/// than SPARSE_MAX. +/// are up to a `SPARSE_MAX` elements in the set, but dense when there are more +/// than `SPARSE_MAX`. /// /// This type is especially efficient for sets that typically have a small /// number of elements, but a large `domain_size`, and are cleared frequently. @@ -479,7 +485,6 @@ impl HybridBitSet { } } - /// Iteration order is unspecified. pub fn iter(&self) -> HybridIter { match self { HybridBitSet::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()), diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1d7557953e976..70b960ac351c0 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -60,7 +60,6 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; pub mod svh; -pub mod array_vec; pub mod base_n; pub mod bit_set; pub mod const_cstr;