1#[cfg(feature = "serde")]
7use super::serde_traits::IndPtrBaseShadow;
8use crate::errors::StructureError;
9use crate::indexing::SpIndex;
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12use std::ops::Range;
13use std::ops::{Deref, DerefMut};
14
15#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(
18 feature = "serde",
19 serde(try_from = "IndPtrBaseShadow<Iptr, Storage>")
20)]
21pub struct IndPtrBase<Iptr, Storage>
22where
23 Iptr: SpIndex,
24 Storage: Deref<Target = [Iptr]>,
25{
26 storage: Storage,
27}
28
29pub type IndPtr<Iptr> = IndPtrBase<Iptr, Vec<Iptr>>;
30pub type IndPtrView<'a, Iptr> = IndPtrBase<Iptr, &'a [Iptr]>;
31
32impl<Iptr, Storage> IndPtrBase<Iptr, Storage>
33where
34 Iptr: SpIndex,
35 Storage: Deref<Target = [Iptr]>,
36{
37 pub(crate) fn check_structure(
38 storage: &Storage,
39 ) -> Result<(), StructureError> {
40 for i in storage.iter() {
41 if i.try_index().is_none() {
42 return Err(StructureError::OutOfRange(
43 "Indptr value out of range of usize",
44 ));
45 }
46 }
47 if !storage
48 .windows(2)
49 .all(|x| x[0].index_unchecked() <= x[1].index_unchecked())
50 {
51 return Err(StructureError::Unsorted("Unsorted indptr"));
52 }
53 if storage
54 .last()
55 .copied()
56 .map(Iptr::index_unchecked)
57 .is_some_and(|i| i > usize::MAX / 2)
58 {
59 return Err(StructureError::OutOfRange(
65 "An indptr value is larger than allowed",
66 ));
67 }
68 if storage.len() == 0 {
69 return Err(StructureError::SizeMismatch(
71 "An indptr should have its len >= 1",
72 ));
73 }
74 Ok(())
75 }
76
77 pub fn new_checked(
78 storage: Storage,
79 ) -> Result<Self, (Storage, StructureError)> {
80 match Self::check_structure(&storage) {
81 Ok(_) => Ok(Self::new_trusted(storage)),
82 Err(e) => Err((storage, e)),
83 }
84 }
85
86 pub(crate) fn new_trusted(storage: Storage) -> Self {
87 Self { storage }
88 }
89
90 pub fn view(&self) -> IndPtrView<'_, Iptr> {
91 IndPtrView {
92 storage: &self.storage[..],
93 }
94 }
95
96 pub fn len(&self) -> usize {
98 self.storage.len()
99 }
100
101 pub fn is_empty(&self) -> bool {
103 debug_assert!(self.storage.len() != 0);
106 self.storage.len() <= 1
107 }
108
109 pub fn outer_dims(&self) -> usize {
111 if self.storage.len() >= 1 {
112 self.storage.len() - 1
113 } else {
114 0
115 }
116 }
117
118 pub fn is_proper(&self) -> bool {
123 self.storage.first().is_some_and(|i| *i == Iptr::zero())
124 }
125
126 pub fn as_slice(&self) -> Option<&[Iptr]> {
130 if self.is_proper() {
131 Some(&self.storage[..])
132 } else {
133 None
134 }
135 }
136
137 pub fn raw_storage(&self) -> &[Iptr] {
141 &self.storage[..]
142 }
143
144 pub(crate) fn raw_storage_mut(&mut self) -> &mut [Iptr]
147 where
148 Storage: DerefMut<Target = [Iptr]>,
149 {
150 &mut self.storage[..]
151 }
152
153 pub fn into_raw_storage(self) -> Storage {
155 self.storage
156 }
157
158 pub fn to_owned(&self) -> IndPtr<Iptr> {
159 IndPtr {
160 storage: self.storage.to_vec(),
161 }
162 }
163
164 pub fn to_proper(&self) -> std::borrow::Cow<'_, [Iptr]> {
207 if self.is_proper() {
208 std::borrow::Cow::Borrowed(&self.storage[..])
209 } else {
210 let offset = self.offset();
211 let proper = self.storage.iter().map(|i| *i - offset).collect();
212 std::borrow::Cow::Owned(proper)
213 }
214 }
215
216 fn offset(&self) -> Iptr {
217 let zero = Iptr::zero();
218 self.storage.first().copied().unwrap_or(zero)
219 }
220
221 pub fn iter_outer_nnz_inds(
224 &self,
225 ) -> impl std::iter::DoubleEndedIterator<Item = usize>
226 + std::iter::ExactSizeIterator<Item = usize>
227 + '_ {
228 let mut cur_outer = 0;
229 (0..self.nnz()).map(move |i| {
230 loop {
234 let nnz_end = self.outer_inds_sz(cur_outer).end;
235 if i == nnz_end {
236 cur_outer += 1;
237 } else {
238 break;
239 }
240 }
241 cur_outer
242 })
243 }
244
245 pub fn iter_outer(
248 &self,
249 ) -> impl std::iter::DoubleEndedIterator<Item = Range<Iptr>>
250 + std::iter::ExactSizeIterator<Item = Range<Iptr>>
251 + '_ {
252 let offset = self.offset();
253 self.storage.windows(2).map(move |x| {
254 if offset == Iptr::zero() {
255 x[0]..x[1]
256 } else {
257 (x[0] - offset)..(x[1] - offset)
258 }
259 })
260 }
261
262 pub fn iter_outer_sz(
267 &self,
268 ) -> impl std::iter::DoubleEndedIterator<Item = Range<usize>>
269 + std::iter::ExactSizeIterator<Item = Range<usize>>
270 + '_ {
271 self.iter_outer().map(|range| {
272 range.start.index_unchecked()..range.end.index_unchecked()
273 })
274 }
275
276 pub fn index(&self, i: usize) -> Iptr {
279 let offset = self.offset();
280 self.storage[i] - offset
281 }
282
283 pub fn outer_inds(&self, i: usize) -> Range<Iptr> {
289 assert!(i + 1 < self.storage.len());
290 let offset = self.offset();
291 (self.storage[i] - offset)..(self.storage[i + 1] - offset)
292 }
293
294 pub fn outer_inds_sz(&self, i: usize) -> Range<usize> {
302 let range = self.outer_inds(i);
303 range.start.index_unchecked()..range.end.index_unchecked()
304 }
305
306 pub fn nnz_in_outer(&self, i: usize) -> Iptr {
312 assert!(i + 1 < self.storage.len());
313 self.storage[i + 1] - self.storage[i]
314 }
315
316 pub fn nnz_in_outer_sz(&self, i: usize) -> usize {
324 self.nnz_in_outer(i).index_unchecked()
325 }
326
327 pub fn outer_inds_slice(&self, start: usize, end: usize) -> Range<usize> {
333 let off = self.offset();
334 let range = (self.storage[start] - off)..(self.storage[end] - off);
335 range.start.index_unchecked()..range.end.index_unchecked()
336 }
337
338 pub fn nnz(&self) -> usize {
340 let offset = self.offset();
341 self.storage
344 .last()
345 .map(|i| *i - offset)
346 .map_or(0, Iptr::index_unchecked)
347 }
348
349 pub fn nnz_i(&self) -> Iptr {
352 let offset = self.offset();
353 let zero = Iptr::zero();
354 self.storage.last().map_or(zero, |i| *i - offset)
357 }
358
359 pub(crate) fn middle_slice(
362 &self,
363 range: impl crate::range::Range,
364 ) -> IndPtrView<'_, Iptr> {
365 self.view().middle_slice_rbr(range)
366 }
367}
368
369impl<Iptr: SpIndex> IndPtr<Iptr> {
370 pub(crate) fn reserve(&mut self, cap: usize) {
372 self.storage.reserve(cap);
373 }
374
375 pub(crate) fn reserve_exact(&mut self, cap: usize) {
377 self.storage.reserve_exact(cap);
378 }
379
380 pub(crate) fn push(&mut self, elem: Iptr) {
383 self.storage.push(elem);
384 }
385
386 pub(crate) fn resize(&mut self, new_len: usize, value: Iptr) {
390 self.storage.resize(new_len, value);
391 }
392
393 pub(crate) fn record_new_element(&mut self, outer_ind: usize) {
396 for val in self.storage[outer_ind + 1..].iter_mut() {
397 *val += Iptr::one();
398 }
399 }
400}
401
402impl<'a, Iptr: SpIndex> IndPtrView<'a, Iptr> {
403 pub(crate) fn middle_slice_rbr(
407 &self,
408 range: impl crate::range::Range,
409 ) -> IndPtrView<'a, Iptr> {
410 let start = range.start();
411 let end = range.end().unwrap_or_else(|| self.outer_dims());
412 IndPtrView {
413 storage: &self.storage[start..=end],
414 }
415 }
416
417 pub(crate) fn reborrow(&self) -> IndPtrView<'a, Iptr> {
419 IndPtrView {
420 storage: &self.storage[..],
421 }
422 }
423}
424
425impl<Iptr: SpIndex, IptrStorage, IptrStorage2> std::cmp::PartialEq<IptrStorage2>
427 for IndPtrBase<Iptr, IptrStorage>
428where
429 IptrStorage: Deref<Target = [Iptr]>,
430 IptrStorage2: Deref<Target = [Iptr]>,
431{
432 fn eq(&self, other: &IptrStorage2) -> bool {
433 self.raw_storage() == &**other
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::{IndPtr, IndPtrView};
440
441 #[test]
442 fn constructors() {
443 let raw_valid = vec![0, 1, 2, 3];
444 assert!(IndPtr::new_checked(raw_valid).is_ok());
445 let raw_valid = vec![0, 1, 2, 3];
446 assert!(IndPtrView::new_checked(&raw_valid).is_ok());
447 let raw_valid = vec![0];
449 assert!(IndPtrView::new_checked(&raw_valid).is_ok());
450 let raw_valid = vec![1];
452 assert!(IndPtrView::new_checked(&raw_valid).is_ok());
453
454 let raw_invalid = &[0, 2, 1];
455 assert_eq!(
456 IndPtrView::new_checked(raw_invalid)
457 .map_err(|(_, e)| e.kind())
458 .unwrap_err(),
459 crate::errors::StructureErrorKind::Unsorted
460 );
461 let raw_invalid: &[usize] = &[];
462 assert!(IndPtrView::new_checked(raw_invalid).is_err());
463 }
464
465 #[test]
466 fn empty() {
467 assert!(IndPtrView::new_checked(&[0]).unwrap().is_empty());
468 assert!(!IndPtrView::new_checked(&[0, 1]).unwrap().is_empty());
469 #[cfg(debug_assertions)]
470 {
471 assert!(IndPtrView::new_trusted(&[0]).is_empty());
472 }
473 #[cfg(not(debug_assertions))]
474 {
475 assert!(IndPtrView::new_trusted(&[0]).is_empty());
476 }
477 }
478
479 #[test]
480 fn outer_dims() {
481 assert_eq!(IndPtrView::new_checked(&[0]).unwrap().outer_dims(), 0);
482 assert_eq!(IndPtrView::new_checked(&[0, 1]).unwrap().outer_dims(), 1);
483 assert_eq!(
484 IndPtrView::new_checked(&[2, 3, 5, 7]).unwrap().outer_dims(),
485 3
486 );
487 }
488
489 #[test]
490 fn is_proper() {
491 assert!(IndPtrView::new_checked(&[0, 1]).unwrap().is_proper());
492 assert!(!IndPtrView::new_checked(&[1, 2]).unwrap().is_proper());
493 }
494
495 #[test]
496 fn offset() {
497 assert_eq!(IndPtrView::new_checked(&[0, 1]).unwrap().offset(), 0);
498 assert_eq!(IndPtrView::new_checked(&[1, 2]).unwrap().offset(), 1);
499 }
500
501 #[test]
502 fn nnz() {
503 assert_eq!(IndPtrView::new_checked(&[0, 1]).unwrap().nnz(), 1);
504 assert_eq!(IndPtrView::new_checked(&[1, 2]).unwrap().nnz(), 1);
505 }
506
507 #[test]
508 fn outer_inds() {
509 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
510 assert_eq!(iptr.outer_inds(0), 0..1);
511 assert_eq!(iptr.outer_inds(1), 1..3);
512 assert_eq!(iptr.outer_inds(2), 3..8);
513 let res = std::panic::catch_unwind(|| iptr.outer_inds(3));
514 assert!(res.is_err());
515 }
516
517 #[test]
518 fn nnz_in_outer() {
519 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
520 assert_eq!(iptr.nnz_in_outer(0), 1);
521 assert_eq!(iptr.nnz_in_outer(1), 2);
522 assert_eq!(iptr.nnz_in_outer(2), 5);
523 }
524
525 #[test]
526 fn outer_inds_slice() {
527 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
528 assert_eq!(iptr.outer_inds_slice(0, 1), 0..1);
529 assert_eq!(iptr.outer_inds_slice(0, 2), 0..3);
530 assert_eq!(iptr.outer_inds_slice(1, 3), 1..8);
531 let res = std::panic::catch_unwind(|| iptr.outer_inds_slice(3, 4));
532 assert!(res.is_err());
533 }
534
535 #[test]
536 fn iter_outer() {
537 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
538 let mut iter = iptr.iter_outer();
539 assert_eq!(iter.next().unwrap(), 0..1);
540 assert_eq!(iter.next().unwrap(), 1..3);
541 assert_eq!(iter.next().unwrap(), 3..8);
542 assert!(iter.next().is_none());
543 }
544
545 #[test]
546 fn iter_outer_nnz_inds() {
547 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
548 let mut iter = iptr.iter_outer_nnz_inds();
549 assert_eq!(iter.next().unwrap(), 0);
550 assert_eq!(iter.next().unwrap(), 1);
551 assert_eq!(iter.next().unwrap(), 1);
552 assert_eq!(iter.next().unwrap(), 2);
553 assert_eq!(iter.next().unwrap(), 2);
554 assert_eq!(iter.next().unwrap(), 2);
555 assert_eq!(iter.next().unwrap(), 2);
556 assert_eq!(iter.next().unwrap(), 2);
557 assert!(iter.next().is_none());
558 }
559
560 #[test]
561 fn compare_with_slices() {
562 let iptr = IndPtrView::new_checked(&[0, 1, 3, 8]).unwrap();
563 assert!(iptr == &[0, 1, 3, 8][..]);
564 assert!(iptr == vec![0, 1, 3, 8]);
565 let iptr = IndPtrView::new_checked(&[1, 1, 3, 8]).unwrap();
566 assert!(iptr == &[1, 1, 3, 8][..]);
567 }
568}