@@ -10,7 +10,7 @@
11module Streamly.Internal.Data.Parser.Chunked
11module Streamly.Internal.Data.Parser.Chunked
13− ParserChunked (..)
13+ ParserChunked (..) -- XXX rename to ChunkParser
14 , fromParserD
14 , fromParserD
15 , parseBreak
15 , parseBreak
16 , K.fromPure
16 , K.fromPure
@@ -76,11 +76,10 @@ backTrack = go
77-- | A continuation to extract the result when a CPS parser is done.
77-- | A continuation to extract the result when a CPS parser is done.
78{-# INLINE parserDone #-}
78{-# INLINE parserDone #-}
79−parserDone :: Monad m => (Int, Int) -> K.Parse b -> m (K.Step m a b)
79+parserDone :: Monad m =>
80+ K.ParseResult b -> Int -> Maybe (Array a) -> m (K.Step a m b)
80−parserDone (0,_) (K.Success n b) = return $ K.Done n b
81+parserDone (K.Success n b) _ _ = return $ K.Done n b
81−parserDone st (K.Success _ _) =
82− error $ "Bug: fromParserK: inside alternative: " ++ show st
83−parserDone _ (K.Failure e) = return $ K.Error e
82+parserDone (K.Failure n e) _ _ = return $ K.Error n e
85-- | Run a 'Parser' over a stream and return rest of the Stream.
84-- | Run a 'Parser' over a stream and return rest of the Stream.
86{-# INLINE_NORMAL parseBreak #-}
85{-# INLINE_NORMAL parseBreak #-}
@@ -90,47 +89,11 @@ parseBreak
90 -> Stream m (Array a)
89 -> Stream m (Array a)
91 -> m (b, Stream m (Array a))
90 -> m (b, Stream m (Array a))
92parseBreak parser input = do
91parseBreak parser input = do
93− pRes <- K.runParser parser 0 (0,0) parserDone
92+ let parserk = \arr -> K.runParser parser 0 0 arr parserDone
95− K.Done n b -> assert (n == 0) (return (b, input))
96− K.Error e -> throwM (D.ParseError e)
97− K.Partial n parserk ->
98− assert (n == 0) (go [] parserk (Stream.toStreamK input))
93+ in go [] parserk (Stream.toStreamK input)
99− K.Continue n parserk ->
100− assert (n == 0) (go [] parserk (Stream.toStreamK input))
104− -- This is a simplified yieldk
105− extractYieldK backBuf parserk arr stream = do
106− pRes <- parserk (Just arr)
108− K.Partial 0 cont1 ->
109− goExtract [] cont1 stream
110− K.Partial n cont1 -> do
111− assertM(n <= sum (map Array.length (arr:backBuf)))
112− goExtract [] cont1 (fst $ backTrack n (arr:backBuf) stream)
113− K.Continue 0 cont1 ->
114− go (arr:backBuf) cont1 stream
115− K.Continue n cont1 -> do
116− assertM(n <= sum (map Array.length (arr:backBuf)))
117− let (s1, backBuf1) = backTrack n (arr:backBuf) stream
118− in go backBuf1 cont1 s1
120− return (b, Stream.fromStreamK stream)
122− assertM(n <= sum (map Array.length (arr:backBuf)))
123− let (s1, _) = backTrack n (arr:backBuf) stream
124− in return (b, Stream.fromStreamK s1)
125− K.Error err -> throwM $ D.ParseError err
127− goExtract backBuf parserk stream = do
128− let stop = goStop backBuf parserk
129− single a = extractYieldK backBuf parserk a StreamK.nil
130− in StreamK.foldStream
131− defState (extractYieldK backBuf parserk) single stop stream
133− -- This is a simplified goExtract
134 {-# INLINE goStop #-}
97 {-# INLINE goStop #-}
135 goStop backBuf parserk = do
98 goStop backBuf parserk = do
136 pRes <- parserk Nothing
99 pRes <- parserk Nothing
@@ -138,49 +101,71 @@ parseBreak parser input = do
138 -- If we stop in an alternative, it will try calling the next
101 -- If we stop in an alternative, it will try calling the next
139 -- parser, the next parser may call initial returning Partial and
102 -- parser, the next parser may call initial returning Partial and
140 -- then immediately we have to call extract on it.
103 -- then immediately we have to call extract on it.
141− K.Partial 0 cont1 -> do
104+ K.Partial 0 cont1 ->
142− goExtract [] cont1 StreamK.nil
105+ go [] cont1 StreamK.nil
143 K.Partial n cont1 -> do
106 K.Partial n cont1 -> do
144− -- error $ "Bug: parseBreak: Partial in extract, n = " ++ show n
107+ let n1 = negate n
145− assertM(n <= sum (map Array.length backBuf))
108+ assertM(n1 >= 0 && n1 <= sum (map Array.length backBuf))
146− let (s1, backBuf1) = backTrack n backBuf StreamK.nil
109+ let (s1, backBuf1) = backTrack n1 backBuf StreamK.nil
147− in goExtract backBuf1 cont1 s1
110+ in go backBuf1 cont1 s1
148− K.Continue 0 cont1 -> do
111+ K.Continue 0 cont1 ->
149− -- error "parseBreak: extract, Continue 0 creates infinite loop"
150 go backBuf cont1 StreamK.nil
112 go backBuf cont1 StreamK.nil
151 K.Continue n cont1 -> do
113 K.Continue n cont1 -> do
152− assertM(n <= sum (map Array.length backBuf))
115+ assertM(n1 >= 0 && n1 <= sum (map Array.length backBuf))
153− let (s1, backBuf1) = backTrack n backBuf StreamK.nil
116+ let (s1, backBuf1) = backTrack n1 backBuf StreamK.nil
154− in goExtract backBuf1 cont1 s1
117+ in go backBuf1 cont1 s1
155− K.Done 0 b -> return (b, Stream.nil)
119+ return (b, Stream.nil)
156 K.Done n b -> do
120 K.Done n b -> do
157− assertM(n <= sum (map Array.length backBuf))
122+ assertM(n1 >= 0 && n1 <= sum (map Array.length backBuf))
158− let (s1, _) = backTrack n backBuf StreamK.nil
123+ let (s1, _) = backTrack n1 backBuf StreamK.nil
159 in return (b, Stream.fromStreamK s1)
124 in return (b, Stream.fromStreamK s1)
160− K.Error err -> throwM $ D.ParseError err
125+ K.Error _ err -> throwM $ D.ParseError err
162− -- SPECIALIZE this on backBuf?
127+ seekErr n len =
128+ error $ "parseBreak: Partial: forward seek not implemented n = "
129+ ++ show n ++ " len = " ++ show len
163− yieldk backBuf !parserk arr stream = do
131+ yieldk backBuf parserk arr stream = do
164 pRes <- parserk (Just arr)
132 pRes <- parserk (Just arr)
133+ let len = Array.length arr
165 case pRes of
134 case pRes of
166− K.Partial 0 cont1 ->
135+ K.Partial n cont1 ->
136+ case compare n len of
167− go [] cont1 stream
137+ EQ -> go [] cont1 stream
168− K.Partial n cont1 -> do
138+ LT -> do
140+ then yieldk [] cont1 arr stream
169− assertM(n <= sum (map Array.length (arr:backBuf)))
143+ bufLen = sum (map Array.length backBuf)
170− go [] cont1 (fst $ backTrack n (arr:backBuf) stream)
144+ s = StreamK.cons arr stream
145+ assertM(n1 >= 0 && n1 <= bufLen)
146+ let (s1, _) = backTrack n1 backBuf s
171− K.Continue 0 cont1 ->
149+ K.Continue n cont1 ->
150+ case compare n len of
172− go (arr:backBuf) cont1 stream
151+ EQ -> go (arr:backBuf) cont1 stream
173− K.Continue n cont1 -> do
152+ LT -> do
154+ then yieldk backBuf cont1 arr stream
174− assertM(n <= sum (map Array.length (arr:backBuf)))
157+ bufLen = sum (map Array.length backBuf)
158+ s = StreamK.cons arr stream
159+ assertM(n1 >= 0 && n1 <= bufLen)
175− let (s1, backBuf1) = backTrack n (arr:backBuf) stream
160+ let (s1, backBuf1) = backTrack n1 backBuf s
176− in go backBuf1 cont1 s1
161+ go backBuf1 cont1 s1
177− K.Done 0 b ->
162+ GT -> seekErr n len
178− return (b, Stream.fromStreamK stream)
179 K.Done n b -> do
163 K.Done n b -> do
180− assertM(n <= sum (map Array.length (arr:backBuf)))
165+ assertM(n1 <= sum (map Array.length (arr:backBuf)))
181− let (s1, _) = backTrack n (arr:backBuf) stream
166+ let (s1, _) = backTrack n1 (arr:backBuf) stream
182 in return (b, Stream.fromStreamK s1)
167 in return (b, Stream.fromStreamK s1)
183− K.Error err -> throwM $ D.ParseError err
168+ K.Error _ err -> throwM $ D.ParseError err
185 go backBuf parserk stream = do
170 go backBuf parserk stream = do
186 let stop = goStop backBuf parserk
171 let stop = goStop backBuf parserk
@@ -188,6 +173,12 @@ parseBreak parser input = do
188 in StreamK.foldStream
173 in StreamK.foldStream
189 defState (yieldk backBuf parserk) single stop stream
174 defState (yieldk backBuf parserk) single stop stream
176+data ChunkResult s b =
178+ | ChunkPartial !Int !s
179+ | ChunkContinue !Int !s
180+ | ChunkError !Int String
191-- This is very similar to fromParserD in the Array/Unboxed/Fold module.
182-- This is very similar to fromParserD in the Array/Unboxed/Fold module.
192{-# INLINE parseChunk #-}
183{-# INLINE parseChunk #-}
193parseChunk
184parseChunk
@@ -195,122 +186,126 @@ parseChunk
195 => (s -> a -> m (Step s b))
186 => (s -> a -> m (Step s b))
197 -> Array a
188 -> Array a
198− -> m (Step s b)
189+ -> Int
190+ -> m (ChunkResult s b)
199−parseChunk pstep state (Array contents start end) = do
191+parseChunk pstep state (Array contents start end) offset = do
200− go SPEC start state
193+ then go SPEC (start + offset * SIZE_OF(a)) state
194+ else return $ ChunkContinue offset state
204− {-# INLINE partial #-}
198+ {-# INLINE onBack #-}
205− partial arrRem cur next elemSize st n fs1 = do
199+ onBack offset1 elemSize constr pst = do
206− let next1 = next - (n * elemSize)
200+ let pos = offset1 - start
207− if next1 >= start && cur < end
201+ in if pos >= 0
208− then go SPEC next1 fs1
202+ then go SPEC offset1 pst
209− else return $ st (arrRem + n) fs1
203+ else return $ constr (pos `div` elemSize) pst
205+ -- Note: div may be expensive but the alternative is to maintain an element
206+ -- offset in addition to a byte offset or just the element offset and use
207+ -- multiplication to get the byte offset every time, both these options
208+ -- turned out to be more expensive than using div.
211− go !_ !cur !pst | cur >= end = return $ Continue 0 pst
209+ go !_ !cur !pst | cur >= end =
210+ return $ ChunkContinue ((end - start) `div` SIZE_OF(a)) pst
212 go !_ !cur !pst = do
211 go !_ !cur !pst = do
213 x <- liftIO $ peekWith contents cur
212 x <- liftIO $ peekWith contents cur
214 pRes <- pstep pst x
213 pRes <- pstep pst x
215 let elemSize = SIZE_OF(a)
214 let elemSize = SIZE_OF(a)
216 next = INDEX_NEXT(cur,a)
215 next = INDEX_NEXT(cur,a)
216+ back n = next - n * elemSize
217+ curOff = (cur - start) `div` elemSize
217− arrRem = (end - next) `div` elemSize
218+ nextOff = (next - start) `div` elemSize
218 case pRes of
219 case pRes of
219− Done n b -> do
220+ Done 0 b ->
220− return $ Done (arrRem + n) b
221+ return $ ChunkDone nextOff b
223+ return $ ChunkDone curOff b
225+ return $ ChunkDone ((back n - start) `div` elemSize) b
221 Partial n pst1 ->
230 Partial n pst1 ->
222− partial arrRem cur next elemSize Partial n pst1
231+ onBack (back n) elemSize ChunkPartial pst1
223− Continue n pst1 -> do
232+ Continue 0 pst1 ->
224− partial arrRem cur next elemSize Continue n pst1
233+ go SPEC next pst1
237+ onBack (back n) elemSize ChunkContinue pst1
225− Error err -> return $ Error err
238+ Error err ->
239+ return $ ChunkError curOff err
227−{-# INLINE_NORMAL parseDToK #-}
241+{-# INLINE parseDToK #-}
229− :: (MonadIO m, Unbox a)
243+ :: forall m a s b r. (MonadIO m, Unbox a)
230 => (s -> a -> m (Step s b))
244 => (s -> a -> m (Step s b))
231 -> m (Initial s b)
245 -> m (Initial s b)
232 -> (s -> m (Step s b))
246 -> (s -> m (Step s b))
234− -> (Int, Int)
248+ -> Int
235− -> ((Int, Int) -> K.Parse b -> m (K.Step m a r))
249+ -> Maybe (Array a)
250+ -> (K.ParseResult b -> Int -> Maybe (Array a) -> m (K.Step a m r))
236− -> m (K.Step m a r)
251+ -> m (K.Step a m r)
237−-- Non 'Alternative' case.
238−parseDToK pstep initial extract leftover (0, _) cont = do
252+parseDToK pstep initial extract offset usedCount input cont = do
239 res <- initial
253 res <- initial
240 case res of
254 case res of
241− IPartial r -> return $ K.Partial leftover (parseCont (return r))
255+ IPartial pst -> do
257+ Just arr -> parseContJust usedCount offset pst arr
258+ Nothing -> parseContNothing usedCount pst
242− IDone b -> cont state (K.Success 0 b)
259+ IDone b -> cont (K.Success offset b) usedCount input
243− IError err -> cont state (K.Failure err)
260+ IError err -> cont (K.Failure offset err) usedCount input
247− -- The continuation is called with (0,0) state i.e. Alternative level
264+ -- XXX We can maintain an absolute position instead of relative that will
248− -- is 0 and the used count is 0. Alternative level is 0 because the level
265+ -- help in reporting of error location in the stream.
249− -- passed in the argument above is 0, the "used" count is 0 because it is
266+ {-# NOINLINE parseContJust #-}
250− -- not useful when Alternative level is 0. We should probably use a Maybe
267+ parseContJust count off pst arr = do
251− -- type for the state but that might impact performance, need to measure.
254− -- We could pass a stream or array here and drive the ParserD with fusion.
255− parseCont pst (Just arr) = do
257− pRes <- parseChunk pstep r arr
268+ pRes <- parseChunk pstep pst arr off
269+ -- The "n" here is stream position index wrt the array start, and not
270+ -- the backtrack count as returned by byte stream parsers.
258 case pRes of
271 case pRes of
259− Done n b -> cont state (K.Success n b)
272+ ChunkDone n b ->
260− Error err -> cont state (K.Failure err)
273+ assert (n <= Array.length arr)
261− Partial n pst1 -> return $ K.Partial n (parseCont (return pst1))
274+ (cont (K.Success n b) (count + n - off) (Just arr))
262− Continue n pst1 -> return $ K.Continue n (parseCont (return pst1))
275+ ChunkPartial n pst1 ->
276+ assert (n < 0 || n >= Array.length arr)
277+ (return $ K.Partial n (parseCont (count + n - off) pst1))
278+ ChunkContinue n pst1 ->
279+ assert (n < 0 || n >= Array.length arr)
280+ (return $ K.Continue n (parseCont (count + n - off) pst1))
282+ cont (K.Failure n err) (count + n - off) (Just arr)
264− parseCont acc Nothing = do
284+ {-# NOINLINE parseContNothing #-}
265− pst <- acc
285+ parseContNothing count pst = do
266 r <- extract pst
286 r <- extract pst
267 case r of
287 case r of
268− Done n b -> cont state (K.Success n b)
288+ -- IMPORTANT: the n here is from the byte stream parser, that means
269− Error err -> cont state (K.Failure err)
289+ -- it is the backtrack element count and not the stream position
270− Partial _ _ -> error "Bug: parseDToK Partial unreachable"
290+ -- index into the current input array.
271− Continue n pst1 -> return $ K.Continue n (parseCont (return pst1))
291+ Done n b ->
273−-- 'Alternative' case. Used count needs to be maintained when inside an
275−parseDToK pstep initial extract leftover (level, count) cont = do
278− IPartial r -> return $ K.Partial leftover (parseCont count (return r))
279− IDone b -> cont (level,count) (K.Success 0 b)
293+ (cont (K.Success (- n) b) (count - n) Nothing)
280− IError err -> cont (level,count) (K.Failure err)
294+ Continue n pst1 ->
282− where
296+ (return $ K.Continue (- n) (parseCont (count - n) pst1))
284− parseCont !cnt pst (Just arr) = do
285− let !cnt1 = cnt + Array.length arr
287− pRes <- parseChunk pstep r arr
291− cont (level, cnt1 - n) (K.Success n b)
292 Error err ->
297 Error err ->
298+ -- XXX It is called only when there is no input arr. So using 0
299+ -- as the position is correct?
293− cont (level, cnt1) (K.Failure err)
300+ cont (K.Failure 0 err) count Nothing
294− Partial n pst1 -> do
296− return $ K.Partial n (parseCont (cnt1 - n) (return pst1))
297− Continue n pst1 -> do
299− return $ K.Continue n (parseCont (cnt1 - n) (return pst1))
300− parseCont cnt acc Nothing = do
303− let s = (level, cnt)
307− cont s (K.Success n b)
308 Partial _ _ -> error "Bug: parseDToK Partial unreachable"
301 Partial _ _ -> error "Bug: parseDToK Partial unreachable"
310− cont s (K.Failure e)
303+ -- XXX Maybe we can use two separate continuations instead of using
311− Continue n pst1 -> do
304+ -- Just/Nothing cases here. That may help in avoiding the parseContJust
312− assertM(n <= cnt)
305+ -- function call.
313− return $ K.Continue n (parseCont (cnt - n) (return pst1))
306+ {-# INLINE parseCont #-}
307+ parseCont cnt pst (Just arr) = parseContJust cnt 0 pst arr
308+ parseCont cnt pst Nothing = parseContNothing cnt pst
315-- | Convert a raw byte 'Parser' to a chunked parser.
310-- | Convert a raw byte 'Parser' to a chunked parser.