11use std:: collections:: { HashMap , HashSet } ;
2- use std:: iter:: FromIterator ;
32
43pub type CharSet = HashSet < char > ;
54pub type Occurrences = HashMap < char , Vec < Occurrence > > ;
65
7- #[ derive( Clone , Copy , Debug ) ]
6+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
7+ #[ repr( align( 8 ) ) ]
88pub struct Occurrence {
99 pub target_idx : u32 ,
10- pub is_start : bool ,
11- pub char : char ,
10+ data : u32 ,
1211}
1312
14- impl Eq for Occurrence { }
13+ impl Occurrence {
14+ #[ inline]
15+ pub fn new ( target_idx : u32 , is_start : bool , char : char ) -> Self {
16+ assert_eq ! ( char as u32 & ( 1 << 31 ) , 0 ) ;
17+ Self {
18+ target_idx,
19+ data : ( ( is_start as u32 ) << 31 ) | char as u32 ,
20+ }
21+ }
1522
16- impl PartialEq for Occurrence {
17- fn eq ( & self , other : & Occurrence ) -> bool {
18- self . target_idx == other. target_idx
19- && self . char == other. char
20- && self . is_start == other. is_start
23+ #[ inline]
24+ pub fn is_start ( self ) -> bool {
25+ ( self . data >> 31 ) != 0
26+ }
27+
28+ #[ inline]
29+ pub fn char ( self ) -> char {
30+ unsafe { char:: from_u32_unchecked ( self . data & !( 1 << 31 ) ) }
2131 }
2232}
2333
@@ -54,11 +64,7 @@ pub fn build_occurrences(query: &QueryChars, string: &str, case_insensitive: boo
5464 occurrences
5565 . entry ( key_char)
5666 . or_insert ( Vec :: new ( ) )
57- . push ( Occurrence {
58- char : original_c,
59- target_idx : i as u32 ,
60- is_start,
61- } ) ;
67+ . push ( Occurrence :: new ( i as u32 , is_start, original_c) ) ;
6268 }
6369
6470 continue ;
@@ -76,11 +82,7 @@ pub fn build_occurrences(query: &QueryChars, string: &str, case_insensitive: boo
7682 occurrences
7783 . entry ( key_char)
7884 . or_insert ( Vec :: new ( ) )
79- . push ( Occurrence {
80- char : original_c,
81- target_idx : i as u32 ,
82- is_start,
83- } ) ;
85+ . push ( Occurrence :: new ( i as u32 , is_start, original_c) ) ;
8486 }
8587
8688 prev_is_start = is_start;
@@ -141,6 +143,19 @@ mod tests {
141143
142144 use super :: { Occurrence , QueryChar , build_occurrences, condense, is_word_sep, process_query} ;
143145
146+ #[ test]
147+ fn occurrence_repr ( ) {
148+ for c in char:: MIN ..=char:: MAX {
149+ let o = Occurrence :: new ( 0 , false , c) ;
150+ assert ! ( !o. is_start( ) ) ;
151+ assert_eq ! ( o. char ( ) , c) ;
152+
153+ let o = Occurrence :: new ( 0 , true , c) ;
154+ assert ! ( o. is_start( ) ) ;
155+ assert_eq ! ( o. char ( ) , c) ;
156+ }
157+ }
158+
144159 #[ test]
145160 fn word_seps ( ) {
146161 let seps: Vec < char > = vec ! [
@@ -204,52 +219,6 @@ mod tests {
204219 ) ;
205220 }
206221
207- #[ test]
208- fn occurrence_eq ( ) {
209- let a = Occurrence {
210- char : 'c' ,
211- target_idx : 0 ,
212- is_start : true ,
213- } ;
214-
215- assert_eq ! (
216- a,
217- Occurrence {
218- char : 'c' ,
219- target_idx: 0 ,
220- is_start: true
221- }
222- ) ;
223- assert_ne ! (
224- a,
225- Occurrence {
226- char : 'c' ,
227- target_idx: 0 ,
228- is_start: false
229- } ,
230- "is_start differs but eq"
231- ) ;
232- assert_ne ! (
233- a,
234- Occurrence {
235- char : 'c' ,
236- target_idx: 1 ,
237- is_start: true
238- } ,
239- "target_idx differs but eq"
240- ) ;
241-
242- assert_ne ! (
243- a,
244- Occurrence {
245- char : 'b' ,
246- target_idx: 0 ,
247- is_start: true
248- } ,
249- "char differs but eq"
250- ) ;
251- }
252-
253222 #[ test]
254223 fn occurrences ( ) {
255224 let t = "SoccerCartoonController" ;
@@ -260,40 +229,17 @@ mod tests {
260229
261230 let s = occs. remove ( & 's' ) . expect ( "Missing s occurrences" ) ;
262231
263- assert_eq ! (
264- s,
265- vec![ Occurrence {
266- char : 'S' ,
267- target_idx: 0 ,
268- is_start: true ,
269- } ]
270- ) ;
232+ assert_eq ! ( s, vec![ Occurrence :: new( 0 , true , 'S' ) ] ) ;
271233
272234 let c = occs. remove ( & 'c' ) . expect ( "Missing c occurrences" ) ;
273235
274236 assert_eq ! (
275237 c,
276238 vec![
277- Occurrence {
278- char : 'c' ,
279- target_idx: 2 ,
280- is_start: false ,
281- } ,
282- Occurrence {
283- char : 'c' ,
284- target_idx: 3 ,
285- is_start: false ,
286- } ,
287- Occurrence {
288- char : 'C' ,
289- target_idx: 6 ,
290- is_start: true ,
291- } ,
292- Occurrence {
293- char : 'C' ,
294- target_idx: 13 ,
295- is_start: true ,
296- } ,
239+ Occurrence :: new( 2 , false , 'c' ) ,
240+ Occurrence :: new( 3 , false , 'c' ) ,
241+ Occurrence :: new( 6 , true , 'C' ) ,
242+ Occurrence :: new( 13 , true , 'C' ) ,
297243 ]
298244 ) ;
299245 }
@@ -311,16 +257,8 @@ mod tests {
311257 assert_eq ! (
312258 s,
313259 vec![
314- Occurrence {
315- char : 'S' ,
316- target_idx: 0 ,
317- is_start: true ,
318- } ,
319- Occurrence {
320- char : 's' ,
321- target_idx: 3 ,
322- is_start: false ,
323- }
260+ Occurrence :: new( 0 , true , 'S' ) ,
261+ Occurrence :: new( 3 , false , 's' )
324262 ]
325263 ) ;
326264
@@ -329,26 +267,10 @@ mod tests {
329267 assert_eq ! (
330268 c,
331269 vec![
332- Occurrence {
333- char : 'c' ,
334- target_idx: 1 ,
335- is_start: false ,
336- } ,
337- Occurrence {
338- char : 'c' ,
339- target_idx: 2 ,
340- is_start: false ,
341- } ,
342- Occurrence {
343- char : 'C' ,
344- target_idx: 4 ,
345- is_start: true ,
346- } ,
347- Occurrence {
348- char : 'C' ,
349- target_idx: 8 ,
350- is_start: true ,
351- } ,
270+ Occurrence :: new( 1 , false , 'c' ) ,
271+ Occurrence :: new( 2 , false , 'c' ) ,
272+ Occurrence :: new( 4 , true , 'C' ) ,
273+ Occurrence :: new( 8 , true , 'C' ) ,
352274 ]
353275 ) ;
354276 }
0 commit comments