@@ -320,7 +320,6 @@ import Data.Int (Int64)
320import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef, IORef)
320import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef, IORef)
321import Data.Maybe (fromJust, isJust, isNothing)
321import Data.Maybe (fromJust, isJust, isNothing)
322import Data.Word (Word32)
322import Data.Word (Word32)
323−import Foreign.Ptr (Ptr)
324import Foreign.Storable (Storable(..))
323import Foreign.Storable (Storable(..))
325import GHC.Exts (SpecConstrAnnotation(..))
324import GHC.Exts (SpecConstrAnnotation(..))
326import GHC.Types (SPEC(..))
325import GHC.Types (SPEC(..))
@@ -1793,6 +1792,8 @@ data SplitOnSeqState rb rh ck w fs s b x =
1793 | SplitOnSeqDone
1792 | SplitOnSeqDone
1795 | SplitOnSeqEmpty s
1794 | SplitOnSeqEmpty s
1796+ | SplitOnSeqSingleInit s x
1796 | SplitOnSeqSingle !fs s x
1797 | SplitOnSeqSingle !fs s x
1798 | SplitOnSeqWordInit s
1799 | SplitOnSeqWordInit s
@@ -1889,6 +1890,9 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
1889 -- Single Pattern
1890 -- Single Pattern
1890 -----------------
1891 -----------------
1893+ stepOuter _ (SplitOnSeqSingleInit _ _) =
1894+ error "This branch should not have hit"
1892 stepOuter gst (SplitOnSeqSingle fs st pat) = do
1896 stepOuter gst (SplitOnSeqSingle fs st pat) = do
1893 res <- step (adaptState gst) st
1897 res <- step (adaptState gst) st
1894 case res of
1898 case res of
@@ -2059,14 +2063,6 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
2059 fs1 <- fstep fs old
2063 fs1 <- fstep fs old
2060 skip $ SplitOnSeqKRDone (n - 1) fs1 rb rh1
2064 skip $ SplitOnSeqKRDone (n - 1) fs1 rb rh1
2062−data SplitOnState1 s a =
2065− | GO_SINGLE_PAT s a
2067− | GO_KARP_RABIN s !(RB.Ring a) !(Ptr a)
2070{-# INLINE_NORMAL splitSuffixOn #-}
2066{-# INLINE_NORMAL splitSuffixOn #-}
2071splitSuffixOn
2067splitSuffixOn
2072 :: forall m a b. (MonadIO m, Storable a, Enum a, Eq a)
2068 :: forall m a b. (MonadIO m, Storable a, Enum a, Eq a)
@@ -2075,9 +2071,8 @@ splitSuffixOn
2075 -> Fold m a b
2071 -> Fold m a b
2076 -> Stream m a
2072 -> Stream m a
2077 -> Stream m b
2073 -> Stream m b
2078−splitSuffixOn withSep patArr (Fold fstep initial done)
2074+splitSuffixOn withSep patArr (Fold fstep initial done) (Stream step state) =
2079− (Stream step state) =
2080− Stream stepOuter GO_START1
2075+ Stream stepOuter SplitOnSeqInit
@@ -2085,248 +2080,332 @@ splitSuffixOn withSep patArr (Fold fstep initial done)
2085 maxIndex = patLen - 1
2080 maxIndex = patLen - 1
2086 elemBits = sizeOf (undefined :: a) * 8
2081 elemBits = sizeOf (undefined :: a) * 8
2083+ -- For word pattern case
2085+ wordMask = (1 `shiftL` (elemBits * patLen)) - 1
2088+ elemMask = (1 `shiftL` elemBits) - 1
2091+ wordPat = wordMask .&. A.foldl' addToWord 0 patArr
2093+ addToWord wd a = (wd `shiftL` elemBits) .|. fromIntegral (fromEnum a)
2095+ -- For Rabin-Karp search
2096+ k = 2891336453 :: Word32
2099+ addCksum cksum a = cksum * k + fromIntegral (fromEnum a)
2101+ deltaCksum cksum old new =
2102+ addCksum cksum new - coeff * fromIntegral (fromEnum old)
2104+ -- XXX shall we use a random starting hash or 1 instead of 0?
2105+ patHash = A.foldl' addCksum 0 patArr
2107+ skip = return . Skip
2088 {-# INLINE_LATE stepOuter #-}
2109 {-# INLINE_LATE stepOuter #-}
2089− stepOuter _ GO_START1 =
2110+ stepOuter _ SplitOnSeqInit =
2090 if patLen == 0
2111 if patLen == 0
2091− then return $ Skip $ GO_EMPTY_PAT1 state
2112+ then return $ Skip $ SplitOnSeqEmpty state
2092 else if patLen == 1
2113 else if patLen == 1
2094− r <- liftIO $ (A.unsafeIndexIO patArr 0)
2115+ let !pat = A.unsafeIndex patArr 0
2095− return $ Skip $ GO_SINGLE_PAT state r
2116+ return $ Skip $ SplitOnSeqSingleInit state pat
2096 else if sizeOf (undefined :: a) * patLen
2117 else if sizeOf (undefined :: a) * patLen
2097− <= sizeOf (undefined :: Word)
2118+ <= sizeOf (undefined :: Word)
2098− then return $ Skip $ GO_SHORT_PAT state
2119+ then return $ Skip $ SplitOnSeqWordInit state
2100− (rb, rhead) <- liftIO $ RB.new patLen
2121+ (rb, rhead) <- liftIO $ RB.new patLen
2101− return $ Skip $ GO_KARP_RABIN state rb rhead
2122+ skip $ SplitOnSeqKRInit 0 state rb rhead
2103− stepOuter gst (GO_SINGLE_PAT stt pat) = do
2124+ stepOuter _ (SplitOnSeqYield x next) = return $ Yield x next
2104− -- This first part is the only difference between splitOn and
2125+
2105− -- splitSuffixOn.
2126+ ---------------------------
2106− -- If the last element is a separator do not issue a blank segment.
2127+ -- Empty pattern
2128+ ---------------------------
2130+ stepOuter gst (SplitOnSeqEmpty st) = do
2107− res <- step (adaptState gst) stt
2131+ res <- step (adaptState gst) st
2108 case res of
2132 case res of
2109 Yield x s -> do
2133 Yield x s -> do
2110 acc <- initial
2134 acc <- initial
2135+ acc1 <- fstep acc x
2137+ skip $ SplitOnSeqYield r (SplitOnSeqEmpty s)
2138+ Skip s -> return $ Skip (SplitOnSeqEmpty s)
2139+ Stop -> return Stop
2145+ stepOuter _ SplitOnSeqDone = return Stop
2151+ stepOuter gst (SplitOnSeqSingleInit st pat) = do
2152+ res <- step (adaptState gst) st
2111 if pat == x
2156 if pat == x
2113− acc' <- if withSep then fstep acc x else return acc
2158+ if withSep
2114− done acc' >>= \r -> return $ Yield r (GO_SINGLE_PAT s pat)
2159+ then do
2115− else fstep acc x >>= go SPEC s
2160+ fs1 <- fstep fs x
2162+ let next = SplitOnSeqSingleInit s pat
2163+ skip $ SplitOnSeqYield r next
2166+ let next = SplitOnSeqSingleInit s pat
2167+ skip $ SplitOnSeqYield r next
2170+ skip $ SplitOnSeqSingle fs1 s pat
2116− Skip s -> return $ Skip $ (GO_SINGLE_PAT s pat)
2171+ Skip s -> return $ Skip $ (SplitOnSeqSingleInit s pat)
2117− Stop -> return Stop
2172+ Stop -> return Stop
2121− -- This is identical for splitOn and splitSuffixOn
2174+ stepOuter gst (SplitOnSeqSingle fs st pat) = do
2123− res <- step (adaptState gst) st
2175+ res <- step (adaptState gst) st
2124− case res of
2176+ case res of
2125− Yield x s -> do
2177+ Yield x s -> do
2126− if pat == x
2178+ if pat == x
2128− acc' <- if withSep then fstep acc x else return acc
2182+ fs1 <- fstep fs x
2184+ let next = SplitOnSeqSingleInit s pat
2185+ skip $ SplitOnSeqYield r next
2129− r <- done acc'
2187+ r <- done fs
2130− return $ Yield r (GO_SINGLE_PAT s pat)
2188+ let next = SplitOnSeqSingleInit s pat
2131− else fstep acc x >>= go SPEC s
2189+ skip $ SplitOnSeqYield r next
2132− Skip s -> go SPEC s acc
2190+ else do
2133− Stop -> done acc >>= \r -> return $ Yield r GO_DONE1
2191+ fs1 <- fstep fs x
2192+ return $ Skip $ (SplitOnSeqSingle fs1 s pat)
2193+ Skip s -> return $ Skip $ SplitOnSeqSingle fs s pat
2196+ return $ Skip $ SplitOnSeqYield r SplitOnSeqDone
2135− stepOuter gst (GO_SHORT_PAT stt) = do
2198+ ---------------------------
2199+ -- Short Pattern - Shift Or
2200+ ---------------------------
2137− -- Call "initial" only if the stream yields an element, otherwise we
2202+ stepOuter _ (SplitOnSeqWordDone 0 fs _) = do
2138− -- may call "initial" but never yield anything. initial may produce a
2203+ r <- done fs
2139− -- side effect, therefore we will end up doing and discard a side
2204+ skip $ SplitOnSeqYield r SplitOnSeqDone
2140− -- effect.
2205+ stepOuter _ (SplitOnSeqWordDone n fs wrd) = do
2206+ let old = elemMask .&. (wrd `shiftR` (elemBits * (n - 1)))
2207+ fs1 <- fstep fs (toEnum $ fromIntegral old)
2208+ skip $ SplitOnSeqWordDone (n - 1) fs1 wrd
2142− let idx = 0
2210+ stepOuter gst (SplitOnSeqWordInit st0) = do
2144− res <- step (adaptState gst) stt
2211+ res <- step (adaptState gst) st0
2145 case res of
2212 case res of
2146 Yield x s -> do
2213 Yield x s -> do
2147− acc <- initial
2214+ fs <- initial
2148− let wrd' = addToWord wrd x
2215+ let wrd = addToWord 0 x
2149− acc' <- if withSep then fstep acc x else return acc
2216+ if withSep
2152− if wrd' .&. mask == patWord
2218+ fs1 <- fstep fs x
2153− then done acc' >>= \r -> return $ Yield r (GO_SHORT_PAT s)
2154− else go0 SPEC (idx + 1) wrd' s acc'
2219+ go SPEC 1 wrd s fs1
2155− else go0 SPEC (idx + 1) wrd' s acc'
2220+ else go SPEC 1 wrd s fs
2156− Skip s -> return $ Skip (GO_SHORT_PAT s)
2221+ Skip s -> return $ Skip (SplitOnSeqWordInit s)
2157 Stop -> return Stop
2222 Stop -> return Stop
2161− mask :: Word
2226+ {-# INLINE go #-}
2162− mask = (1 `shiftL` (elemBits * patLen)) - 1
2164− addToWord wrd a = (wrd `shiftL` elemBits) .|. fromIntegral (fromEnum a)
2167− patWord = mask .&. A.foldl' addToWord 0 patArr
2169− go0 !_ !idx wrd st !acc = do
2227+ go !_ !idx !wrd !st !fs = do
2170 res <- step (adaptState gst) st
2228 res <- step (adaptState gst) st
2171 case res of
2229 case res of
2172 Yield x s -> do
2230 Yield x s -> do
2173− let wrd' = addToWord wrd x
2231+ let wrd1 = addToWord wrd x
2174− acc' <- if withSep then fstep acc x else return acc
2232+ if withSep
2177− if wrd' .&. mask == patWord
2234+ fs1 <- fstep fs x
2237+ if wrd1 .&. wordMask == wordPat
2179− r <- done acc'
2239+ r <- done fs
2180− return $ Yield r (GO_SHORT_PAT s)
2240+ let next = SplitOnSeqWordInit s
2181− else go1 SPEC wrd' s acc'
2241+ skip $ SplitOnSeqYield r next
2182− else go0 SPEC (idx + 1) wrd' s acc'
2242+ else skip $ SplitOnSeqWordLoop wrd1 s fs1
2183− Skip s -> go0 SPEC idx wrd s acc
2243+ else go SPEC (idx + 1) wrd1 s fs1
2185− if (idx == maxIndex) && (wrd .&. mask == patWord)
2188− acc' <- if idx /= 0 && not withSep
2245+ if idx == maxIndex
2189− then go2 wrd idx acc
2246+ then do
2190− else return acc
2247+ if wrd1 .&. wordMask == wordPat
2191− done acc' >>= \r -> return $ Yield r GO_DONE1
2248+ then do
2250+ let next = SplitOnSeqWordInit s
2251+ skip $ SplitOnSeqYield r next
2252+ else skip $ SplitOnSeqWordLoop wrd1 s fs
2253+ else go SPEC (idx + 1) wrd1 s fs
2254+ Skip s -> go SPEC idx wrd s fs
2255+ Stop -> skip $ SplitOnSeqWordDone idx fs wrd
2257+ stepOuter gst (SplitOnSeqWordLoop wrd0 st0 fs0) =
2258+ go SPEC wrd0 st0 fs0
2193− {-# INLINE go1 #-}
2262+ {-# INLINE go #-}
2194− go1 !_ wrd st !acc = do
2263+ go !_ !wrd !st !fs = do
2195 res <- step (adaptState gst) st
2264 res <- step (adaptState gst) st
2196 case res of
2265 case res of
2197 Yield x s -> do
2266 Yield x s -> do
2198− let wrd' = addToWord wrd x
2267+ let wrd1 = addToWord wrd x
2268+ old = (wordMask .&. wrd)
2199− old = (mask .&. wrd) `shiftR` (elemBits * (patLen - 1))
2269+ `shiftR` (elemBits * (patLen - 1))
2200− acc' <- if withSep
2270+ if withSep
2201− then fstep acc x
2272+ fs1 <- fstep fs x
2273+ if wrd1 .&. wordMask == wordPat
2276+ let next = SplitOnSeqWordInit s
2277+ skip $ SplitOnSeqYield r next
2278+ else go SPEC wrd1 s fs1
2202− else fstep acc (toEnum $ fromIntegral old)
2280+ fs1 <- fstep fs (toEnum $ fromIntegral old)
2203− if wrd' .&. mask == patWord
2281+ if wrd1 .&. wordMask == wordPat
2204− then done acc' >>= \r -> return $ Yield r (GO_SHORT_PAT s)
2282+ then do
2284+ let next = SplitOnSeqWordInit s
2285+ skip $ SplitOnSeqYield r next
2205− else go1 SPEC wrd' s acc'
2286+ else go SPEC wrd1 s fs1
2206− Skip s -> go1 SPEC wrd s acc
2287+ Skip s -> go SPEC wrd s fs
2208− -- If the last sequence is a separator do not issue a blank
2289+ if wrd .&. wordMask == wordPat
2210− if wrd .&. mask == patWord
2211 then return Stop
2290 then return Stop
2213− acc' <- if withSep
2292+ if withSep
2214− then return acc
2293+ then do
2215− else go2 wrd patLen acc
2294+ r <- done fs
2216− done acc' >>= \r -> return $ Yield r GO_DONE1
2295+ skip $ SplitOnSeqYield r SplitOnSeqDone
2217−
2296+ else skip $ SplitOnSeqWordDone patLen fs wrd
2218− go2 !wrd !n !acc | n > 0 = do
2297+
2219− let old = (mask .&. wrd) `shiftR` (elemBits * (n - 1))
2298+ -------------------------------
2220− fstep acc (toEnum $ fromIntegral old) >>= go2 wrd (n - 1)
2299+ -- General Pattern - Karp Rabin
2221− go2 _ _ acc = return acc
2300+ -------------------------------
2223− stepOuter gst (GO_KARP_RABIN stt rb rhead) = do
2302+ stepOuter gst (SplitOnSeqKRInit idx0 st0 rb rh0) = do
2225− res <- step (adaptState gst) stt
2303+ res <- step (adaptState gst) st0
2226 case res of
2304 case res of
2227 Yield x s -> do
2305 Yield x s -> do
2229− acc' <- if withSep then fstep acc x else return acc
2230− rh' <- liftIO (RB.unsafeInsert rb rhead x)
2306+ rh1 <- liftIO $ RB.unsafeInsert rb rh0 x
2231− if idx == maxIndex
2307+ fs <- initial
2233− let fold = RB.unsafeFoldRing (RB.ringBound rb)
2310+ fs1 <- fstep fs x
2234− let !ringHash = fold addCksum 0 rb
2311+ go SPEC 1 rh1 s fs1
2235− if ringHash == patHash
2236− then go2 SPEC ringHash rh' s acc'
2237− else go0 SPEC (idx + 1) rh' s acc'
2238− else go0 SPEC (idx + 1) rh' s acc'
2312+ else go SPEC 1 rh1 s fs
2239− Skip s -> return $ Skip (GO_KARP_RABIN s rb rhead)
2313+ Skip s -> skip $ SplitOnSeqKRInit idx0 s rb rh0
2240 Stop -> return Stop
2314 Stop -> return Stop
2244− k = 2891336453 :: Word32
2246− addCksum cksum a = cksum * k + fromIntegral (fromEnum a)
2247− deltaCksum cksum old new =
2248− addCksum cksum new - coeff * fromIntegral (fromEnum old)
2250− -- XXX shall we use a random starting hash or 1 instead of 0?
2251− patHash = A.foldl' addCksum 0 patArr
2254− go0 !_ !idx !rh st !acc = do
2318+ go !_ !idx !rh st !fs = do
2255 res <- step (adaptState gst) st
2319 res <- step (adaptState gst) st
2256 case res of
2320 case res of
2257 Yield x s -> do
2321 Yield x s -> do
2258− acc' <- if withSep then fstep acc x else return acc
2259− rh' <- liftIO (RB.unsafeInsert rb rh x)
2322+ rh1 <- liftIO (RB.unsafeInsert rb rh x)
2260− if idx == maxIndex
2323+ if withSep
2262− let fold = RB.unsafeFoldRing (RB.ringBound rb)
2328+ let fold = RB.unsafeFoldRing (RB.ringBound rb)
2263− let !ringHash = fold addCksum 0 rb
2329+ let !ringHash = fold addCksum 0 rb
2264− if ringHash == patHash
2330+ if ringHash == patHash
2265− then go2 SPEC ringHash rh' s acc'
2331+ then skip $ SplitOnSeqKRCheck fs1 s rb rh1
2266− else go1 SPEC ringHash rh' s acc'
2332+ else skip $ SplitOnSeqKRLoop fs1 s rb rh1 ringHash
2333+ else go SPEC (idx + 1) rh1 s fs1
2337+ let fold = RB.unsafeFoldRing (RB.ringBound rb)
2338+ let !ringHash = fold addCksum 0 rb
2339+ if ringHash == patHash
2340+ then skip $ SplitOnSeqKRCheck fs s rb rh1
2341+ else skip $ SplitOnSeqKRLoop fs s rb rh1 ringHash
2267− else go0 SPEC (idx + 1) rh' s acc'
2342+ else go SPEC (idx + 1) rh1 s fs
2268− Skip s -> go0 SPEC idx rh s acc
2343+ Skip s -> go SPEC idx rh s fs
2269 Stop -> do
2344 Stop -> do
2270 -- do not issue a blank segment when we end at pattern
2345 -- do not issue a blank segment when we end at pattern
2271 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2346 if (idx == maxIndex) && RB.unsafeEqArray rb rh patArr
2272 then return Stop
2347 then return Stop
2274− !acc' <- if idx /= 0 && not withSep
2349+ if withSep
2275− then RB.unsafeFoldRingM rh fstep acc rb
2350+ then do
2276− else return acc
2351+ r <- done fs
2277− done acc' >>= \r -> return $ Yield r GO_DONE1
2352+ skip $ SplitOnSeqYield r SplitOnSeqDone
2278−
2353+ else skip $ SplitOnSeqKRDone idx fs rb (RB.startOf rb)
2279− -- XXX Theoretically this code can do 4 times faster if GHC generates
2354+
2280− -- optimal code. If we use just "(cksum' == patHash)" condition it goes
2355+ -- XXX The recursive "go" is more efficient than the state based recursion
2281− -- 4x faster, as soon as we add the "RB.unsafeEqArray rb v" condition
2356+ -- code commented out below. Perhaps its more efficient because of
2282− -- the generated code changes drastically and becomes 4x slower. Need
2357+ -- factoring out "rb" outside the loop.
2283− -- to investigate what is going on with GHC.
2358+ --
2284− {-# INLINE go1 #-}
2359+ stepOuter gst (SplitOnSeqKRLoop fs0 st0 rb rh0 cksum0) =
2285− go1 !_ !cksum !rh st !acc = do
2360+ go SPEC fs0 st0 rh0 cksum0
2364+ go !_ !fs !st !rh !cksum = do
2286 res <- step (adaptState gst) st
2365 res <- step (adaptState gst) st
2287 case res of
2366 case res of
2288 Yield x s -> do
2367 Yield x s -> do
2289 old <- liftIO $ peek rh
2368 old <- liftIO $ peek rh
2369+ rh1 <- liftIO (RB.unsafeInsert rb rh x)
2290− let cksum' = deltaCksum cksum old x
2370+ let cksum1 = deltaCksum cksum old x
2291− acc' <- if withSep
2371+ if withSep
2295− if (cksum' == patHash)
2297− rh' <- liftIO (RB.unsafeInsert rb rh x)
2373+ fs1 <- fstep fs x
2298− go2 SPEC cksum' rh' s acc'
2374+ if (cksum1 == patHash)
2375+ then skip $ SplitOnSeqKRCheck fs1 s rb rh1
2376+ else go SPEC fs1 s rh1 cksum1
2300− rh' <- liftIO (RB.unsafeInsert rb rh x)
2378+ fs1 <- fstep fs old
2301− go1 SPEC cksum' rh' s acc'
2379+ if (cksum1 == patHash)
2380+ then skip $ SplitOnSeqKRCheck fs1 s rb rh1
2381+ else go SPEC fs1 s rh1 cksum1
2302− Skip s -> go1 SPEC cksum rh s acc
2382+ Skip s -> go SPEC fs s rh cksum
2303− Stop -> do
2383+ Stop ->
2304 if RB.unsafeEqArray rb rh patArr
2384 if RB.unsafeEqArray rb rh patArr
2305 then return Stop
2385 then return Stop
2307− acc' <- if withSep
2387+ if withSep
2308− then return acc
2388+ then do
2309− else RB.unsafeFoldRingFullM rh fstep acc rb
2389+ r <- done fs
2310− done acc' >>= \r -> return $ Yield r GO_DONE1
2390+ skip $ SplitOnSeqYield r SplitOnSeqDone
2311−
2391+ else skip $ SplitOnSeqKRDone patLen fs rb rh
2312− go2 !_ !cksum' !rh' s !acc' = do
2392+
2393+ stepOuter _ (SplitOnSeqKRCheck fs st rb rh) = do
2313− if RB.unsafeEqArray rb rh' patArr
2394+ if RB.unsafeEqArray rb rh patArr
2314− then do
2395+ then do
2315− r <- done acc'
2396+ r <- done fs
2316− return $ Yield r (GO_KARP_RABIN s rb rhead)
2397+ let next = SplitOnSeqKRInit 0 st rb (RB.startOf rb)
2317− else go1 SPEC cksum' rh' s acc'
2398+ skip $ SplitOnSeqYield r next
2318−
2399+ else skip $ SplitOnSeqKRLoop fs st rb rh patHash
2319− stepOuter gst (GO_EMPTY_PAT1 st) = do
2320− res <- step (adaptState gst) st
2324− acc' <- fstep acc x
2325− done acc' >>= \r -> return $ Yield r (GO_EMPTY_PAT1 s)
2326− Skip s -> return $ Skip (GO_EMPTY_PAT1 s)
2327− Stop -> return Stop
2329− stepOuter _ GO_DONE1 = return Stop
2401+ stepOuter _ (SplitOnSeqKRDone 0 fs _ _) = do
2403+ skip $ SplitOnSeqYield r SplitOnSeqDone
2404+ stepOuter _ (SplitOnSeqKRDone n fs rb rh) = do
2405+ old <- liftIO $ peek rh
2406+ let rh1 = RB.advance rb rh
2407+ fs1 <- fstep fs old
2408+ skip $ SplitOnSeqKRDone (n - 1) fs1 rb rh1
2331data SplitState s arr
2410data SplitState s arr
2332 = SplitInitial s
2411 = SplitInitial s