1 | use ttf_parser::GlyphId; |
2 | |
3 | // To make things easier, we don't have the generic parameter mask_t, |
4 | // and assume we always use u64, since this is what is also used in |
5 | // harfbuzz. |
6 | type mask_t = u64; |
7 | |
8 | pub trait hb_set_digest_ext: Clone { |
9 | type A; |
10 | // Instead of `init()` |
11 | fn new() -> Self; |
12 | fn full() -> Self; |
13 | fn add(&mut self, g: GlyphId); |
14 | fn add_array(&mut self, array: impl IntoIterator<Item = GlyphId> + Clone); |
15 | fn add_range(&mut self, a: GlyphId, b: GlyphId) -> bool; |
16 | fn may_have(&self, o: &Self::A) -> bool; |
17 | fn may_have_glyph(&self, g: GlyphId) -> bool; |
18 | } |
19 | |
20 | #[derive (Clone)] |
21 | pub struct hb_set_digest_bits_pattern_t<const shift: u8> { |
22 | mask: mask_t, |
23 | } |
24 | |
25 | impl<const shift: u8> hb_set_digest_bits_pattern_t<shift> { |
26 | const fn mask_bytes() -> mask_t { |
27 | core::mem::size_of::<mask_t>() as mask_t |
28 | } |
29 | |
30 | const fn mask_bits() -> mask_t { |
31 | (core::mem::size_of::<mask_t>() * 8) as mask_t |
32 | } |
33 | |
34 | fn mask_for(g: GlyphId) -> mask_t { |
35 | 1 << ((g.0 as mask_t >> shift) & (hb_set_digest_bits_pattern_t::<shift>::mask_bits() - 1)) |
36 | } |
37 | |
38 | const fn num_bits() -> usize { |
39 | let mut num = 0; |
40 | |
41 | if hb_set_digest_bits_pattern_t::<shift>::mask_bytes() >= 1 { |
42 | num += 3; |
43 | } |
44 | |
45 | if hb_set_digest_bits_pattern_t::<shift>::mask_bytes() >= 2 { |
46 | num += 1; |
47 | } |
48 | |
49 | if hb_set_digest_bits_pattern_t::<shift>::mask_bytes() >= 4 { |
50 | num += 1; |
51 | } |
52 | |
53 | if hb_set_digest_bits_pattern_t::<shift>::mask_bytes() >= 8 { |
54 | num += 1; |
55 | } |
56 | |
57 | if hb_set_digest_bits_pattern_t::<shift>::mask_bytes() >= 16 { |
58 | num += 1; |
59 | } |
60 | |
61 | num |
62 | } |
63 | } |
64 | |
65 | impl<const shift: u8> hb_set_digest_ext for hb_set_digest_bits_pattern_t<shift> { |
66 | type A = hb_set_digest_bits_pattern_t<shift>; |
67 | |
68 | fn new() -> Self { |
69 | debug_assert!((shift as usize) < core::mem::size_of::<GlyphId>() * 8); |
70 | debug_assert!((shift as usize + Self::num_bits()) < core::mem::size_of::<GlyphId>() * 8); |
71 | Self { mask: 0 } |
72 | } |
73 | |
74 | fn full() -> Self { |
75 | Self { mask: mask_t::MAX } |
76 | } |
77 | |
78 | fn add(&mut self, g: GlyphId) { |
79 | self.mask |= hb_set_digest_bits_pattern_t::<shift>::mask_for(g); |
80 | } |
81 | |
82 | fn add_array(&mut self, array: impl IntoIterator<Item = GlyphId> + Clone) { |
83 | for el in array { |
84 | self.add(el); |
85 | } |
86 | } |
87 | |
88 | fn add_range(&mut self, a: GlyphId, b: GlyphId) -> bool { |
89 | if self.mask == mask_t::MAX { |
90 | return false; |
91 | } |
92 | |
93 | if (b.0 as mask_t >> shift) - (a.0 as mask_t >> shift) |
94 | >= hb_set_digest_bits_pattern_t::<shift>::mask_bits() - 1 |
95 | { |
96 | self.mask = mask_t::MAX; |
97 | false |
98 | } else { |
99 | let ma = hb_set_digest_bits_pattern_t::<shift>::mask_for(a); |
100 | let mb = hb_set_digest_bits_pattern_t::<shift>::mask_for(b); |
101 | self.mask |= mb + mb.wrapping_sub(ma) - mask_t::from(mb < ma); |
102 | true |
103 | } |
104 | } |
105 | |
106 | fn may_have(&self, o: &hb_set_digest_bits_pattern_t<shift>) -> bool { |
107 | self.mask & o.mask != 0 |
108 | } |
109 | |
110 | fn may_have_glyph(&self, g: GlyphId) -> bool { |
111 | self.mask & hb_set_digest_bits_pattern_t::<shift>::mask_for(g) != 0 |
112 | } |
113 | } |
114 | |
115 | #[derive (Clone)] |
116 | pub struct hb_set_digest_combiner_t<head_t, tail_t> |
117 | where |
118 | head_t: hb_set_digest_ext, |
119 | tail_t: hb_set_digest_ext, |
120 | { |
121 | head: head_t, |
122 | tail: tail_t, |
123 | } |
124 | |
125 | impl<head_t, tail_t> hb_set_digest_ext for hb_set_digest_combiner_t<head_t, tail_t> |
126 | where |
127 | head_t: hb_set_digest_ext<A = head_t>, |
128 | tail_t: hb_set_digest_ext<A = tail_t>, |
129 | { |
130 | type A = hb_set_digest_combiner_t<head_t, tail_t>; |
131 | |
132 | fn new() -> Self { |
133 | Self { |
134 | head: head_t::new(), |
135 | tail: tail_t::new(), |
136 | } |
137 | } |
138 | |
139 | fn full() -> Self { |
140 | Self { |
141 | head: head_t::full(), |
142 | tail: tail_t::full(), |
143 | } |
144 | } |
145 | |
146 | fn add(&mut self, g: GlyphId) { |
147 | self.head.add(g); |
148 | self.tail.add(g); |
149 | } |
150 | |
151 | fn add_array(&mut self, array: impl IntoIterator<Item = GlyphId> + Clone) { |
152 | // TODO: Is this expensive if someone passes e.g. a vector? |
153 | self.head.add_array(array.clone()); |
154 | self.tail.add_array(array); |
155 | } |
156 | |
157 | fn add_range(&mut self, a: GlyphId, b: GlyphId) -> bool { |
158 | let first = self.head.add_range(a, b); |
159 | let second = self.tail.add_range(a, b); |
160 | first || second |
161 | } |
162 | |
163 | fn may_have(&self, o: &Self::A) -> bool { |
164 | self.head.may_have(&o.head) && self.tail.may_have(&o.tail) |
165 | } |
166 | |
167 | fn may_have_glyph(&self, g: GlyphId) -> bool { |
168 | self.head.may_have_glyph(g) && self.tail.may_have_glyph(g) |
169 | } |
170 | } |
171 | |
172 | #[rustfmt::skip] |
173 | pub type hb_set_digest_t = hb_set_digest_combiner_t< |
174 | hb_set_digest_bits_pattern_t<4>, |
175 | hb_set_digest_combiner_t< |
176 | hb_set_digest_bits_pattern_t<0>, |
177 | hb_set_digest_bits_pattern_t<9> |
178 | >, |
179 | >; |
180 | |
181 | #[rustfmt::skip] |
182 | #[cfg (test)] |
183 | mod tests { |
184 | use super::*; |
185 | |
186 | #[test ] |
187 | fn test_single() { |
188 | let mut set = hb_set_digest_t::new(); |
189 | |
190 | set.add(GlyphId(2)); |
191 | assert!(set.may_have_glyph(GlyphId(2))) |
192 | } |
193 | |
194 | #[test ] |
195 | fn test_multiple_1() { |
196 | let mut set = hb_set_digest_t::new(); |
197 | |
198 | set.add(GlyphId(2)); |
199 | set.add(GlyphId(10)); |
200 | set.add(GlyphId(300)); |
201 | set.add(GlyphId(255)); |
202 | assert!(set.may_have_glyph(GlyphId(2))); |
203 | assert!(set.may_have_glyph(GlyphId(300))); |
204 | assert!(set.may_have_glyph(GlyphId(10))); |
205 | assert!(set.may_have_glyph(GlyphId(255))); |
206 | } |
207 | |
208 | #[test ] |
209 | fn test_multiple_2() { |
210 | let mut set = hb_set_digest_t::new(); |
211 | |
212 | set.add(GlyphId(245)); |
213 | set.add(GlyphId(1060)); |
214 | set.add(GlyphId(300)); |
215 | set.add(GlyphId(599)); |
216 | assert!(set.may_have_glyph(GlyphId(245))); |
217 | assert!(set.may_have_glyph(GlyphId(1060))); |
218 | assert!(set.may_have_glyph(GlyphId(300))); |
219 | assert!(set.may_have_glyph(GlyphId(599))); |
220 | } |
221 | |
222 | #[test ] |
223 | fn test_range_1() { |
224 | let mut set = hb_set_digest_t::new(); |
225 | |
226 | set.add_range(GlyphId(10), GlyphId(12)); |
227 | assert!(set.may_have_glyph(GlyphId(10))); |
228 | assert!(set.may_have_glyph(GlyphId(11))); |
229 | assert!(set.may_have_glyph(GlyphId(12))); |
230 | } |
231 | |
232 | #[test ] |
233 | fn test_range_2() { |
234 | let mut set = hb_set_digest_t::new(); |
235 | |
236 | set.add_range(GlyphId(15), GlyphId(20)); |
237 | assert!(set.may_have_glyph(GlyphId(15))); |
238 | assert!(set.may_have_glyph(GlyphId(16))); |
239 | assert!(set.may_have_glyph(GlyphId(17))); |
240 | assert!(set.may_have_glyph(GlyphId(18))); |
241 | assert!(set.may_have_glyph(GlyphId(19))); |
242 | assert!(set.may_have_glyph(GlyphId(20))); |
243 | } |
244 | |
245 | #[test ] |
246 | fn test_range_3() { |
247 | let mut set = hb_set_digest_t::new(); |
248 | |
249 | for i in 170..=239 { |
250 | set.add(GlyphId(i)); |
251 | } |
252 | assert!(set.may_have_glyph(GlyphId(200))); |
253 | } |
254 | |
255 | #[test ] |
256 | fn test_complex() { |
257 | let mut set = hb_set_digest_t::new(); |
258 | |
259 | set.add_range(GlyphId(5670), GlyphId(5675)); |
260 | set.add(GlyphId(3)); |
261 | set.add(GlyphId(8769)); |
262 | set.add(GlyphId(10000)); |
263 | set.add_range(GlyphId(3456), GlyphId(3460)); |
264 | assert!(set.may_have_glyph(GlyphId(5670))); |
265 | assert!(set.may_have_glyph(GlyphId(5675))); |
266 | assert!(set.may_have_glyph(GlyphId(3))); |
267 | assert!(set.may_have_glyph(GlyphId(8769))); |
268 | assert!(set.may_have_glyph(GlyphId(10000))); |
269 | assert!(set.may_have_glyph(GlyphId(3456))); |
270 | assert!(set.may_have_glyph(GlyphId(3460))); |
271 | } |
272 | } |
273 | |