rapidfuzz/details/
common.rs1use crate::{Hash, HashableChar};
2use std::iter::{Skip, Take};
3
4pub fn norm_sim_to_norm_dist(score_cutoff: f64) -> f64 {
5 let imprecision = 0.00001;
6 (1.0 - score_cutoff + imprecision).min(1.0)
7}
8
9macro_rules! impl_hashable_char {
10 ($base_type:ty, $kind:tt $(, $t:ty)*) => {
11 impl HashableChar for $base_type {
12 #[inline]
13 fn hash_char(&self) -> Hash
14 {
15 Hash::$kind(*self $(as $t)*)
16 }
17 }
18
19 impl HashableChar for &$base_type {
20 #[inline]
21 fn hash_char(&self) -> Hash
22 {
23 Hash::$kind(**self $(as $t)*)
24 }
25 }
26 }
27}
28
29impl_hashable_char!(char, UNSIGNED, u32, u64);
30impl_hashable_char!(i8, SIGNED, i64);
31impl_hashable_char!(i16, SIGNED, i64);
32impl_hashable_char!(i32, SIGNED, i64);
33impl_hashable_char!(i64, SIGNED, i64);
34impl_hashable_char!(u8, UNSIGNED, u64);
35impl_hashable_char!(u16, UNSIGNED, u64);
36impl_hashable_char!(u32, UNSIGNED, u64);
37impl_hashable_char!(u64, UNSIGNED, u64);
38
39pub fn find_common_prefix<Iter1, Iter2>(s1: Iter1, s2: Iter2) -> usize
40where
41 Iter1: Iterator + Clone,
42 Iter2: Iterator + Clone,
43 Iter1::Item: PartialEq<Iter2::Item>,
44 Iter2::Item: PartialEq<Iter1::Item>,
45{
46 s1.zip(s2)
47 .take_while(|(a_char, b_char)| a_char == b_char)
48 .count()
49}
50
51pub fn find_common_suffix<Iter1, Iter2>(s1: Iter1, s2: Iter2) -> usize
52where
53 Iter1: DoubleEndedIterator + Clone,
54 Iter2: DoubleEndedIterator + Clone,
55 Iter1::Item: PartialEq<Iter2::Item>,
56 Iter2::Item: PartialEq<Iter1::Item>,
57{
58 s1.rev()
59 .zip(s2.rev())
60 .take_while(|(a_char, b_char)| a_char == b_char)
61 .count()
62}
63
64pub struct RemovedAffix<Iter1, Iter2>
65where
66 Iter1: DoubleEndedIterator + Clone,
67 Iter2: DoubleEndedIterator + Clone,
68 Iter1::Item: PartialEq<Iter2::Item>,
69 Iter2::Item: PartialEq<Iter1::Item>,
70{
71 pub s1: Skip<Take<Iter1>>,
72 pub len1: usize,
73 pub s2: Skip<Take<Iter2>>,
74 pub len2: usize,
75 pub prefix_len: usize,
76 pub suffix_len: usize,
77}
78
79pub fn remove_common_affix<Iter1, Iter2>(
80 s1: Iter1,
81 mut len1: usize,
82 s2: Iter2,
83 mut len2: usize,
84) -> RemovedAffix<Iter1, Iter2>
85where
86 Iter1: DoubleEndedIterator + Clone,
87 Iter2: DoubleEndedIterator + Clone,
88 Iter1::Item: PartialEq<Iter2::Item> + HashableChar,
89 Iter2::Item: PartialEq<Iter1::Item> + HashableChar,
90{
91 let suffix_len = find_common_suffix(s1.clone(), s2.clone());
92 let s1_iter_no_suffix = s1.take(len1 - suffix_len);
93 let s2_iter_no_suffix = s2.take(len2 - suffix_len);
94 let prefix_len = find_common_prefix(s1_iter_no_suffix.clone(), s2_iter_no_suffix.clone());
95 let s1_iter = s1_iter_no_suffix.skip(prefix_len);
96 let s2_iter = s2_iter_no_suffix.skip(prefix_len);
97 len1 -= prefix_len + suffix_len;
98 len2 -= prefix_len + suffix_len;
99
100 RemovedAffix {
101 s1: s1_iter,
102 len1,
103 s2: s2_iter,
104 len2,
105 prefix_len,
106 suffix_len,
107 }
108}