1use crate::ule::AsULE;
6use crate::ZeroVec;
7use alloc::borrow::Borrow;
8use core::cmp::Ordering;
9use core::convert::TryFrom;
10use core::fmt;
11use core::iter::FromIterator;
12use core::ops::Range;
13
14use super::*;
15use crate::map::ZeroMapKV;
16use crate::map::{MutableZeroVecLike, ZeroVecLike};
17
18pub struct ZeroMap2d<'a, K0, K1, V>
78where
79 K0: ZeroMapKV<'a>,
80 K1: ZeroMapKV<'a>,
81 V: ZeroMapKV<'a>,
82 K0: ?Sized,
83 K1: ?Sized,
84 V: ?Sized,
85{
86 pub(crate) keys0: K0::Container,
87 pub(crate) joiner: ZeroVec<'a, u32>,
88 pub(crate) keys1: K1::Container,
89 pub(crate) values: V::Container,
90}
91
92impl<'a, K0, K1, V> Default for ZeroMap2d<'a, K0, K1, V>
93where
94 K0: ZeroMapKV<'a>,
95 K1: ZeroMapKV<'a>,
96 V: ZeroMapKV<'a>,
97 K0: ?Sized,
98 K1: ?Sized,
99 V: ?Sized,
100{
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106impl<'a, K0, K1, V> ZeroMap2d<'a, K0, K1, V>
107where
108 K0: ZeroMapKV<'a>,
109 K1: ZeroMapKV<'a>,
110 V: ZeroMapKV<'a>,
111 K0: ?Sized,
112 K1: ?Sized,
113 V: ?Sized,
114{
115 pub fn new() -> Self {
126 Self {
127 keys0: K0::Container::zvl_with_capacity(0),
128 joiner: ZeroVec::new(),
129 keys1: K1::Container::zvl_with_capacity(0),
130 values: V::Container::zvl_with_capacity(0),
131 }
132 }
133
134 #[doc(hidden)] pub const unsafe fn from_parts_unchecked(
136 keys0: K0::Container,
137 joiner: ZeroVec<'a, u32>,
138 keys1: K1::Container,
139 values: V::Container,
140 ) -> Self {
141 Self {
142 keys0,
143 joiner,
144 keys1,
145 values,
146 }
147 }
148
149 pub fn with_capacity(capacity: usize) -> Self {
151 Self {
152 keys0: K0::Container::zvl_with_capacity(capacity),
153 joiner: ZeroVec::with_capacity(capacity),
154 keys1: K1::Container::zvl_with_capacity(capacity),
155 values: V::Container::zvl_with_capacity(capacity),
156 }
157 }
158
159 pub fn as_borrowed(&'a self) -> ZeroMap2dBorrowed<'a, K0, K1, V> {
161 ZeroMap2dBorrowed {
162 keys0: self.keys0.zvl_as_borrowed(),
163 joiner: &self.joiner,
164 keys1: self.keys1.zvl_as_borrowed(),
165 values: self.values.zvl_as_borrowed(),
166 }
167 }
168
169 pub fn len(&self) -> usize {
171 self.values.zvl_len()
172 }
173
174 pub fn is_empty(&self) -> bool {
176 self.values.zvl_len() == 0
177 }
178
179 pub fn clear(&mut self) {
181 self.keys0.zvl_clear();
182 self.joiner.clear();
183 self.keys1.zvl_clear();
184 self.values.zvl_clear();
185 }
186
187 pub fn reserve(&mut self, additional: usize) {
192 self.keys0.zvl_reserve(additional);
193 self.joiner.zvl_reserve(additional);
194 self.keys1.zvl_reserve(additional);
195 self.values.zvl_reserve(additional);
196 }
197
198 pub fn iter0<'l>(&'l self) -> impl Iterator<Item = ZeroMap2dCursor<'l, 'a, K0, K1, V>> + 'l {
227 (0..self.keys0.zvl_len()).map(move |idx| ZeroMap2dCursor::from_cow(self, idx))
228 }
229
230 fn get_range_for_key0_index(&self, key0_index: usize) -> Range<usize> {
234 ZeroMap2dCursor::from_cow(self, key0_index).get_range()
235 }
236
237 fn remove_key0_index(&mut self, key0_index: usize) {
239 self.keys0.zvl_remove(key0_index);
240 self.joiner.with_mut(|v| v.remove(key0_index));
241 }
242
243 fn joiner_expand(&mut self, key0_index: usize) {
245 #[allow(clippy::expect_used)] self.joiner
247 .to_mut_slice()
248 .iter_mut()
249 .skip(key0_index)
250 .for_each(|ref mut v| {
251 **v = v
253 .as_unsigned_int()
254 .checked_add(1)
255 .expect("Attempted to add more than 2^32 elements to a ZeroMap2d")
256 .to_unaligned()
257 })
258 }
259
260 fn joiner_shrink(&mut self, key0_index: usize) {
262 self.joiner
263 .to_mut_slice()
264 .iter_mut()
265 .skip(key0_index)
266 .for_each(|ref mut v| **v = (v.as_unsigned_int() - 1).to_unaligned())
267 }
268}
269
270impl<'a, K0, K1, V> ZeroMap2d<'a, K0, K1, V>
271where
272 K0: ZeroMapKV<'a> + Ord,
273 K1: ZeroMapKV<'a> + Ord,
274 V: ZeroMapKV<'a>,
275 K0: ?Sized,
276 K1: ?Sized,
277 V: ?Sized,
278{
279 pub fn get_2d(&self, key0: &K0, key1: &K1) -> Option<&V::GetType> {
297 self.get0(key0)?.get1(key1)
298 }
299
300 pub fn insert(&mut self, key0: &K0, key1: &K1, value: &V) -> Option<V::OwnedType> {
313 let (key0_index, range) = self.get_or_insert_range_for_key0(key0);
314 debug_assert!(range.start <= range.end); debug_assert!(range.end <= self.keys1.zvl_len());
316 let range_start = range.start;
317 #[allow(clippy::unwrap_used)] let index = range_start
319 + match self.keys1.zvl_binary_search_in_range(key1, range).unwrap() {
320 Ok(index) => return Some(self.values.zvl_replace(range_start + index, value)),
321 Err(index) => index,
322 };
323 self.keys1.zvl_insert(index, key1);
324 self.values.zvl_insert(index, value);
325 self.joiner_expand(key0_index);
326 #[cfg(debug_assertions)]
327 self.check_invariants();
328 None
329 }
330
331 pub fn remove(&mut self, key0: &K0, key1: &K1) -> Option<V::OwnedType> {
347 let key0_index = self.keys0.zvl_binary_search(key0).ok()?;
348 let range = self.get_range_for_key0_index(key0_index);
349 debug_assert!(range.start < range.end); debug_assert!(range.end <= self.keys1.zvl_len());
351 let is_singleton_range = range.start + 1 == range.end;
352 #[allow(clippy::unwrap_used)] let index = range.start
354 + self
355 .keys1
356 .zvl_binary_search_in_range(key1, range)
357 .unwrap()
358 .ok()?;
359 self.keys1.zvl_remove(index);
360 let removed = self.values.zvl_remove(index);
361 self.joiner_shrink(key0_index);
362 if is_singleton_range {
363 self.remove_key0_index(key0_index);
364 }
365 #[cfg(debug_assertions)]
366 self.check_invariants();
367 Some(removed)
368 }
369
370 #[must_use]
396 pub fn try_append<'b>(
397 &mut self,
398 key0: &'b K0,
399 key1: &'b K1,
400 value: &'b V,
401 ) -> Option<(&'b K0, &'b K1, &'b V)> {
402 if self.is_empty() {
403 self.keys0.zvl_push(key0);
404 self.joiner.with_mut(|v| v.push(1u32.to_unaligned()));
405 self.keys1.zvl_push(key1);
406 self.values.zvl_push(value);
407 return None;
408 }
409
410 #[allow(clippy::unwrap_used)]
412 let last_key0 = self.keys0.zvl_get(self.keys0.zvl_len() - 1).unwrap();
413 let key0_cmp = K0::Container::t_cmp_get(key0, last_key0);
414 #[allow(clippy::unwrap_used)]
415 let last_key1 = self.keys1.zvl_get(self.keys1.zvl_len() - 1).unwrap();
416 let key1_cmp = K1::Container::t_cmp_get(key1, last_key1);
417
418 match key0_cmp {
420 Ordering::Less => {
421 return Some((key0, key1, value));
423 }
424 Ordering::Equal => {
425 match key1_cmp {
426 Ordering::Less | Ordering::Equal => {
427 return Some((key0, key1, value));
429 }
430 _ => {}
431 }
432 }
433 _ => {}
434 }
435
436 #[allow(clippy::expect_used)] let joiner_value = u32::try_from(self.keys1.zvl_len() + 1)
438 .expect("Attempted to add more than 2^32 elements to a ZeroMap2d");
439
440 #[allow(clippy::unwrap_used)]
442 if key0_cmp == Ordering::Greater {
443 self.keys0.zvl_push(key0);
444 self.joiner
445 .with_mut(|v| v.push(joiner_value.to_unaligned()));
446 } else {
447 *self.joiner.to_mut_slice().last_mut().unwrap() = joiner_value.to_unaligned();
449 }
450 self.keys1.zvl_push(key1);
451 self.values.zvl_push(value);
452
453 #[cfg(debug_assertions)]
454 self.check_invariants();
455
456 None
457 }
458
459 #[cfg(debug_assertions)]
462 #[allow(clippy::unwrap_used)] pub(crate) fn check_invariants(&self) {
464 debug_assert_eq!(self.keys0.zvl_len(), self.joiner.len());
465 debug_assert_eq!(self.keys1.zvl_len(), self.values.zvl_len());
466 debug_assert!(self.keys0.zvl_is_ascending());
467 debug_assert!(self.joiner.zvl_is_ascending());
468 if let Some(last_joiner) = self.joiner.last() {
469 debug_assert_eq!(last_joiner as usize, self.keys1.zvl_len());
470 }
471 for i in 0..self.joiner.len() {
472 let j0 = if i == 0 {
473 0
474 } else {
475 self.joiner.get(i - 1).unwrap() as usize
476 };
477 let j1 = self.joiner.get(i).unwrap() as usize;
478 debug_assert_ne!(j0, j1);
479 for j in (j0 + 1)..j1 {
480 let m0 = self.keys1.zvl_get(j - 1).unwrap();
481 let m1 = self.keys1.zvl_get(j).unwrap();
482 debug_assert_eq!(Ordering::Less, K1::Container::get_cmp_get(m0, m1));
483 }
484 }
485 }
486}
487
488impl<'a, K0, K1, V> ZeroMap2d<'a, K0, K1, V>
489where
490 K0: ZeroMapKV<'a> + Ord,
491 K1: ZeroMapKV<'a>,
492 V: ZeroMapKV<'a>,
493 K0: ?Sized,
494 K1: ?Sized,
495 V: ?Sized,
496{
497 #[inline]
514 pub fn get0<'l>(&'l self, key0: &K0) -> Option<ZeroMap2dCursor<'l, 'a, K0, K1, V>> {
515 let key0_index = self.keys0.zvl_binary_search(key0).ok()?;
516 Some(ZeroMap2dCursor::from_cow(self, key0_index))
517 }
518
519 pub fn get0_by<'l>(
531 &'l self,
532 predicate: impl FnMut(&K0) -> Ordering,
533 ) -> Option<ZeroMap2dCursor<'l, 'a, K0, K1, V>> {
534 let key0_index = self.keys0.zvl_binary_search_by(predicate).ok()?;
535 Some(ZeroMap2dCursor::from_cow(self, key0_index))
536 }
537
538 pub fn contains_key0(&self, key0: &K0) -> bool {
550 self.keys0.zvl_binary_search(key0).is_ok()
551 }
552
553 fn get_or_insert_range_for_key0(&mut self, key0: &K0) -> (usize, Range<usize>) {
557 match self.keys0.zvl_binary_search(key0) {
558 Ok(key0_index) => (key0_index, self.get_range_for_key0_index(key0_index)),
559 Err(key0_index) => {
560 let joiner_value = if key0_index == 0 {
562 0
563 } else {
564 debug_assert!(key0_index <= self.joiner.len());
565 #[allow(clippy::unwrap_used)]
567 self.joiner.get(key0_index - 1).unwrap()
568 };
569 self.keys0.zvl_insert(key0_index, key0);
570 self.joiner
571 .with_mut(|v| v.insert(key0_index, joiner_value.to_unaligned()));
572 (key0_index, (joiner_value as usize)..(joiner_value as usize))
573 }
574 }
575 }
576}
577
578impl<'a, K0, K1, V> ZeroMap2d<'a, K0, K1, V>
579where
580 K0: ZeroMapKV<'a> + Ord,
581 K1: ZeroMapKV<'a> + Ord,
582 V: ZeroMapKV<'a>,
583 V: Copy,
584 K0: ?Sized,
585 K1: ?Sized,
586{
587 #[inline]
601 pub fn get_copied_2d(&self, key0: &K0, key1: &K1) -> Option<V> {
602 self.get0(key0)?.get1_copied(key1)
603 }
604}
605
606impl<'a, K0, K1, V> From<ZeroMap2dBorrowed<'a, K0, K1, V>> for ZeroMap2d<'a, K0, K1, V>
607where
608 K0: ZeroMapKV<'a>,
609 K1: ZeroMapKV<'a>,
610 V: ZeroMapKV<'a>,
611 K0: ?Sized,
612 K1: ?Sized,
613 V: ?Sized,
614{
615 fn from(other: ZeroMap2dBorrowed<'a, K0, K1, V>) -> Self {
616 Self {
617 keys0: K0::Container::zvl_from_borrowed(other.keys0),
618 joiner: other.joiner.as_zerovec(),
619 keys1: K1::Container::zvl_from_borrowed(other.keys1),
620 values: V::Container::zvl_from_borrowed(other.values),
621 }
622 }
623}
624
625impl<'a, 'b, K0, K1, V> PartialEq<ZeroMap2d<'b, K0, K1, V>> for ZeroMap2d<'a, K0, K1, V>
629where
630 K0: for<'c> ZeroMapKV<'c> + ?Sized,
631 K1: for<'c> ZeroMapKV<'c> + ?Sized,
632 V: for<'c> ZeroMapKV<'c> + ?Sized,
633 <K0 as ZeroMapKV<'a>>::Container: PartialEq<<K0 as ZeroMapKV<'b>>::Container>,
634 <K1 as ZeroMapKV<'a>>::Container: PartialEq<<K1 as ZeroMapKV<'b>>::Container>,
635 <V as ZeroMapKV<'a>>::Container: PartialEq<<V as ZeroMapKV<'b>>::Container>,
636{
637 fn eq(&self, other: &ZeroMap2d<'b, K0, K1, V>) -> bool {
638 self.keys0.eq(&other.keys0)
639 && self.joiner.eq(&other.joiner)
640 && self.keys1.eq(&other.keys1)
641 && self.values.eq(&other.values)
642 }
643}
644
645impl<'a, K0, K1, V> fmt::Debug for ZeroMap2d<'a, K0, K1, V>
646where
647 K0: ZeroMapKV<'a> + ?Sized,
648 K1: ZeroMapKV<'a> + ?Sized,
649 V: ZeroMapKV<'a> + ?Sized,
650 <K0 as ZeroMapKV<'a>>::Container: fmt::Debug,
651 <K1 as ZeroMapKV<'a>>::Container: fmt::Debug,
652 <V as ZeroMapKV<'a>>::Container: fmt::Debug,
653{
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
655 f.debug_struct("ZeroMap2d")
656 .field("keys0", &self.keys0)
657 .field("joiner", &self.joiner)
658 .field("keys1", &self.keys1)
659 .field("values", &self.values)
660 .finish()
661 }
662}
663
664impl<'a, K0, K1, V> Clone for ZeroMap2d<'a, K0, K1, V>
665where
666 K0: ZeroMapKV<'a> + ?Sized,
667 K1: ZeroMapKV<'a> + ?Sized,
668 V: ZeroMapKV<'a> + ?Sized,
669 <K0 as ZeroMapKV<'a>>::Container: Clone,
670 <K1 as ZeroMapKV<'a>>::Container: Clone,
671 <V as ZeroMapKV<'a>>::Container: Clone,
672{
673 fn clone(&self) -> Self {
674 Self {
675 keys0: self.keys0.clone(),
676 joiner: self.joiner.clone(),
677 keys1: self.keys1.clone(),
678 values: self.values.clone(),
679 }
680 }
681}
682
683impl<'a, A, B, C, K0, K1, V> FromIterator<(A, B, C)> for ZeroMap2d<'a, K0, K1, V>
684where
685 A: Borrow<K0>,
686 B: Borrow<K1>,
687 C: Borrow<V>,
688 K0: ZeroMapKV<'a> + ?Sized + Ord,
689 K1: ZeroMapKV<'a> + ?Sized + Ord,
690 V: ZeroMapKV<'a> + ?Sized,
691{
692 fn from_iter<T>(iter: T) -> Self
693 where
694 T: IntoIterator<Item = (A, B, C)>,
695 {
696 let iter = iter.into_iter();
697 let mut map = match iter.size_hint() {
698 (_, Some(upper)) => Self::with_capacity(upper),
699 (lower, None) => Self::with_capacity(lower),
700 };
701
702 for (key0, key1, value) in iter {
703 if let Some((key0, key1, value)) =
704 map.try_append(key0.borrow(), key1.borrow(), value.borrow())
705 {
706 map.insert(key0, key1, value);
707 }
708 }
709 #[cfg(debug_assertions)]
710 map.check_invariants();
711 map
712 }
713}
714
715#[cfg(test)]
716mod test {
717 use super::*;
718 use alloc::collections::BTreeMap;
719
720 #[test]
721 fn stress_test() {
722 let mut zm2d = ZeroMap2d::<u16, str, str>::new();
723
724 assert_eq!(
725 format!("{zm2d:?}"),
726 "ZeroMap2d { keys0: ZeroVec([]), joiner: ZeroVec([]), keys1: [], values: [] }"
727 );
728 assert_eq!(zm2d.get0(&0), None);
729
730 let result = zm2d.try_append(&3, "ccc", "CCC");
731 assert!(result.is_none());
732
733 assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3]), joiner: ZeroVec([1]), keys1: [\"ccc\"], values: [\"CCC\"] }");
734 assert_eq!(zm2d.get0(&0), None);
735 assert_eq!(zm2d.get0(&3).unwrap().get1(""), None);
736 assert_eq!(zm2d.get_2d(&3, "ccc"), Some("CCC"));
737 assert_eq!(zm2d.get0(&99), None);
738
739 let result = zm2d.try_append(&3, "eee", "EEE");
740 assert!(result.is_none());
741
742 assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3]), joiner: ZeroVec([2]), keys1: [\"ccc\", \"eee\"], values: [\"CCC\", \"EEE\"] }");
743 assert_eq!(zm2d.get0(&0), None);
744 assert_eq!(zm2d.get0(&3).unwrap().get1(""), None);
745 assert_eq!(zm2d.get_2d(&3, "ccc"), Some("CCC"));
746 assert_eq!(zm2d.get_2d(&3, "eee"), Some("EEE"));
747 assert_eq!(zm2d.get0(&3).unwrap().get1("five"), None);
748 assert_eq!(zm2d.get0(&99), None);
749
750 let result = zm2d.try_append(&3, "ddd", "DD0");
752 assert!(result.is_some());
753
754 let result = zm2d.try_append(&5, "ddd", "DD1");
756 assert!(result.is_none());
757 let result = zm2d.try_append(&7, "ddd", "DD2");
758 assert!(result.is_none());
759 let result = zm2d.try_append(&7, "eee", "EEE");
760 assert!(result.is_none());
761 let result = zm2d.try_append(&7, "www", "WWW");
762 assert!(result.is_none());
763 let result = zm2d.try_append(&9, "yyy", "YYY");
764 assert!(result.is_none());
765
766 assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3, 5, 7, 9]), joiner: ZeroVec([2, 3, 6, 7]), keys1: [\"ccc\", \"eee\", \"ddd\", \"ddd\", \"eee\", \"www\", \"yyy\"], values: [\"CCC\", \"EEE\", \"DD1\", \"DD2\", \"EEE\", \"WWW\", \"YYY\"] }");
767 assert_eq!(zm2d.get0(&0), None);
768 assert_eq!(zm2d.get0(&3).unwrap().get1(""), None);
769 assert_eq!(zm2d.get_2d(&3, "ccc"), Some("CCC"));
770 assert_eq!(zm2d.get_2d(&3, "eee"), Some("EEE"));
771 assert_eq!(zm2d.get0(&3).unwrap().get1("zzz"), None);
772 assert_eq!(zm2d.get0(&4), None);
773 assert_eq!(zm2d.get0(&5).unwrap().get1("aaa"), None);
774 assert_eq!(zm2d.get_2d(&5, "ddd"), Some("DD1"));
775 assert_eq!(zm2d.get0(&5).unwrap().get1("zzz"), None);
776 assert_eq!(zm2d.get0(&6), None);
777 assert_eq!(zm2d.get0(&7).unwrap().get1("aaa"), None);
778 assert_eq!(zm2d.get_2d(&7, "ddd"), Some("DD2"));
779 assert_eq!(zm2d.get_2d(&7, "eee"), Some("EEE"));
780 assert_eq!(zm2d.get_2d(&7, "www"), Some("WWW"));
781 assert_eq!(zm2d.get0(&7).unwrap().get1("yyy"), None);
782 assert_eq!(zm2d.get0(&7).unwrap().get1("zzz"), None);
783 assert_eq!(zm2d.get0(&8), None);
784 assert_eq!(zm2d.get0(&9).unwrap().get1("aaa"), None);
785 assert_eq!(zm2d.get0(&9).unwrap().get1("www"), None);
786 assert_eq!(zm2d.get_2d(&9, "yyy"), Some("YYY"));
787 assert_eq!(zm2d.get0(&9).unwrap().get1("zzz"), None);
788 assert_eq!(zm2d.get0(&10), None);
789 assert_eq!(zm2d.get0(&99), None);
790
791 zm2d.insert(&3, "mmm", "MM0");
793 zm2d.insert(&6, "ddd", "DD3");
794 zm2d.insert(&6, "mmm", "MM1");
795 zm2d.insert(&6, "nnn", "NNN");
796
797 assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3, 5, 6, 7, 9]), joiner: ZeroVec([3, 4, 7, 10, 11]), keys1: [\"ccc\", \"eee\", \"mmm\", \"ddd\", \"ddd\", \"mmm\", \"nnn\", \"ddd\", \"eee\", \"www\", \"yyy\"], values: [\"CCC\", \"EEE\", \"MM0\", \"DD1\", \"DD3\", \"MM1\", \"NNN\", \"DD2\", \"EEE\", \"WWW\", \"YYY\"] }");
798 assert_eq!(zm2d.get0(&0), None);
799 assert_eq!(zm2d.get0(&3).unwrap().get1(""), None);
800 assert_eq!(zm2d.get_2d(&3, "ccc"), Some("CCC"));
801 assert_eq!(zm2d.get_2d(&3, "eee"), Some("EEE"));
802 assert_eq!(zm2d.get_2d(&3, "mmm"), Some("MM0"));
803 assert_eq!(zm2d.get0(&3).unwrap().get1("zzz"), None);
804 assert_eq!(zm2d.get0(&4), None);
805 assert_eq!(zm2d.get0(&5).unwrap().get1("aaa"), None);
806 assert_eq!(zm2d.get_2d(&5, "ddd"), Some("DD1"));
807 assert_eq!(zm2d.get0(&5).unwrap().get1("zzz"), None);
808 assert_eq!(zm2d.get0(&6).unwrap().get1("aaa"), None);
809 assert_eq!(zm2d.get_2d(&6, "ddd"), Some("DD3"));
810 assert_eq!(zm2d.get_2d(&6, "mmm"), Some("MM1"));
811 assert_eq!(zm2d.get_2d(&6, "nnn"), Some("NNN"));
812 assert_eq!(zm2d.get0(&6).unwrap().get1("zzz"), None);
813 assert_eq!(zm2d.get0(&7).unwrap().get1("aaa"), None);
814 assert_eq!(zm2d.get_2d(&7, "ddd"), Some("DD2"));
815 assert_eq!(zm2d.get_2d(&7, "eee"), Some("EEE"));
816 assert_eq!(zm2d.get_2d(&7, "www"), Some("WWW"));
817 assert_eq!(zm2d.get0(&7).unwrap().get1("yyy"), None);
818 assert_eq!(zm2d.get0(&7).unwrap().get1("zzz"), None);
819 assert_eq!(zm2d.get0(&8), None);
820 assert_eq!(zm2d.get0(&9).unwrap().get1("aaa"), None);
821 assert_eq!(zm2d.get0(&9).unwrap().get1("www"), None);
822 assert_eq!(zm2d.get_2d(&9, "yyy"), Some("YYY"));
823 assert_eq!(zm2d.get0(&9).unwrap().get1("zzz"), None);
824 assert_eq!(zm2d.get0(&10), None);
825 assert_eq!(zm2d.get0(&99), None);
826
827 let result = zm2d.remove(&3, "ccc"); assert_eq!(result.as_deref(), Some("CCC"));
830 let result = zm2d.remove(&3, "mmm"); assert_eq!(result.as_deref(), Some("MM0"));
832 let result = zm2d.remove(&5, "ddd"); assert_eq!(result.as_deref(), Some("DD1"));
834 let result = zm2d.remove(&9, "yyy"); assert_eq!(result.as_deref(), Some("YYY"));
836
837 assert_eq!(format!("{zm2d:?}"), "ZeroMap2d { keys0: ZeroVec([3, 6, 7]), joiner: ZeroVec([1, 4, 7]), keys1: [\"eee\", \"ddd\", \"mmm\", \"nnn\", \"ddd\", \"eee\", \"www\"], values: [\"EEE\", \"DD3\", \"MM1\", \"NNN\", \"DD2\", \"EEE\", \"WWW\"] }");
838 }
839
840 #[test]
841 fn zeromap2d_metazone() {
842 let source_data = [
843 (*b"aedxb", 0, Some(*b"gulf")),
844 (*b"afkbl", 0, Some(*b"afgh")),
845 (*b"ushnl", 0, None),
846 (*b"ushnl", 7272660, Some(*b"haal")),
847 (*b"ushnl", 0, None),
848 (*b"ushnl", 7272660, Some(*b"haal")),
849 ];
850
851 let btreemap: BTreeMap<([u8; 5], i32), Option<[u8; 4]>> = source_data
852 .iter()
853 .copied()
854 .map(|(a, b, c)| ((a, b), c))
855 .collect();
856
857 let zeromap2d: ZeroMap2d<[u8; 5], i32, Option<[u8; 4]>> =
858 source_data.iter().copied().collect();
859
860 let mut btreemap_iter = btreemap.iter();
861
862 for cursor in zeromap2d.iter0() {
863 for (key1, value) in cursor.iter1() {
864 let expected = btreemap_iter.next().unwrap();
866 assert_eq!(
867 (expected.0 .0, expected.0 .1, expected.1),
868 (*cursor.key0(), key1.as_unsigned_int() as i32, &value.get())
869 );
870 }
871 }
872 assert!(btreemap_iter.next().is_none());
873 }
874}