@@ -11,8 +11,8 @@ use std::arch::x86::*;
1111use std:: arch:: x86_64:: * ;
1212use std:: mem;
1313
14- /// Rolling hash for the simple Rabin-Karp implementation. As a hashing function, the sum of all the
15- /// bytes is computed.
14+ /// Rolling hash for the simple Rabin-Karp implementation. As a hashing
15+ /// function, the sum of all the bytes is computed.
1616#[ derive( Clone , Copy , Default , PartialEq ) ]
1717struct ScalarHash ( usize ) ;
1818
@@ -38,8 +38,9 @@ impl ScalarHash {
3838 }
3939}
4040
41- /// Represents an SIMD register type that is x86-specific (but could be used more generically) in
42- /// order to share functionality between SSE2, AVX2 and possibly future implementations.
41+ /// Represents an SIMD register type that is x86-specific (but could be used
42+ /// more generically) in order to share functionality between SSE2, AVX2 and
43+ /// possibly future implementations.
4344trait Vector : Copy {
4445 unsafe fn set1_epi8 ( a : i8 ) -> Self ;
4546
@@ -116,9 +117,10 @@ impl Vector for __m256i {
116117 }
117118}
118119
119- /// Hash of the first and "last" bytes in the needle for use with the SIMD algorithm implemented by
120- /// `Avx2Searcher::vector_search_in`. As explained, any byte can be chosen to represent the "last"
121- /// byte of the hash to prevent worst-case attacks.
120+ /// Hash of the first and "last" bytes in the needle for use with the SIMD
121+ /// algorithm implemented by `Avx2Searcher::vector_search_in`. As explained, any
122+ /// byte can be chosen to represent the "last" byte of the hash to prevent
123+ /// worst-case attacks.
122124struct VectorHash < V : Vector > {
123125 first : V ,
124126 last : V ,
@@ -136,30 +138,36 @@ impl<V: Vector> VectorHash<V> {
136138
137139macro_rules! avx2_searcher {
138140 ( $name: ident, $size: literal, $memcmp: path) => {
139- /// Single-substring searcher using an AVX2 algorithm based on the "Generic SIMD" algorithm
140- /// [presented by Wojciech Muła](http://0x80.pl/articles/simd-strfind.html).
141+ /// Single-substring searcher using an AVX2 algorithm based on the
142+ /// "Generic SIMD" algorithm [presented by Wojciech
143+ /// Muła](http://0x80.pl/articles/simd-strfind.html).
141144 ///
142- /// It is similar to the Rabin-Karp algorithm, except that the hash is not rolling and is
143- /// calculated for several lanes at once. It begins by picking the first byte in the needle
144- /// and checking at which positions in the haystack it occurs. Any position where it does
145- /// not can be immediately discounted as a potential match.
145+ /// It is similar to the Rabin-Karp algorithm, except that the hash is
146+ /// not rolling and is calculated for several lanes at once. It begins
147+ /// by picking the first byte in the needle and checking at which
148+ /// positions in the haystack it occurs. Any position where it does not
149+ /// can be immediately discounted as a potential match.
146150 ///
147- /// We then repeat this idea with a second byte in the needle (where the haystack is
148- /// suitably offset) and take a bitwise AND to further limit the possible positions the
149- /// needle can match in. Any remaining positions are fully evaluated using an equality
150- /// comparison with the needle.
151+ /// We then repeat this idea with a second byte in the needle (where the
152+ /// haystack is suitably offset) and take a bitwise AND to further limit
153+ /// the possible positions the needle can match in. Any remaining
154+ /// positions are fully evaluated using an equality comparison with the
155+ /// needle.
151156 ///
152- /// Originally, the algorithm always used the last byte for this second byte. Whilst this is
153- /// often the most efficient option, it is vulnerable to a worst-case attack and so this
154- /// implementation instead allows any byte (including a random one) to be chosen.
157+ /// Originally, the algorithm always used the last byte for this second
158+ /// byte. Whilst this is often the most efficient option, it is
159+ /// vulnerable to a worst-case attack and so this implementation instead
160+ /// allows any byte (including a random one) to be chosen.
155161 ///
156- /// In the case where the needle is not a multiple of the number of SIMD lanes, the last
157- /// chunk is made up of a partial overlap with the penultimate chunk to avoid reading random
158- /// memory, differing from the original implementation. In this case, a mask is used to
159- /// prevent performing an equality comparison on the same position twice.
162+ /// In the case where the needle is not a multiple of the number of SIMD
163+ /// lanes, the last chunk is made up of a partial overlap with the
164+ /// penultimate chunk to avoid reading random memory, differing from the
165+ /// original implementation. In this case, a mask is used to prevent
166+ /// performing an equality comparison on the same position twice.
160167 ///
161- /// When the haystack is too short for an AVX2 register, a similar SSE2 fallback is used
162- /// instead. Finally, for very short haystacks there is a scalar Rabin-Karp implementation.
168+ /// When the haystack is too short for an AVX2 register, a similar SSE2
169+ /// fallback is used instead. Finally, for very short haystacks there is
170+ /// a scalar Rabin-Karp implementation.
163171 pub struct $name {
164172 needle: Box <[ u8 ] >,
165173 position: usize ,
@@ -169,15 +177,16 @@ macro_rules! avx2_searcher {
169177 }
170178
171179 impl $name {
172- /// Creates a new searcher for `needle`. By default, `position` is set to the last
173- /// character in the needle.
180+ /// Creates a new searcher for `needle`. By default, `position` is
181+ /// set to the last character in the needle.
174182 #[ target_feature( enable = "avx2" ) ]
175183 pub unsafe fn new( needle: Box <[ u8 ] >) -> Self {
176184 let position = needle. len( ) - 1 ;
177185 Self :: with_position( needle, position)
178186 }
179187
180- /// Same as `new` but allows additionally specifying the `position` to use.
188+ /// Same as `new` but allows additionally specifying the `position`
189+ /// to use.
181190 #[ target_feature( enable = "avx2" ) ]
182191 pub unsafe fn with_position( needle: Box <[ u8 ] >, position: usize ) -> Self {
183192 assert!( !needle. is_empty( ) ) ;
@@ -344,12 +353,14 @@ avx2_searcher!(Avx2Searcher11, 11, memcmp::memcmp10);
344353avx2_searcher ! ( Avx2Searcher12 , 12 , memcmp:: memcmp11) ;
345354avx2_searcher ! ( Avx2Searcher13 , 13 , memcmp:: memcmp12) ;
346355
347- /// Single-substring searcher based on `Avx2Searcher` but with dynamic algorithm selection.
356+ /// Single-substring searcher based on `Avx2Searcher` but with dynamic algorithm
357+ /// selection.
348358///
349- /// It has specialized cases for zero-length needles, which are found in all haystacks, and
350- /// one-length needles, which uses `MemchrSearcher`. For needles up to a length of thirteen it uses
351- /// specialized versions of `Avx2Searcher`, finally falling back to the generic version of
352- /// `Avx2Searcher` for longer needles.
359+ /// It has specialized cases for zero-length needles, which are found in all
360+ /// haystacks, and one-length needles, which uses `MemchrSearcher`. For needles
361+ /// up to a length of thirteen it uses specialized versions of `Avx2Searcher`,
362+ /// finally falling back to the generic version of `Avx2Searcher` for longer
363+ /// needles.
353364pub enum DynamicAvx2Searcher {
354365 /// Specialization for needles with length 0.
355366 N0 ,
@@ -384,8 +395,8 @@ pub enum DynamicAvx2Searcher {
384395}
385396
386397impl DynamicAvx2Searcher {
387- /// Creates a new searcher for `needle`. By default, `position` is set to the last character in
388- /// the needle.
398+ /// Creates a new searcher for `needle`. By default, `position` is set to
399+ /// the last character in the needle.
389400 #[ target_feature( enable = "avx2" ) ]
390401 pub unsafe fn new ( needle : Box < [ u8 ] > ) -> Self {
391402 let position = needle. len ( ) - 1 ;
0 commit comments