#![allow(clippy::comparison_chain)]
#[cfg(test)]
mod tests;
mod mem_config;
pub use mem_config::*;
mod slice;
pub use slice::*;
pub mod detail {
#[cfg(feature = "thin-segments")]
pub type Segment<T> = thin_vec::ThinVec<T>;
#[cfg(not(feature = "thin-segments"))]
pub type Segment<T> = Vec<T>;
#[cfg(feature = "small-vec")]
pub type Segments<T> = smallvec::SmallVec<[Segment<T>; 3]>;
#[cfg(not(feature = "small-vec"))]
pub type Segments<T> = Vec<Segment<T>>;
}
use std::cmp;
use std::default::Default;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::{Flatten, FromIterator, FusedIterator};
use std::mem;
use std::ops::{Bound, Index, IndexMut, RangeBounds};
pub struct SegVec<T, C: MemConfig = Exponential<1>> {
len: usize,
segments: detail::Segments<T>,
config: C,
}
impl<T, C: MemConfig> SegVec<T, C> {
pub fn new() -> Self {
C::debug_assert_config();
SegVec {
len: 0,
segments: detail::Segments::new(),
config: C::new(),
}
}
pub fn with_capacity(capacity_hint: usize) -> Self {
let mut v = SegVec::new();
v.reserve(capacity_hint);
v
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.config.capacity(self.segments.len())
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
let min_cap = match self.len().checked_add(additional) {
Some(c) => c,
None => capacity_overflow(),
};
if min_cap > self.capacity() {
self.reserve_cold(min_cap);
}
}
#[cold]
fn reserve_cold(&mut self, min_cap: usize) {
let (segment, _) = self.config.segment_and_offset(min_cap - 1);
for i in self.segments.len()..=segment {
let seg_size = self.config.segment_size(i);
self.segments.push(detail::Segment::with_capacity(seg_size));
}
self.config.update_capacity(self.segments.len());
}
pub fn get(&self, index: usize) -> Option<&T> {
if index < self.len {
let (seg, offset) = self.config.segment_and_offset(index);
unsafe { Some(self.segments.get_unchecked(seg).get_unchecked(offset)) }
} else {
None
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index < self.len {
let (seg, offset) = self.config.segment_and_offset(index);
unsafe {
Some(
self.segments
.get_unchecked_mut(seg)
.get_unchecked_mut(offset),
)
}
} else {
None
}
}
pub fn push(&mut self, val: T) {
self.reserve(1);
let (seg, _) = self.config.segment_and_offset(self.len);
unsafe {
self.segments.get_unchecked_mut(seg).push(val);
}
self.len += 1;
}
pub fn pop(&mut self) -> Option<T> {
match self.len {
0 => None,
size => {
let (seg, offset) = self.config.segment_and_offset(size);
self.len -= 1;
match offset {
0 => unsafe { self.segments.get_unchecked_mut(seg - 1).pop() },
_ => unsafe { self.segments.get_unchecked_mut(seg).pop() },
}
}
}
}
pub fn truncate(&mut self, len: usize) {
if len < self.capacity() {
let (seg, offset) = self.config.segment_and_offset(len);
if offset == 0 {
self.segments.drain(seg..);
} else {
if len < self.len {
unsafe { self.segments.get_unchecked_mut(seg).drain(offset..) };
}
self.segments.drain(seg + 1..);
}
self.len = len;
self.config.update_capacity(self.segments.len());
}
}
pub fn resize_with<F>(&mut self, new_len: usize, f: F)
where
F: FnMut() -> T,
{
let cur_len = self.len();
if new_len > cur_len {
let to_add = new_len - cur_len;
self.extend(std::iter::repeat_with(f).take(to_add));
} else if new_len < cur_len {
self.truncate(new_len);
}
}
pub fn resize(&mut self, new_len: usize, val: T)
where
T: Clone,
{
let cur_len = self.len();
if new_len > cur_len {
let to_add = new_len - cur_len;
self.extend(std::iter::repeat(val).take(to_add));
} else if new_len < cur_len {
self.truncate(new_len);
}
}
pub fn iter(&self) -> Iter<T> {
Iter {
size: self.len,
iter: self.segments.iter().flatten(),
}
}
pub fn insert(&mut self, index: usize, val: T) {
if index > self.len {
index_oob("SegVec::insert", index, self.len);
}
if mem::size_of::<T>() == 0 {
self.push(val);
return;
}
self.reserve(1);
let (mut seg_idx, mut seg_offset) = self.config.segment_and_offset(index);
let mut displaced = val;
loop {
let maybe_displaced = unsafe {
let segment = self.segments.get_unchecked_mut(seg_idx);
let seg_len = segment.len();
let seg_cap = segment.capacity();
if seg_len == 0 {
debug_assert!(
seg_offset == 0,
"expected offset == 0 when inserting into an empty segment"
);
segment.push(displaced);
None
} else if seg_len < seg_cap {
debug_assert!(
seg_offset <= seg_len,
"expected offset <= len when inserting into a partially full segment"
);
let src_ptr = segment.as_mut_ptr().add(seg_offset);
let dst_ptr = src_ptr.add(1);
std::ptr::copy(src_ptr, dst_ptr, seg_len - seg_offset);
std::ptr::write(src_ptr, displaced);
segment.set_len(seg_len + 1);
None
} else {
debug_assert!(
seg_offset < seg_len,
"expected offset < len when inserting into a full segment"
);
let new_displaced = std::ptr::read(segment.get_unchecked_mut(seg_len - 1));
let src_ptr = segment.as_mut_ptr().add(seg_offset);
let dst_ptr = src_ptr.add(1);
std::ptr::copy(src_ptr, dst_ptr, seg_len - seg_offset - 1);
std::ptr::write(src_ptr, displaced);
Some(new_displaced)
}
};
match maybe_displaced {
Some(new_displaced) => {
displaced = new_displaced;
seg_idx += 1;
seg_offset = 0;
}
None => break,
}
}
self.len += 1
}
pub fn remove(&mut self, index: usize) -> T {
if index >= self.len {
index_oob("SegVec::remove", index, self.len);
}
if mem::size_of::<T>() == 0 {
return self.pop().unwrap();
}
let (mut seg_idx, seg_offset) = self.config.segment_and_offset(index);
let segment = unsafe { self.segments.get_unchecked(seg_idx) };
let removed = unsafe { std::ptr::read(segment.get_unchecked(seg_offset)) };
let mut orig_len = segment.len();
let mut orig_cap = segment.capacity();
unsafe {
let segment_mut = self.segments.get_unchecked_mut(seg_idx);
let dst_ptr = segment_mut.get_unchecked_mut(seg_offset) as *mut T;
let src_ptr = dst_ptr.add(1);
std::ptr::copy(src_ptr, dst_ptr, orig_len - seg_offset - 1);
segment_mut.set_len(orig_len - 1);
}
while orig_len == orig_cap {
seg_idx += 1;
if seg_idx >= self.segments.len() {
break;
}
let segment = unsafe { self.segments.get_unchecked(seg_idx) };
orig_len = segment.len();
orig_cap = segment.capacity();
if orig_len > 0 {
let displaced = unsafe {
std::ptr::read(
self.segments
.get_unchecked_mut(seg_idx)
.get_unchecked_mut(0),
)
};
unsafe {
self.segments.get_unchecked_mut(seg_idx - 1).push(displaced);
let segment_mut = self.segments.get_unchecked_mut(seg_idx);
let dst_ptr = segment_mut.as_mut_ptr();
let src_ptr = dst_ptr.add(1);
std::ptr::copy(src_ptr, dst_ptr, orig_len - 1);
segment_mut.set_len(orig_len - 1);
}
}
}
self.len -= 1;
removed
}
pub fn drain<R>(&mut self, range: R) -> Drain<T, C>
where
R: RangeBounds<usize>,
{
let (start, end) = bounds(self.len, "SegVec::drain", range);
Drain {
inner: self,
drained: 0,
index: start,
total: end - start,
}
}
pub fn slice<R>(&self, range: R) -> Slice<'_, T>
where
R: RangeBounds<usize>,
{
let (start, end) = bounds(self.len, "SegVec::slice", range);
Slice::new(self, start, end - start)
}
pub fn slice_mut<R>(&mut self, range: R) -> SliceMut<'_, T>
where
R: RangeBounds<usize>,
{
let (start, end) = bounds(self.len, "SegVec::slice_mut", range);
SliceMut::new(self, start, end - start)
}
pub fn reverse(&mut self) {
if self.len() < 2 {
return;
}
let mut left = 0;
let mut right = self.len() - 1;
while left < right {
self.swap(left, right);
left += 1;
right -= 1;
}
}
pub fn sort_unstable(&mut self)
where
T: Ord,
{
self.sort_unstable_by(Ord::cmp)
}
fn _sort_partition<F>(&mut self, lo: usize, hi: usize, compare: &mut F) -> usize
where
F: FnMut(&T, &T) -> cmp::Ordering,
{
let pivot = lo;
let mut left = lo;
let mut right = hi + 1;
while left < right {
loop {
left += 1;
if left >= right || compare(&self[pivot], &self[left]).is_lt() {
break;
}
}
loop {
right -= 1;
if right <= left || compare(&self[right], &self[pivot]).is_lt() {
break;
}
}
if right > left {
self.swap(right, left);
}
}
let final_pivot_location = if compare(&self[right], &self[pivot]).is_lt() {
right
} else {
right - 1
};
self.swap(final_pivot_location, pivot);
final_pivot_location
}
fn _sort_quicksort<F>(&mut self, lo: usize, hi: usize, compare: &mut F)
where
F: FnMut(&T, &T) -> cmp::Ordering,
{
if hi > lo {
match hi - lo {
1 => {
if compare(&self[hi], &self[lo]).is_lt() {
self.swap(lo, hi);
}
}
_ => {
let mid = self._sort_partition(lo, hi, compare);
if mid > lo {
self._sort_quicksort(lo, mid - 1, compare);
}
if mid < hi {
self._sort_quicksort(mid + 1, hi, compare);
}
}
}
}
}
pub fn sort_unstable_by<F>(&mut self, mut compare: F)
where
F: FnMut(&T, &T) -> cmp::Ordering,
{
match self.len() {
..=1 => {}
len => self._sort_quicksort(0, len - 1, &mut compare),
}
}
fn swap(&mut self, a: usize, b: usize) {
if a != b && std::mem::size_of::<T>() > 0 {
let a_ptr = &mut self[a] as *mut T;
let b_ptr = &mut self[b] as *mut T;
unsafe { std::ptr::swap(a_ptr, b_ptr) };
}
}
}
impl<T, C: MemConfig> Default for SegVec<T, C> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone, C: MemConfig> Clone for SegVec<T, C> {
fn clone(&self) -> Self {
SegVec {
len: self.len,
segments: self.segments.clone(),
config: C::new(),
}
}
}
impl<T, C: MemConfig> Index<usize> for SegVec<T, C> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
match self.get(index) {
Some(t) => t,
None => index_oob("SegVec::index", index, self.len),
}
}
}
impl<T, C: MemConfig> IndexMut<usize> for SegVec<T, C> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let size = self.len;
match self.get_mut(index) {
Some(t) => t,
None => index_oob("SegVec::index_mut", index, size),
}
}
}
impl<T: Debug, C: MemConfig> Debug for SegVec<T, C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T: Hash, C: MemConfig> Hash for SegVec<T, C> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.iter().for_each(|i| i.hash(state));
}
}
impl<T, C: MemConfig> PartialEq for SegVec<T, C>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
(0..self.len()).all(|i| self[i] == other[i])
}
}
impl<T, C: MemConfig> Eq for SegVec<T, C> where Self: PartialEq {}
impl<T, C: MemConfig> Extend<T> for SegVec<T, C> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let iter = iter.into_iter();
let (min_size, max_size) = iter.size_hint();
let additional = std::cmp::max(max_size.unwrap_or(0), min_size);
self.reserve(additional);
for i in iter {
self.push(i);
}
}
}
impl<'a, T: Copy + 'a, C: MemConfig> Extend<&'a T> for SegVec<T, C> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
<Self as Extend<T>>::extend(self, iter.into_iter().copied())
}
}
impl<T, C: MemConfig> FromIterator<T> for SegVec<T, C> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut v = SegVec::new();
v.extend(iter);
v
}
}
impl<'a, T: Clone + 'a, C: MemConfig> FromIterator<&'a T> for SegVec<T, C> {
fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self {
let mut v = SegVec::new();
v.extend(iter.into_iter().cloned());
v
}
}
impl<T, C: MemConfig> IntoIterator for SegVec<T, C> {
type IntoIter = IntoIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
size: self.len,
iter: self.segments.into_iter().flatten(),
}
}
}
pub struct Iter<'a, T> {
size: usize,
iter: std::iter::Flatten<std::slice::Iter<'a, detail::Segment<T>>>,
}
impl<'a, T: 'a> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(i) => {
self.size -= 1;
Some(i)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.size, Some(self.size))
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match self.iter.next_back() {
Some(i) => {
self.size -= 1;
Some(i)
}
None => None,
}
}
}
impl<'a, T> FusedIterator for Iter<'a, T> {}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
pub struct IntoIter<T> {
size: usize,
iter: std::iter::Flatten<<detail::Segments<T> as std::iter::IntoIterator>::IntoIter>,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(i) => {
self.size -= 1;
Some(i)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.size, Some(self.size))
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
match self.iter.next_back() {
Some(i) => {
self.size -= 1;
Some(i)
}
None => None,
}
}
}
impl<T> FusedIterator for IntoIter<T> {}
impl<T> ExactSizeIterator for IntoIter<T> {}
pub struct Drain<'a, T, C: MemConfig> {
inner: &'a mut SegVec<T, C>,
index: usize,
total: usize,
drained: usize,
}
impl<'a, T, C: MemConfig> Iterator for Drain<'a, T, C> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.drained < self.total {
let next = self.inner.remove(self.index);
self.drained += 1;
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let left = self.total - self.drained;
(left, Some(left))
}
}
impl<'a, T, C: MemConfig> DoubleEndedIterator for Drain<'a, T, C> {
fn next_back(&mut self) -> Option<Self::Item> {
let left = self.total - self.drained;
if left > 0 {
let next = self.inner.remove(self.index + (left - 1));
self.drained += 1;
Some(next)
} else {
None
}
}
}
impl<'a, T, C: MemConfig> FusedIterator for Drain<'a, T, C> {}
impl<'a, T, C: MemConfig> ExactSizeIterator for Drain<'a, T, C> {}
impl<'a, T, C: MemConfig> Drop for Drain<'a, T, C> {
fn drop(&mut self) {
self.for_each(drop);
}
}
#[cold]
fn capacity_overflow() -> ! {
panic!("SegVec: capacity overflow")
}
#[cold]
fn index_oob(caller: &str, idx: usize, len: usize) -> ! {
panic!(
"{}: index out of bounds: index is {}, len is {}",
caller, idx, len
)
}
fn bounds<R>(len: usize, caller: &str, range: R) -> (usize, usize)
where
R: RangeBounds<usize>,
{
let start = range.start_bound();
let start = match start {
Bound::Included(&start) => start,
Bound::Excluded(start) => start.checked_add(1).expect("start bound fits into usize"),
Bound::Unbounded => 0,
};
let end = range.end_bound();
let end = match end {
Bound::Included(end) => end.checked_add(1).expect("end bound fits into usize"),
Bound::Excluded(&end) => end,
Bound::Unbounded => len,
};
if start > end {
panic!("{}: lower bound {} > upper bound {}", caller, start, end);
}
if end > len {
index_oob(caller, end, len);
}
(start, end)
}