/* ==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- 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()); }