1#![no_std]
2#![cfg_attr(not(debug_assertions), deny(warnings))]
3#![forbid(unsafe_code)]
4#![warn(
5 clippy::all,
6 clippy::await_holding_lock,
7 clippy::char_lit_as_u8,
8 clippy::checked_conversions,
9 clippy::dbg_macro,
10 clippy::debug_assert_with_mut_call,
11 clippy::doc_markdown,
12 clippy::empty_enum,
13 clippy::enum_glob_use,
14 clippy::exit,
15 clippy::expl_impl_clone_on_copy,
16 clippy::explicit_deref_methods,
17 clippy::explicit_into_iter_loop,
18 clippy::fallible_impl_from,
19 clippy::filter_map_next,
20 clippy::float_cmp_const,
21 clippy::fn_params_excessive_bools,
22 clippy::if_let_mutex,
23 clippy::imprecise_flops,
24 clippy::inefficient_to_string,
25 clippy::invalid_upcast_comparisons,
26 clippy::large_types_passed_by_value,
27 clippy::let_unit_value,
28 clippy::linkedlist,
29 clippy::lossy_float_literal,
30 clippy::macro_use_imports,
31 clippy::manual_ok_or,
32 clippy::map_flatten,
33 clippy::match_on_vec_items,
34 clippy::match_same_arms,
35 clippy::match_wildcard_for_single_variants,
36 clippy::mem_forget,
37 clippy::mismatched_target_os,
38 clippy::missing_errors_doc,
39 clippy::missing_safety_doc,
40 clippy::mut_mut,
41 clippy::mutex_integer,
42 clippy::needless_borrow,
43 clippy::needless_continue,
44 clippy::needless_pass_by_value,
45 clippy::option_option,
46 clippy::path_buf_push_overwrite,
47 clippy::ptr_as_ptr,
48 clippy::ref_option_ref,
49 clippy::rest_pat_in_fully_bound_structs,
50 clippy::same_functions_in_if_condition,
51 clippy::string_add_assign,
52 clippy::string_add,
53 clippy::string_lit_as_bytes,
54 clippy::string_to_string,
55 clippy::todo,
56 clippy::trait_duplication_in_bounds,
57 clippy::unimplemented,
58 clippy::unnested_or_patterns,
59 clippy::unused_self,
60 clippy::useless_transmute,
61 clippy::verbose_file_reads,
62 clippy::zero_sized_map_values,
63 future_incompatible,
64 nonstandard_style,
65 rust_2018_idioms
66)]
67#![doc = include_str!("../libdoc.md")]
68
69pub mod quickfind;
70pub mod quickunion;
71pub mod rng;
72
73use core::marker::PhantomData;
74use core::ops::AddAssign;
75
76use rand_core::RngCore;
77
78pub use crate::quickfind::QuickFind;
79use crate::quickunion::Heuristic;
80pub use crate::quickunion::QuickUnion;
81pub use crate::quickunion::{ByRank, BySize, Unweighted};
82
83pub struct Fat;
85pub struct Thin;
86
87pub struct Owned;
88pub struct Borrowed<P: PointerType + ?Sized = Fat>(PhantomData<P>);
89
90pub trait PointerType {}
91impl PointerType for Fat {}
92impl PointerType for Thin {}
93
94pub trait VertexType: Eq + Copy {
96 type IdentifierType: Copy + Eq + PartialOrd + AddAssign<Self::IdentifierType>;
97
98 fn id(&self) -> Self::IdentifierType;
99 fn usize(a: Self::IdentifierType) -> usize;
100}
101
102macro_rules! generate_index_type_impl{
103 ($($num_type:ident), *) => {
104 $(
105 impl VertexType for $num_type {
106 type IdentifierType = Self;
107
108 #[inline(always)]
109 fn id(&self) -> Self {
110 *self
111 }
112
113 #[inline(always)]
114 fn usize(a: Self) -> usize {
115 a as usize
116 }
117 }
118 )*
119 };
120}
121
122generate_index_type_impl!(u8, u16, u32, u64, usize);
123
124pub struct UnionFind<'a, A, T, const N: usize>
158where
159 T: VertexType + 'a,
160 A: AlgorithmContainer,
161{
162 representative: A::RepresentativeContainer<'a, T, N>,
163 heuristic: A::HeuristicContainer<'a, N>,
164 rng: A::RngKind<'a>,
165 algorithm: PhantomData<A>,
166}
167
168impl<'a, A, T, const N: usize> UnionFind<'a, A, T, N>
169where
170 T: VertexType,
171 A: AlgorithmContainer + Union<T, A::HeuristicKind<'a>> + Find<T> + Connected<T>,
172{
173 pub fn connected(&mut self, a: T::IdentifierType, b: T::IdentifierType) -> bool {
175 A::connected(self.representative.as_mut(), a, b)
176 }
177
178 pub fn find(&mut self, a: T::IdentifierType) -> T {
180 A::find(self.representative.as_mut(), a)
181 }
182
183 pub fn union_sets(&mut self, a: T::IdentifierType, b: T::IdentifierType) {
186 A::union_sets(
187 self.representative.as_mut(),
188 self.heuristic.as_mut(),
189 a,
190 b,
191 &mut self.rng,
192 )
193 }
194 pub fn representative(&self) -> &A::RepresentativeContainer<'a, T, N> {
196 &self.representative
197 }
198
199 pub fn heuristic(&self) -> &A::HeuristicContainer<'a, N> {
201 &self.heuristic
202 }
203}
204
205pub trait AlgorithmContainer {
207 type HeuristicKind<'a>: Heuristic<RngProvider = Self::RngKind<'a>>;
208
209 type HeuristicContainer<'a, const N: usize>: AsRef<[usize]> + AsMut<[usize]>;
216
217 type RepresentativeContainer<'a, V: VertexType + 'a, const N: usize>: AsRef<[V]> + AsMut<[V]>;
223
224 type RngKind<'a>: RngCore;
226}
227
228pub trait Union<T: VertexType, H: Heuristic> {
230 fn union_sets(
231 representative: &mut [T],
232 heuristic: &mut [usize],
233 a: T::IdentifierType,
234 b: T::IdentifierType,
235 rng: &mut H::RngProvider,
236 );
237}
238
239pub trait Find<T: VertexType> {
241 fn find(representative: &mut [T], a: T::IdentifierType) -> T;
242}
243
244pub trait Connected<T: VertexType> {
246 fn connected(representative: &mut [T], a: T::IdentifierType, b: T::IdentifierType) -> bool;
247}
248
249#[cfg(test)]
250mod tests {
251 use crate::{QuickFind, QuickUnion, UnionFind, VertexType};
252 use core::mem::size_of;
253
254 #[test]
255 fn test_qf_sz() {
256 assert_eq!(
257 size_of::<UnionFind::<'_, QuickFind, u32, 32>>(),
258 size_of::<[u32; 32]>()
259 );
260 assert_eq!(
261 size_of::<UnionFind::<'_, QuickFind, u8, 32>>(),
262 size_of::<[u8; 32]>()
263 );
264 assert_eq!(
265 size_of::<UnionFind::<'_, QuickFind, usize, 32>>(),
266 size_of::<[usize; 32]>()
267 );
268 }
269
270 #[test]
271 fn test_wqupc_sz() {
272 assert_eq!(
273 size_of::<UnionFind::<'_, QuickUnion, usize, 32>>(),
274 size_of::<[usize; 32]>() * 2
275 );
276
277 assert_eq!(
278 size_of::<UnionFind::<'_, QuickUnion, usize, 32>>(),
279 size_of::<[usize; 32]>() + size_of::<[usize; 32]>()
280 );
281 }
282
283 #[derive(Clone, Copy)]
284 pub struct CityVertex<'a> {
285 pub id: u8,
286 pub name: &'a str,
287 pub road_cost: u32,
288 }
289
290 impl<'a> CityVertex<'a> {
291 pub fn new(id: u8, name: &'a str, road_cost: u32) -> Self {
292 Self {
293 id,
294 name,
295 road_cost,
296 }
297 }
298 }
299
300 impl PartialEq for CityVertex<'_> {
301 fn eq(&self, other: &Self) -> bool {
302 self.id == other.id
303 }
304 }
305
306 impl PartialOrd for CityVertex<'_> {
307 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
308 Some(self.id.cmp(&other.id))
309 }
310 }
311
312 impl Eq for CityVertex<'_> {}
313
314 impl VertexType for CityVertex<'_> {
315 type IdentifierType = u8;
316
317 fn id(&self) -> u8 {
318 self.id
319 }
320
321 fn usize(a: u8) -> usize {
322 a as usize
323 }
324 }
325}