git.iko.soy/typeable/attoparsec
on master help sign in
Text.FastSet: Always add at least one element of padding

Otherwise consider the case of, let fs = fromList "abcx" in '\239' `member` fs In this case, * `l == 4`, therefore * `((5 * l) `div` 4) == 5`, therefore * `mask' == 7`, therefore * we ended up with a hashtable array of length 14 * however, during the membership check we start with `i = 239 .&. 7 = 7` * meaning the first entrance into `go` starts with `j = 14`; the first `lookupAt` tries to examine elements 14 and 15 of the hashtable array, which are out-of-bounds. The solution taken here is to ensure there is always at least one entry of padding at the end of the hashtable array. This now passes the quickcheck tests added previously. `FastSet` carries a quite nice performance improvement in microbenchmarks, ``` benchmarking sets/Fast time 8.046 ns (8.011 ns .. 8.115 ns) 0.999 R² (0.999 R² .. 1.000 R²) mean 8.076 ns (8.042 ns .. 8.130 ns) std dev 135.4 ps (98.67 ps .. 193.0 ps) variance introduced by outliers: 24% (moderately inflated) benchmarking sets/Hash time 15.18 ns (15.13 ns .. 15.24 ns) 1.000 R² (1.000 R² .. 1.000 R²) mean 15.15 ns (15.13 ns .. 15.19 ns) std dev 94.77 ps (62.22 ps .. 155.6 ps) benchmarking sets/Int time 14.11 ns (14.03 ns .. 14.22 ns) 1.000 R² (1.000 R² .. 1.000 R²) mean 14.22 ns (14.16 ns .. 14.28 ns) std dev 210.7 ps (184.2 ps .. 250.6 ps) variance introduced by outliers: 19% (moderately inflated) benchmarking sets/TextFast time 8.532 ns (8.482 ns .. 8.572 ns) 1.000 R² (1.000 R² .. 1.000 R²) mean 8.485 ns (8.461 ns .. 8.520 ns) std dev 101.8 ps (81.45 ps .. 161.0 ps) variance introduced by outliers: 14% (moderately inflated) ``` Fixes #103.

commite6813a3f0f9d2e86773f79f2730c1cd9ece2300d authorBen Gamari <ben@smart-cactus.org> dateFri 8 Apr 2016, 12:20 (11 years ago) parentf13c4cb
2 files changed+6−2
Data/Attoparsec/Text/FastSet.hs+3−1 benchmarks/TextFastSet.hs+3−1
Data/Attoparsec/Text/FastSet.hs+3−1
@@ -62,7 +62,9 @@ resolveCollisions (a:b:entries) = a' : resolveCollisions (b' : entries)
6262
6363pad :: Int -> [Entry] -> [Entry]
6464pad = go 0
65− where go !_ !m [] = replicate (max 1 m) empty
65+ where -- ensure that we pad enough so that lookups beyond the
66+ -- last hash in the table fall within the array
67+ go !_ !m [] = replicate (max 1 m + 1) empty
6668 go k m (e:entries) = map (const empty) [k..i - 1] ++ e :
6769 go (i + 1) (m + i - k - 1) entries
6870 where i = index e
benchmarks/TextFastSet.hs+3−1
@@ -62,7 +62,9 @@ resolveCollisions (a:b:entries) = a' : resolveCollisions (b' : entries)
6262
6363pad :: Int -> [Entry] -> [Entry]
6464pad = go 0
65− where go !_ !m [] = replicate (max 1 m) empty
65+ where -- ensure that we pad enough so that lookups beyond the
66+ -- last hash in the table fall within the array
67+ go !_ !m [] = replicate (max 1 m + 1) empty
6668 go k m (e:entries) = map (const empty) [k..i - 1] ++ e :
6769 go (i + 1) (m + i - k - 1) entries
6870 where i = index e