Skip to content

Commit

Permalink
permutations
Browse files Browse the repository at this point in the history
  • Loading branch information
2A5F committed Nov 18, 2024
1 parent 2f192f1 commit 3336f84
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,11 @@ Provides many useful tools related to tuples
let a = a.sorted();
assert_eq!(a, (0, 2, 5, 6, 6, 8))
```

- permutations

```rust
let a = (1, '2', "3");
let r = a.permutations_2();
assert_eq!(r, ((1, '2'), (1, "3"), ('2', 1), ('2', "3"), ("3", 1), ("3", '2')));
```
3 changes: 2 additions & 1 deletion code_gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ edition = "2021"
[dependencies]
syn = "2.0"
quote = "1.0"
proc-macro2 = "1.0"
proc-macro2 = "1.0"
itertools = "0.13"
88 changes: 88 additions & 0 deletions code_gen/src/code_gen.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use itertools::Itertools;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
use std::{fs, path::Path};
Expand Down Expand Up @@ -33,6 +34,7 @@ pub fn code_gen(out_dir: &Path) {
gen_capt(&ctx, &out_dir);
gen_tuple_get(&ctx, &out_dir);
gen_tuple_swap(&ctx, &out_dir);
gen_permutations(&ctx, &out_dir);
}

#[allow(dead_code)]
Expand Down Expand Up @@ -1482,3 +1484,89 @@ fn gen_tuple_swap_cart(ctx: &Ctx) -> TokenStream {
};
tks
}

fn gen_permutations(ctx: &Ctx, out_dir: &Path) {
let items = (2..4usize).into_iter().map(|i| gen_permutations_size(ctx, i));
let tks = quote! { #(#items)* };
let mut code = tks.to_string();
code.insert_str(0, "// This file is by code gen, do not modify\n\n");
let dest_path = Path::new(out_dir).join("permutations.rs");
fs::write(&dest_path, code).unwrap();
}

fn gen_permutations_size(ctx: &Ctx, size: usize) -> TokenStream {
let trait_name = format_ident!("TuplePermutations{}", size);
let fn_name = format_ident!("permutations_{}", size);

let impls = (size..33usize).into_iter().filter(|i| i.pow(size as u32) - i < 33).map(|i| gen_permutations_impl_n(ctx, size, i, &trait_name, &fn_name));

let doc = format!("Permutation by {size}");

let tks = quote! {
#[doc = #doc]
pub trait #trait_name {
type Output;

#[doc = #doc]
fn #fn_name(self) -> Self::Output;
}

#(#impls)*
};
tks
}

fn gen_permutations_impl_n(ctx: &Ctx, size: usize, n: usize, trait_name: &Ident, fn_name: &Ident) -> TokenStream {
let nts = &ctx.nts[0..n];
let size_lits = &ctx.size_lits[0..n];

let output_types = nts
.iter()
.permutations(size)
.map(|v| {
quote! {
(#(#v,)*)
}
})
.collect::<Vec<_>>();

let mut set = std::collections::HashSet::<usize>::new();
let output_impls = size_lits
.iter()
.enumerate()
.permutations(size)
.collect::<Vec<_>>()
.into_iter()
.rev()
.map(|v| {
let v = v.into_iter().map(|(i, l)| {
if set.contains(&i) {
quote! {
self.#l.clone()
}
} else {
set.insert(i);
quote! {
self.#l
}
}
});
quote! {
(#(#v,)*)
}
})
.collect::<Vec<_>>()
.into_iter()
.rev();

let tks = quote! {
impl<#(#nts:Clone),*> #trait_name for (#(#nts,)*) {
type Output = (#(#output_types,)*);

fn #fn_name(self) -> Self::Output {
(#(#output_impls,)*)
}
}
};
tks
}
2 changes: 2 additions & 0 deletions tuples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ default = [
"capt",
"tuple_get",
"sort",
"permutations"
]
flatten = []
re-exports = []
Expand All @@ -56,6 +57,7 @@ tuple_iter = []
tuple_map = []
tuple_meta = []
tuple_swap_n = []
permutations = []

[package.metadata.docs.rs]
all-features = true
50 changes: 50 additions & 0 deletions tuples/src/gen/permutations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// This file is by code gen, do not modify

#[doc = "Permutation by 2"]
pub trait TuplePermutations2 {
type Output;
#[doc = "Permutation by 2"]
fn permutations_2(self) -> Self::Output;
}
impl<T0: Clone, T1: Clone> TuplePermutations2 for (T0, T1) {
type Output = ((T0, T1), (T1, T0));
fn permutations_2(self) -> Self::Output {
((self.0.clone(), self.1.clone()), (self.1, self.0))
}
}
impl<T0: Clone, T1: Clone, T2: Clone> TuplePermutations2 for (T0, T1, T2) {
type Output = ((T0, T1), (T0, T2), (T1, T0), (T1, T2), (T2, T0), (T2, T1));
fn permutations_2(self) -> Self::Output {
((self.0.clone(), self.1.clone()), (self.0.clone(), self.2.clone()), (self.1.clone(), self.0.clone()), (self.1.clone(), self.2.clone()), (self.2.clone(), self.0), (self.2, self.1))
}
}
impl<T0: Clone, T1: Clone, T2: Clone, T3: Clone> TuplePermutations2 for (T0, T1, T2, T3) {
type Output = ((T0, T1), (T0, T2), (T0, T3), (T1, T0), (T1, T2), (T1, T3), (T2, T0), (T2, T1), (T2, T3), (T3, T0), (T3, T1), (T3, T2));
fn permutations_2(self) -> Self::Output {
((self.0.clone(), self.1.clone()), (self.0.clone(), self.2.clone()), (self.0.clone(), self.3.clone()), (self.1.clone(), self.0.clone()), (self.1.clone(), self.2.clone()), (self.1.clone(), self.3.clone()), (self.2.clone(), self.0.clone()), (self.2.clone(), self.1.clone()), (self.2.clone(), self.3.clone()), (self.3.clone(), self.0), (self.3.clone(), self.1), (self.3, self.2))
}
}
impl<T0: Clone, T1: Clone, T2: Clone, T3: Clone, T4: Clone> TuplePermutations2 for (T0, T1, T2, T3, T4) {
type Output = ((T0, T1), (T0, T2), (T0, T3), (T0, T4), (T1, T0), (T1, T2), (T1, T3), (T1, T4), (T2, T0), (T2, T1), (T2, T3), (T2, T4), (T3, T0), (T3, T1), (T3, T2), (T3, T4), (T4, T0), (T4, T1), (T4, T2), (T4, T3));
fn permutations_2(self) -> Self::Output {
((self.0.clone(), self.1.clone()), (self.0.clone(), self.2.clone()), (self.0.clone(), self.3.clone()), (self.0.clone(), self.4.clone()), (self.1.clone(), self.0.clone()), (self.1.clone(), self.2.clone()), (self.1.clone(), self.3.clone()), (self.1.clone(), self.4.clone()), (self.2.clone(), self.0.clone()), (self.2.clone(), self.1.clone()), (self.2.clone(), self.3.clone()), (self.2.clone(), self.4.clone()), (self.3.clone(), self.0.clone()), (self.3.clone(), self.1.clone()), (self.3.clone(), self.2.clone()), (self.3.clone(), self.4.clone()), (self.4.clone(), self.0), (self.4.clone(), self.1), (self.4.clone(), self.2), (self.4, self.3))
}
}
impl<T0: Clone, T1: Clone, T2: Clone, T3: Clone, T4: Clone, T5: Clone> TuplePermutations2 for (T0, T1, T2, T3, T4, T5) {
type Output = ((T0, T1), (T0, T2), (T0, T3), (T0, T4), (T0, T5), (T1, T0), (T1, T2), (T1, T3), (T1, T4), (T1, T5), (T2, T0), (T2, T1), (T2, T3), (T2, T4), (T2, T5), (T3, T0), (T3, T1), (T3, T2), (T3, T4), (T3, T5), (T4, T0), (T4, T1), (T4, T2), (T4, T3), (T4, T5), (T5, T0), (T5, T1), (T5, T2), (T5, T3), (T5, T4));
fn permutations_2(self) -> Self::Output {
((self.0.clone(), self.1.clone()), (self.0.clone(), self.2.clone()), (self.0.clone(), self.3.clone()), (self.0.clone(), self.4.clone()), (self.0.clone(), self.5.clone()), (self.1.clone(), self.0.clone()), (self.1.clone(), self.2.clone()), (self.1.clone(), self.3.clone()), (self.1.clone(), self.4.clone()), (self.1.clone(), self.5.clone()), (self.2.clone(), self.0.clone()), (self.2.clone(), self.1.clone()), (self.2.clone(), self.3.clone()), (self.2.clone(), self.4.clone()), (self.2.clone(), self.5.clone()), (self.3.clone(), self.0.clone()), (self.3.clone(), self.1.clone()), (self.3.clone(), self.2.clone()), (self.3.clone(), self.4.clone()), (self.3.clone(), self.5.clone()), (self.4.clone(), self.0.clone()), (self.4.clone(), self.1.clone()), (self.4.clone(), self.2.clone()), (self.4.clone(), self.3.clone()), (self.4.clone(), self.5.clone()), (self.5.clone(), self.0), (self.5.clone(), self.1), (self.5.clone(), self.2), (self.5.clone(), self.3), (self.5, self.4))
}
}
#[doc = "Permutation by 3"]
pub trait TuplePermutations3 {
type Output;
#[doc = "Permutation by 3"]
fn permutations_3(self) -> Self::Output;
}
impl<T0: Clone, T1: Clone, T2: Clone> TuplePermutations3 for (T0, T1, T2) {
type Output = ((T0, T1, T2), (T0, T2, T1), (T1, T0, T2), (T1, T2, T0), (T2, T0, T1), (T2, T1, T0));
fn permutations_3(self) -> Self::Output {
((self.0.clone(), self.1.clone(), self.2.clone()), (self.0.clone(), self.2.clone(), self.1.clone()), (self.1.clone(), self.0.clone(), self.2.clone()), (self.1.clone(), self.2.clone(), self.0.clone()), (self.2.clone(), self.0.clone(), self.1.clone()), (self.2, self.1, self.0))
}
}
7 changes: 6 additions & 1 deletion tuples/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![no_std]
#![allow(unused_imports)]

#[cfg(feature = "tuple_meta")]
mod meta {
Expand Down Expand Up @@ -107,7 +108,6 @@ mod shorthand {
{ $($t:tt)* } => { tuple_! { $($t)* } }
}
}
#[allow(unused_imports)]
#[cfg(feature = "shorthand")]
pub use shorthand::*;

Expand Down Expand Up @@ -206,3 +206,8 @@ pub use sort::*;
pub mod tuple_swap_n;
#[cfg(any(all(feature = "tuple_swap_n", feature = "re-exports"), test, doc))]
pub use tuple_swap_n::*;

#[cfg(any(feature = "permutations", test, doc))]
pub mod permutations;
#[cfg(any(all(feature = "permutations", feature = "re-exports"), test, doc))]
pub use permutations::*;
21 changes: 21 additions & 0 deletions tuples/src/permutations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
include!("./gen/permutations.rs");

#[cfg(test)]
mod tests {
use super::TuplePermutations2;

#[test]
fn test1() {
let a = (1, 2, 3);
let r = a.permutations_2();
assert_eq!(r, ((1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)));
}


#[test]
fn test2() {
let a = (1, '2', "3");
let r = a.permutations_2();
assert_eq!(r, ((1, '2'), (1, "3"), ('2', 1), ('2', "3"), ("3", 1), ("3", '2')));
}
}

0 comments on commit 3336f84

Please sign in to comment.