/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--
Perm
Copyright (C) 2021-2023 Anonymous
There are several releases over multiple years,
they are listed as ranges, such as: "2021-2023".
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/
use {
core::ops::RangeInclusive,
std::collections::HashSet,
perm::{Buffer, PermIter, Result},
};
#[test]
fn perm_iters() -> Result<()> {
let buffer = Buffer::with_capacity(9);
format!("{:?}", PermIter::new(vec![0_u8..=1, 0..=2, 0..=0], &buffer));
assert_eq!(
PermIter::new(vec![0_u8..=1, 0..=2, 0..=0], &buffer).map(|i| i.to_vec()).collect::>(),
[
&[0, 0, 0], &[1, 0, 0],
&[0, 1, 0], &[1, 1, 0],
&[0, 2, 0], &[1, 2, 0],
].iter().map(|i| i.to_vec()).collect(),
);
assert_eq!(
PermIter::new(vec![0_u8..=0, 0..=2, 0..=0], &buffer).map(|i| i.to_vec()).collect::>(),
[
&[0, 0, 0],
&[0, 1, 0],
&[0, 2, 0],
].iter().map(|i| i.to_vec()).collect(),
);
assert_eq!(
PermIter::new(vec![0_u8..=0, 0..=0, 0..=0, 0..=0], &buffer).map(|i| i.to_vec()).collect::>(),
[&[0, 0, 0, 0]].iter().map(|i| i.to_vec()).collect(),
);
assert_eq!(
PermIter::new(vec![0_u8..=9, 0..=9], &buffer).last().unwrap().as_slice(),
&[9, 9],
);
Ok(())
}
/// # 4-3-3
///
/// [0] [0, 0, 0]
/// [1] [1, 0, 0]
/// [2] [2, 0, 0]
/// [3] [3, 0, 0]
/// [4] [0, 1, 0]
/// [5] [1, 1, 0]
/// [6] [2, 1, 0]
/// [7] [3, 1, 0]
/// [8] [0, 2, 0]
/// [9] [1, 2, 0]
/// [10] [2, 2, 0]
/// [11] [3, 2, 0]
/// [12] [0, 0, 1]
/// [13] [1, 0, 1]
/// [14] [2, 0, 1]
/// [15] [3, 0, 1]
/// [16] [0, 1, 1]
/// [17] [1, 1, 1]
/// [18] [2, 1, 1]
/// [19] [3, 1, 1]
/// [20] [0, 2, 1]
/// [21] [1, 2, 1]
/// [22] [2, 2, 1]
/// [23] [3, 2, 1]
/// [24] [0, 0, 2]
/// [25] [1, 0, 2]
/// [26] [2, 0, 2]
/// [27] [3, 0, 2]
/// [28] [0, 1, 2]
/// [29] [1, 1, 2]
/// [30] [2, 1, 2]
/// [31] [3, 1, 2]
/// [32] [0, 2, 2]
/// [33] [1, 2, 2]
/// [34] [2, 2, 2]
/// [35] [3, 2, 2]
#[test]
fn perm_iters_implementation_of_iterator_nth() {
const DATA: &[RangeInclusive] = &[0..=3, 0..=2, 0..=2];
let buffer = Buffer::with_capacity(DATA.len());
for (n, expected) in &[
(0, Some(&[0, 0, 0][..])),
(3, Some(&[3, 0, 0])),
(7, Some(&[3, 1, 0])),
(11, Some(&[3, 2, 0])),
(28, Some(&[0, 1, 2])),
(34, Some(&[2, 2, 2])),
(35, Some(&[3, 2, 2])),
(36, None),
(37, None),
(39, None),
(40, None),
(99, None),
] {
match PermIter::new(DATA.to_vec(), &buffer).nth(*n) {
Some(item) => assert_eq!(item.as_slice(), expected.unwrap()),
None => assert!(expected.is_none()),
};
}
for (skip, n, expected) in &[
(0, 0, Some(&[0, 0, 0][..])),
(1, 0, Some(&[1, 0, 0])),
(1, 1, Some(&[2, 0, 0])),
(2, 0, Some(&[2, 0, 0])),
(3, 0, Some(&[3, 0, 0])),
(4, 0, Some(&[0, 1, 0])),
(7, 0, Some(&[3, 1, 0])),
(7, 1, Some(&[0, 2, 0])),
(9, 0, Some(&[1, 2, 0])),
(9, 1, Some(&[2, 2, 0])),
(9, 9, Some(&[2, 1, 1])),
(23, 5, Some(&[0, 1, 2])),
(26, 6, Some(&[0, 2, 2])),
(26, 7, Some(&[1, 2, 2])),
(26, 8, Some(&[2, 2, 2])),
(26, 9, Some(&[3, 2, 2])),
(26, 10, None),
(9, 50, None),
] {
match PermIter::new(DATA.to_vec(), &buffer).skip(*skip).nth(*n) {
Some(item) => assert_eq!((skip, n, item.as_slice()), (skip, n, expected.unwrap())),
None => assert!(expected.is_none()),
};
}
}
#[test]
fn perm_iters_implementation_of_iterator_nth_with_simple_data() {
const DATA: &[RangeInclusive] = &[0..=3];
let buffer = Buffer::with_capacity(DATA.len());
for (n, expected) in &[
(0, Some(&[0][..])),
(1, Some(&[1])),
(2, Some(&[2])),
(3, Some(&[3])),
(4, None),
(5, None),
(6, None),
(7, None),
(99, None),
] {
match PermIter::new(DATA.to_vec(), &buffer).nth(*n) {
Some(item) => assert_eq!(item.as_slice(), expected.unwrap()),
None => assert!(expected.is_none()),
};
}
for (skip, n, expected) in &[
(0, 0, Some(&[0][..])),
(1, 0, Some(&[1])),
(1, 1, Some(&[2])),
(1, 2, Some(&[3])),
(2, 0, Some(&[2])),
(2, 1, Some(&[3])),
(3, 0, Some(&[3])),
(3, 1, None),
(4, 0, None),
(99, 0, None),
] {
match PermIter::new(DATA.to_vec(), &buffer).skip(*skip).nth(*n) {
Some(item) => assert_eq!(item.as_slice(), expected.unwrap()),
None => assert!(expected.is_none()),
};
}
}
#[test]
fn perm_iters_implementation_of_iterator_nth_with_small_data() {
// [0] [0, 0, 0]
// [1] [1, 0, 0]
// [2] [2, 0, 0]
// [3] [0, 1, 0]
// [4] [1, 1, 0]
// [5] [2, 1, 0]
// [6] [0, 2, 0]
// [7] [1, 2, 0]
// [8] [2, 2, 0]
// [9] [0, 0, 1]
// [10] [1, 0, 1]
// [11] [2, 0, 1]
// [12] [0, 1, 1]
// [13] [1, 1, 1]
// [14] [2, 1, 1]
// [15] [0, 2, 1]
// [16] [1, 2, 1]
// [17] [2, 2, 1]
// [18] [0, 0, 2]
// [19] [1, 0, 2]
// [20] [2, 0, 2]
// [21] [0, 1, 2]
// [22] [1, 1, 2]
// [23] [2, 1, 2]
// [24] [0, 2, 2]
// [25] [1, 2, 2]
// [26] [2, 2, 2]
const DATA: &[core::ops::Range] = &[0..3, 0..3, 0..3];
let buffer = Buffer::with_capacity(DATA.len());
for delta in 0..DATA.iter().map(|i| i.len()).product::().checked_sub(2).unwrap() {
let mut iter = PermIter::new(DATA.to_vec(), &buffer);
let skip = DATA.iter().map(|i| i.len()).product::().checked_sub(2).unwrap().checked_sub(delta).unwrap();
assert!(iter.nth(skip).is_some());
assert_eq!(
iter.nth(delta).unwrap().as_slice(),
DATA.to_vec().into_iter().map(|i| i.last().unwrap()).collect::>(),
);
assert!(iter.next().is_none());
}
}
#[test]
#[cfg(target_pointer_width = "64")]
fn perm_iters_implementation_of_iterator_nth_with_large_data() {
#[cfg(feature="std")]
use std::time::Instant;
const DATA: &[core::ops::Range] = &[0..64, 0..64, 0..64, 0..64, 0..64, 0..64];
let buffer = Buffer::with_capacity(DATA.len());
for delta in &[67, 133, 567, 1267, 5679] {
let mut iter = PermIter::new(DATA.to_vec(), &buffer);
let skip = DATA.iter().map(|i| i.len()).product::().checked_sub(2).unwrap().checked_sub(*delta).unwrap();
#[cfg(feature="std")]
let start = Instant::now();
assert!(iter.nth(skip).is_some());
#[cfg(feature="std")]
std::println!(
"`PermIter::nth({skip})` in: {duration:?}",
skip=skip.to_string().chars().rev().enumerate().fold(String::with_capacity(99), |mut result, (i, c)| {
if i > 0 && i % 3 == 0 {
result.push(',');
}
result.push(c);
result
}).chars().rev().collect::(),
duration=Instant::now().duration_since(start),
);
assert_eq!(
iter.nth(*delta).unwrap().as_slice(),
DATA.to_vec().into_iter().map(|i| i.last().unwrap()).collect::>(),
);
assert!(iter.next().is_none());
}
}
#[test]
fn perm_iters_clone_with() {
const DATA: &[RangeInclusive] = &[0..=9, 0..=3, 0..=6];
let count: usize = DATA.iter().map(|i| i.len()).product();
let counter = 10..count;
let sample: HashSet<_> = PermIter::new(DATA.to_vec(), &Buffer::with_capacity(DATA.len())).map(|i| i.to_vec()).collect();
let first = {
let mut buffer_list = Vec::with_capacity(99);
counter.clone().try_fold(0_usize, |total, next| {
match total.checked_add(next) {
Some(result) => if result < count {
buffer_list.push((next, Buffer::with_capacity(DATA.len())));
Some(result)
} else {
buffer_list.push((count - total, Buffer::with_capacity(DATA.len())));
None
},
None => None,
}
});
let mut iter_list = Vec::with_capacity(99);
iter_list.push(PermIter::new(DATA.to_vec(), &buffer_list.first().unwrap().1));
for (_, buffer) in buffer_list.iter().skip(1) {
iter_list.push(iter_list.last().unwrap().clone_with(buffer));
}
iter_list.into_iter().enumerate().fold(Vec::with_capacity(count), |mut result, (idx, iter)| {
for item in iter.skip(result.len()).take(buffer_list[idx].0) {
result.push(item.to_vec());
}
result
})
};
let second = {
let mut second = Vec::with_capacity(count);
let buffer = Buffer::with_capacity(DATA.len());
let mut iter = PermIter::new(DATA.to_vec(), &buffer);
for _ in 0..count / 3 {
second.push(iter.next().unwrap().to_vec());
}
assert!(second.is_empty() == false);
for item in iter.clone_with(&buffer) {
second.push(item.to_vec());
}
second
};
assert_eq!(sample.len(), first.len());
assert_eq!(sample.len(), second.len());
assert_eq!(sample, first.into_iter().collect());
assert_eq!(sample, second.into_iter().collect());
}