use super::*;
use std::convert::{AsMut, AsRef};
use std::ops::Range;
#[cfg(feature = "rayon")]
pub(crate) mod par_iter;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ClumpedOffsets<O = Vec<usize>> {
pub chunk_offsets: Offsets<O>,
pub offsets: Offsets<O>,
}
impl<O: AsRef<[usize]>> Set for ClumpedOffsets<O> {
type Elem = usize;
type Atom = usize;
#[inline]
fn len(&self) -> usize {
self.num_offsets()
}
}
impl<O: AsRef<[usize]>> ClumpedOffsets<O> {
#[inline]
unsafe fn offset_value_and_clump_index_unchecked(&self, index: usize) -> (usize, usize) {
let ((_, off), clump_idx, _) = self.get_chunk_at_unchecked(index);
(off, clump_idx)
}
#[inline]
unsafe fn get_chunk_at_unchecked(&self, index: usize) -> ((usize, usize), usize, bool) {
let ClumpedOffsets {
chunk_offsets,
offsets,
} = self;
debug_assert!(chunk_offsets.num_offsets() > 0);
debug_assert!(offsets.num_offsets() > 0);
match chunk_offsets.binary_search(&index) {
Ok(clump_idx) => (
(
chunk_offsets.offset_value_unchecked(clump_idx),
offsets.offset_value_unchecked(clump_idx),
),
clump_idx,
true,
),
Err(clump_idx) => {
let begin_off = offsets.offset_value_unchecked(clump_idx - 1);
let clump_dist = offsets.offset_value_unchecked(clump_idx) - begin_off;
let begin_clump_off = chunk_offsets.offset_value_unchecked(clump_idx - 1);
let clump_size = chunk_offsets.offset_value_unchecked(clump_idx) - begin_clump_off;
let stride = clump_dist / clump_size;
let chunk_offset = index + chunk_offsets.first_offset_value();
let offset = begin_off + stride * (chunk_offset - begin_clump_off);
((chunk_offset, offset), clump_idx - 1, false)
}
}
}
#[inline]
pub fn first_chunk_offset_value(&self) -> usize {
self.chunk_offsets.first_offset_value()
}
#[inline]
pub fn last_chunk_offset_value(&self) -> usize {
self.chunk_offsets.last_offset_value()
}
#[inline]
pub fn num_clump_offsets(&self) -> usize {
self.offsets.num_offsets()
}
#[inline]
pub fn num_clumps(&self) -> usize {
self.offsets.num_offsets() - 1
}
#[inline]
pub fn clump_stride(&self, index: usize) -> usize {
assert!(index < self.num_clumps(), "Offset index out of bounds");
unsafe {
self.offsets.chunk_len_unchecked(index) / self.chunk_offsets.chunk_len_unchecked(index)
}
}
}
unsafe impl<O: AsRef<[usize]>> GetOffset for ClumpedOffsets<O> {
#[inline]
unsafe fn offset_value_unchecked(&self, index: usize) -> usize {
self.offset_value_and_clump_index_unchecked(index).0
}
fn num_offsets(&self) -> usize {
let offsets = self.chunk_offsets.as_ref();
debug_assert!(!offsets.is_empty(), "Clump offsets are corrupted");
unsafe { 1 + offsets.get_unchecked(offsets.len() - 1) - offsets.get_unchecked(0) }
}
}
impl<O: AsRef<[usize]>> ClumpedOffsets<O> {
#[inline]
pub fn sizes(&self) -> UnclumpedSizes {
debug_assert!(self.chunk_offsets.num_offsets() > 0);
UnclumpedSizes {
iter: UnclumpedOffsetValuesAndSizes {
stride: 0,
cur: self.offsets.first_offset_value(),
clumped_offsets: self.view(),
},
}
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
debug_assert!(!self.offsets.as_ref().is_empty());
let first = self.first_offset_value();
UnclumpedOffsetValues {
cur_stride: 0,
cur_offset: self.offsets.first_offset_value(),
chunk_offsets: self.chunk_offsets.as_ref(),
offsets: self.offsets.as_ref(),
}
.map(move |x| x - first)
}
#[inline]
pub fn values(&self) -> UnclumpedOffsetValues {
debug_assert!(!self.offsets.as_ref().is_empty());
UnclumpedOffsetValues {
cur_stride: 0,
cur_offset: self.offsets.first_offset_value(),
chunk_offsets: self.chunk_offsets.as_ref(),
offsets: self.offsets.as_ref(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnclumpedOffsetValuesAndSizes<'a> {
stride: usize,
cur: usize,
clumped_offsets: ClumpedOffsets<&'a [usize]>,
}
impl<'a> Iterator for UnclumpedOffsetValuesAndSizes<'a> {
type Item = (usize, usize);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let UnclumpedOffsetValuesAndSizes {
stride,
cur,
clumped_offsets: co,
} = self;
let n = co.offsets.num_offsets();
debug_assert!(n > 0);
let offset = co.offsets.first_offset_value();
if *cur == offset {
if n < 2 {
return None;
}
let chunk_offset = co.chunk_offsets.first_offset_value();
unsafe {
co.offsets.remove_prefix_unchecked(1);
co.chunk_offsets.remove_prefix_unchecked(1);
}
let next_offset = co.offsets.first_offset_value();
let next_chunk_offset = co.chunk_offsets.first_offset_value();
let clump_dist = next_offset - offset;
let chunk_size = next_chunk_offset - chunk_offset;
*stride = clump_dist / chunk_size;
}
let off = *cur;
*cur += *stride;
Some((off, *stride))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.clumped_offsets.num_offsets() - 1;
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.size_hint().0
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let UnclumpedOffsetValuesAndSizes {
stride,
cur,
clumped_offsets: co,
} = self;
let first_offset = co.offsets.first_offset_value();
let adjusted_n = if *stride > 0 {
let first_clump_count = (first_offset - *cur) / *stride;
if first_clump_count > n {
*cur += *stride * (n + 1);
return Some((*cur, *stride));
} else {
n - first_clump_count
}
} else {
n
};
if adjusted_n + 1 < co.num_offsets() {
let (cur_off, clump_idx) =
unsafe { co.offset_value_and_clump_index_unchecked(adjusted_n) };
let (offset, chunk_offset, next_offset, next_chunk_offset) = unsafe {
(
co.offsets.offset_value_unchecked(clump_idx),
co.chunk_offsets.offset_value_unchecked(clump_idx),
co.offsets.offset_value_unchecked(clump_idx + 1),
co.chunk_offsets.offset_value_unchecked(clump_idx + 1),
)
};
let clump_dist = next_offset - offset;
let chunk_size = next_chunk_offset - chunk_offset;
*stride = clump_dist / chunk_size;
unsafe {
co.offsets.remove_prefix_unchecked(clump_idx + 1);
co.chunk_offsets.remove_prefix_unchecked(clump_idx + 1);
};
*cur = cur_off + *stride;
Some((cur_off, *stride))
} else {
None
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnclumpedOffsetsAndSizes<'a> {
first_offset_value: usize,
iter: UnclumpedOffsetValuesAndSizes<'a>,
}
impl UnclumpedOffsetsAndSizes<'_> {
#[inline]
fn offset_and_size_mapper(&self) -> impl Fn((usize, usize)) -> (usize, usize) + '_ {
move |(off, size)| (off - self.first_offset_value, size)
}
}
impl<'a> Iterator for UnclumpedOffsetsAndSizes<'a> {
type Item = (usize, usize);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(self.offset_and_size_mapper())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
#[inline]
fn count(self) -> usize {
self.iter.count()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(self.offset_and_size_mapper())
}
}
impl ExactSizeIterator for UnclumpedOffsetsAndSizes<'_> {}
impl std::iter::FusedIterator for UnclumpedOffsetsAndSizes<'_> {}
impl ExactSizeIterator for UnclumpedOffsetValuesAndSizes<'_> {}
impl std::iter::FusedIterator for UnclumpedOffsetValuesAndSizes<'_> {}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnclumpedSizes<'a> {
iter: UnclumpedOffsetValuesAndSizes<'a>,
}
impl<'a> Iterator for UnclumpedSizes<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, size)| size)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
#[inline]
fn count(self) -> usize {
self.iter.count()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(|(_, size)| size)
}
}
impl ExactSizeIterator for UnclumpedSizes<'_> {}
impl std::iter::FusedIterator for UnclumpedSizes<'_> {}
impl<'a> IntoValues for ClumpedOffsets<&'a [usize]> {
type Iter = UnclumpedOffsetValues<'a>;
#[inline]
fn into_values(self) -> UnclumpedOffsetValues<'a> {
debug_assert!(self.chunk_offsets.num_offsets() > 0);
UnclumpedOffsetValues {
cur_stride: 0,
cur_offset: self.offsets.first_offset_value(),
chunk_offsets: self.chunk_offsets.into_inner(),
offsets: self.offsets.into_inner(),
}
}
}
impl<'a> IntoSizes for ClumpedOffsets<&'a [usize]> {
type Iter = UnclumpedSizes<'a>;
#[inline]
fn into_sizes(self) -> UnclumpedSizes<'a> {
debug_assert!(self.chunk_offsets.num_offsets() > 0);
UnclumpedSizes {
iter: UnclumpedOffsetValuesAndSizes {
stride: 0,
cur: self.offsets.first_offset_value(),
clumped_offsets: self,
},
}
}
}
impl<'a> IntoOffsetValuesAndSizes for ClumpedOffsets<&'a [usize]> {
type Iter = UnclumpedOffsetValuesAndSizes<'a>;
#[inline]
fn into_offset_values_and_sizes(self) -> UnclumpedOffsetValuesAndSizes<'a> {
debug_assert!(self.chunk_offsets.num_offsets() > 0);
UnclumpedOffsetValuesAndSizes {
stride: 0,
cur: self.offsets.first_offset_value(),
clumped_offsets: self,
}
}
}
#[derive(Copy, Clone)]
pub struct UnclumpedOffsetValues<'a> {
cur_stride: usize,
cur_offset: usize,
chunk_offsets: &'a [usize],
offsets: &'a [usize],
}
impl<'a> Iterator for UnclumpedOffsetValues<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
let UnclumpedOffsetValues {
cur_stride,
cur_offset,
chunk_offsets,
offsets,
} = self;
if chunk_offsets.is_empty() {
return None;
}
debug_assert_eq!(chunk_offsets.len(), offsets.len());
let offset = unsafe { *offsets.get_unchecked(0) };
if *cur_offset == offset {
let chunk_offset = unsafe { *chunk_offsets.get_unchecked(0) };
unsafe {
self.offsets = offsets.get_unchecked(1..);
self.chunk_offsets = chunk_offsets.get_unchecked(1..);
}
if let Some(next_offset) = self.offsets.get(0) {
let next_chunk_offset = unsafe { self.chunk_offsets.get_unchecked(0) };
let clump_dist = next_offset - offset;
let chunk_size = next_chunk_offset - chunk_offset;
*cur_stride = clump_dist / chunk_size;
*cur_offset += *cur_stride;
}
Some(offset)
} else {
let result = Some(*cur_offset);
*cur_offset += *cur_stride;
result
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self
.chunk_offsets
.last()
.map(|last| {
last - unsafe { *self.chunk_offsets.get_unchecked(0) } + 1
})
.unwrap_or(0);
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.size_hint().0
}
}
impl ExactSizeIterator for UnclumpedOffsetValues<'_> {}
impl std::iter::FusedIterator for UnclumpedOffsetValues<'_> {}
impl<'a> SplitOffsetsAt for ClumpedOffsets<&'a [usize]> {
#[inline]
fn split_offsets_with_intersection_at(
self,
mid_off: usize,
) -> (
ClumpedOffsets<&'a [usize]>,
ClumpedOffsets<&'a [usize]>,
usize,
) {
assert!(mid_off < self.num_offsets());
let mid_idx = self
.chunk_offsets
.binary_search(&mid_off)
.expect("Cannot split clumped offsets through a clump");
let (los, ros, off) = self.offsets.split_offsets_with_intersection_at(mid_idx);
let (lcos, rcos) = self.chunk_offsets.split_offsets_at(mid_idx);
(
ClumpedOffsets {
chunk_offsets: lcos,
offsets: los,
},
ClumpedOffsets {
chunk_offsets: rcos,
offsets: ros,
},
off,
)
}
#[inline]
fn split_offsets_at(
self,
mid: usize,
) -> (ClumpedOffsets<&'a [usize]>, ClumpedOffsets<&'a [usize]>) {
assert!(mid < self.num_offsets());
let mid_idx = self
.chunk_offsets
.binary_search(&mid)
.expect("Cannot split clumped offsets through a clump");
let (los, ros) = self.offsets.split_offsets_at(mid_idx);
let (lcos, rcos) = self.chunk_offsets.split_offsets_at(mid_idx);
(
ClumpedOffsets {
chunk_offsets: lcos,
offsets: los,
},
ClumpedOffsets {
chunk_offsets: rcos,
offsets: ros,
},
)
}
}
impl<O> IndexRange for ClumpedOffsets<O>
where
Self: GetOffset,
{
#[inline]
unsafe fn index_range_unchecked(&self, range: Range<usize>) -> Range<usize> {
let begin = self.offset_unchecked(range.start);
let end = self.offset_unchecked(range.end);
begin..end
}
#[inline]
fn index_range(&self, range: Range<usize>) -> Option<Range<usize>> {
if range.end < self.num_offsets() {
unsafe { Some(self.index_range_unchecked(range)) }
} else {
None
}
}
}
impl std::iter::FromIterator<usize> for ClumpedOffsets {
#[inline]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = usize>,
{
let mut offset_iter = iter.into_iter();
let mut chunk_offsets = Vec::with_capacity(8);
let mut offsets = Vec::with_capacity(16);
chunk_offsets.push(0);
if let Some(first) = offset_iter.next() {
offsets.push(first);
if let Some(mut prev_offset) = offset_iter.next() {
let mut prev_stride = prev_offset - first;
let mut next_chunk_offset = 1;
for offset in offset_iter {
let stride = offset - prev_offset;
if prev_stride != stride {
offsets.push(prev_offset);
chunk_offsets.push(next_chunk_offset);
}
next_chunk_offset += 1;
prev_stride = stride;
prev_offset = offset;
}
offsets.push(prev_offset);
chunk_offsets.push(next_chunk_offset);
}
} else {
offsets.push(0);
}
unsafe {
ClumpedOffsets {
chunk_offsets: Offsets::from_raw(chunk_offsets),
offsets: Offsets::from_raw(offsets),
}
}
}
}
impl<O: Viewed> Viewed for ClumpedOffsets<O> {}
impl<'a, O: AsRef<[usize]>> View<'a> for ClumpedOffsets<O> {
type Type = ClumpedOffsets<&'a [usize]>;
#[inline]
fn view(&'a self) -> Self::Type {
ClumpedOffsets {
chunk_offsets: self.chunk_offsets.view(),
offsets: self.offsets.view(),
}
}
}
impl<'a, O: AsMut<[usize]>> ViewMut<'a> for ClumpedOffsets<O> {
type Type = ClumpedOffsets<&'a mut [usize]>;
#[inline]
fn view_mut(&'a mut self) -> Self::Type {
ClumpedOffsets {
chunk_offsets: self.chunk_offsets.view_mut(),
offsets: self.offsets.view_mut(),
}
}
}
impl<O: AsRef<[usize]> + Set> From<Offsets<O>> for ClumpedOffsets {
#[inline]
fn from(offsets: Offsets<O>) -> Self {
debug_assert!(offsets.num_offsets() > 0, "Offsets are corrupted.");
offsets.values().collect()
}
}
impl<O: AsRef<[usize]> + Set> From<ClumpedOffsets<O>> for Offsets {
#[inline]
fn from(clumped_offsets: ClumpedOffsets<O>) -> Self {
debug_assert!(clumped_offsets.num_offsets() > 0, "Offsets are corrupted.");
Offsets::new(clumped_offsets.values().collect())
}
}
impl<O: AsRef<[usize]>> ClumpedOffsets<O> {
#[inline]
pub fn new(chunk_offsets: O, offsets: O) -> Self {
ClumpedOffsets {
chunk_offsets: Offsets::new(chunk_offsets),
offsets: Offsets::new(offsets),
}
}
#[inline]
pub unsafe fn from_raw(chunk_offsets: O, offsets: O) -> Self {
ClumpedOffsets {
chunk_offsets: Offsets::from_raw(chunk_offsets),
offsets: Offsets::from_raw(offsets),
}
}
}
impl Default for ClumpedOffsets<Vec<usize>> {
#[inline]
fn default() -> Self {
ClumpedOffsets {
chunk_offsets: Default::default(),
offsets: Default::default(),
}
}
}
impl<O: Dummy> Dummy for ClumpedOffsets<O> {
#[inline]
unsafe fn dummy() -> Self {
ClumpedOffsets {
chunk_offsets: Dummy::dummy(),
offsets: Dummy::dummy(),
}
}
}
impl Clear for ClumpedOffsets {
#[inline]
fn clear(&mut self) {
self.chunk_offsets.truncate(1);
self.offsets.truncate(1);
}
}
impl<'a, O> GetIndex<'a, ClumpedOffsets<O>> for usize
where
ClumpedOffsets<O>: GetOffset,
{
type Output = usize;
#[inline]
fn get(self, clumped_offsets: &ClumpedOffsets<O>) -> Option<Self::Output> {
if self < clumped_offsets.num_offsets() {
unsafe { Some(clumped_offsets.offset_unchecked(self)) }
} else {
None
}
}
}
impl<'a, O> GetIndex<'a, ClumpedOffsets<O>> for &usize
where
ClumpedOffsets<O>: GetOffset,
{
type Output = usize;
#[inline]
fn get(self, clumped_offsets: &ClumpedOffsets<O>) -> Option<Self::Output> {
GetIndex::get(*self, clumped_offsets)
}
}
impl<O> IsolateIndex<ClumpedOffsets<O>> for usize
where
ClumpedOffsets<O>: GetOffset,
{
type Output = usize;
#[inline]
unsafe fn isolate_unchecked(self, clumped_offsets: ClumpedOffsets<O>) -> Self::Output {
clumped_offsets.offset_unchecked(self)
}
#[inline]
fn try_isolate(self, clumped_offsets: ClumpedOffsets<O>) -> Option<Self::Output> {
if self < clumped_offsets.num_offsets() {
unsafe { Some(IsolateIndex::isolate_unchecked(self, clumped_offsets)) }
} else {
None
}
}
}
impl<O: Truncate> Truncate for ClumpedOffsets<O> {
#[inline]
fn truncate(&mut self, new_len: usize) {
self.chunk_offsets.truncate(new_len);
self.offsets.truncate(new_len);
}
}
impl<O: RemovePrefix + Set> RemovePrefix for ClumpedOffsets<O> {
#[inline]
fn remove_prefix(&mut self, n: usize) {
self.chunk_offsets.remove_prefix(n);
self.offsets.remove_prefix(n);
}
}
impl<O: IntoOwned> IntoOwned for ClumpedOffsets<O> {
type Owned = ClumpedOffsets<O::Owned>;
#[inline]
fn into_owned(self) -> Self::Owned {
ClumpedOffsets {
chunk_offsets: self.chunk_offsets.into_owned(),
offsets: self.offsets.into_owned(),
}
}
}
impl<O: Reserve> Reserve for ClumpedOffsets<O> {
#[inline]
fn reserve_with_storage(&mut self, n: usize, storage_n: usize) {
self.chunk_offsets.reserve_with_storage(n, storage_n);
self.offsets.reserve_with_storage(n, storage_n);
}
}
impl std::iter::Extend<(usize, usize)> for ClumpedOffsets {
fn extend<T: IntoIterator<Item = (usize, usize)>>(&mut self, iter: T) {
let mut iter = iter.into_iter();
if let Some((first_chunk_offset, first_offset)) = iter.next() {
let last_offset = self.last_offset_value();
let Self {
chunk_offsets,
offsets,
} = self;
chunk_offsets.extend(std::iter::once(first_chunk_offset).chain(iter.map(
|(chunk_offset, offset)| {
offsets.push(offset + last_offset - first_offset);
chunk_offset
},
)));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_offset_at_test() {
let offsets = Offsets::new(vec![3, 6, 9, 12, 15, 19, 23, 27, 30, 33, 36, 39, 42]);
let clumped_offsets = ClumpedOffsets::from(offsets);
let (l, r, off) = clumped_offsets.view().split_offsets_with_intersection_at(4);
assert_eq!(Offsets::from(l).into_inner(), &[3, 6, 9, 12, 15]);
assert_eq!(
Offsets::from(r).into_inner(),
&[15, 19, 23, 27, 30, 33, 36, 39, 42]
);
assert_eq!(off, 12);
let (l, r, off) = clumped_offsets.view().split_offsets_with_intersection_at(0);
assert_eq!(Offsets::from(l).into_inner(), &[3]);
assert_eq!(
Offsets::from(r).into_inner(),
&[3, 6, 9, 12, 15, 19, 23, 27, 30, 33, 36, 39, 42]
);
assert_eq!(off, 0);
let (l, r, off) = clumped_offsets
.view()
.split_offsets_with_intersection_at(12);
assert_eq!(
Offsets::from(l).into_inner(),
&[3, 6, 9, 12, 15, 19, 23, 27, 30, 33, 36, 39, 42]
);
assert_eq!(Offsets::from(r).into_inner(), &[42]);
assert_eq!(off, 39);
}
#[test]
fn iterators() {
let offsets = Offsets::new(vec![3, 6, 9, 12, 16, 20, 24, 27, 30, 33, 36, 39, 42]);
let clumped_offsets = ClumpedOffsets::from(offsets.clone());
assert_eq!(clumped_offsets.offset(6), 21);
for (orig, unclumped) in offsets.values().zip(clumped_offsets.values()) {
assert_eq!(orig, unclumped);
}
for (orig, unclumped) in offsets.sizes().zip(clumped_offsets.sizes()) {
assert_eq!(orig, unclumped);
}
}
#[test]
fn index_range() {
let offsets = Offsets::new(vec![3, 6, 9, 12, 15, 19, 23, 27, 30, 33, 36, 39, 42]);
let clumped_offsets = ClumpedOffsets::from(offsets.clone());
assert_eq!(clumped_offsets.index_range(2..5), Some(6..16));
assert_eq!(clumped_offsets.index_range(0..3), Some(0..9));
assert_eq!(clumped_offsets.index_range(6..8), Some(20..27));
assert_eq!(clumped_offsets.index_range(6..800), None);
}
#[test]
fn clear() {
let mut offsets = ClumpedOffsets::from(Offsets::new(vec![0, 1, 2, 3, 4, 5]));
offsets.clear();
assert_eq!(offsets, ClumpedOffsets::new(vec![0], vec![0]));
}
#[test]
fn get_offset() {
let s = ClumpedOffsets::new(vec![3, 6, 7], vec![2, 11, 15]);
assert_eq!(0, s.offset(0));
assert_eq!(3, s.offset(1));
assert_eq!(6, s.offset(2));
assert_eq!(9, s.offset(3));
assert_eq!(13, s.offset(4));
assert_eq!(2, s.offset_value(0));
assert_eq!(5, s.offset_value(1));
assert_eq!(8, s.offset_value(2));
assert_eq!(11, s.offset_value(3));
assert_eq!(15, s.offset_value(4));
}
#[test]
fn offset_value_iter() {
use ExactSizeIterator;
let offsets = Offsets::new(vec![0, 3, 6, 9, 12, 16, 20, 24, 27, 30, 33, 36, 39]);
let clumped_offsets = ClumpedOffsets::from(offsets.clone());
let iter = clumped_offsets.values();
let iter_len = iter.len();
assert_eq!(iter_len, offsets.num_offsets());
assert_eq!(iter_len, iter.count());
let mut count = 0;
for _ in iter {
count += 1;
}
assert_eq!(iter_len, count);
}
#[test]
fn sizes_iter() {
use ExactSizeIterator;
let offsets = Offsets::new(vec![3, 6, 9, 12, 15, 19, 23, 27, 30, 33, 36, 39, 42]);
let clumped_offsets = ClumpedOffsets::from(offsets.clone());
let mut iter = clumped_offsets.sizes();
let iter_len = iter.len();
assert_eq!(iter_len, offsets.num_offsets() - 1);
assert_eq!(iter_len, iter.count());
for _ in 0..4 {
assert_eq!(iter.next().unwrap(), 3);
}
for _ in 0..3 {
assert_eq!(iter.next().unwrap(), 4);
}
for _ in 0..5 {
assert_eq!(iter.next().unwrap(), 3);
}
assert_eq!(clumped_offsets.sizes().nth(0).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(1).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(2).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(3).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(4).unwrap(), 4);
assert_eq!(clumped_offsets.sizes().nth(5).unwrap(), 4);
assert_eq!(clumped_offsets.sizes().nth(6).unwrap(), 4);
assert_eq!(clumped_offsets.sizes().nth(7).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(8).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(9).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(10).unwrap(), 3);
assert_eq!(clumped_offsets.sizes().nth(11).unwrap(), 3);
let mut count = 0;
for _ in clumped_offsets.sizes() {
count += 1;
}
assert_eq!(iter_len, count);
let mut iter = clumped_offsets.sizes();
assert_eq!(iter.next().unwrap(), 3); assert_eq!(iter.nth(3).unwrap(), 4); assert_eq!(iter.next().unwrap(), 4);
assert_eq!(iter.nth(0).unwrap(), 4); assert_eq!(iter.next().unwrap(), 3);
assert_eq!(iter.nth(3).unwrap(), 3); assert_eq!(iter.next(), None);
assert_eq!(iter.nth(0), None);
let mut iter = clumped_offsets.sizes();
assert_eq!(iter.nth(3).unwrap(), 3); assert_eq!(iter.next().unwrap(), 4);
assert_eq!(iter.nth(2).unwrap(), 3); assert_eq!(iter.next().unwrap(), 3);
assert_eq!(iter.nth(1).unwrap(), 3); assert_eq!(iter.next().unwrap(), 3);
assert_eq!(iter.next(), None);
assert_eq!(iter.nth(0), None);
let mut iter = clumped_offsets.sizes();
assert_eq!(iter.nth(5).unwrap(), 4); }
#[test]
fn extend_clumped_offsets() {
let offsets = Offsets::new(vec![3, 6, 9, 10, 11]);
let mut clumped_offsets = ClumpedOffsets::from(offsets.clone());
let orig_clumped_offsets = clumped_offsets.clone();
clumped_offsets.extend(vec![]); assert_eq!(clumped_offsets, orig_clumped_offsets);
clumped_offsets.extend(vec![(0, 0)]); assert_eq!(clumped_offsets, orig_clumped_offsets);
clumped_offsets.extend(vec![(1, 1), (3, 5)]); let exp_extended_offsets = Offsets::new(vec![3, 6, 9, 10, 11, 13, 15]);
assert_eq!(clumped_offsets, ClumpedOffsets::from(exp_extended_offsets));
}
}