on master help sign in
Use chunked parsing by default
4840f43Harendra Kumar
benchmark/Streamly/Benchmark/Data/Parser/ParserK.hs+29−26
@@ -15,7 +15,10 @@ module Main
15 ) where
15 ) where
16
16
17import Control.DeepSeq (NFData(..))
17import Control.DeepSeq (NFData(..))
18+import Control.Monad.IO.Class (MonadIO)
18import Data.Foldable (asum)
19import Data.Foldable (asum)
20+import Streamly.Data.Array (Array, Unbox)
21+import Streamly.Data.Stream.StreamK (StreamK)
19import Streamly.Internal.Data.Parser (ParseError(..))
22import Streamly.Internal.Data.Parser (ParseError(..))
20import Streamly.Internal.Data.Stream.StreamD (Stream)
23import Streamly.Internal.Data.Stream.StreamD (Stream)
21import System.Random (randomRIO)
24import System.Random (randomRIO)
@@ -25,11 +28,11 @@ import Prelude hiding
25import qualified Control.Applicative as AP
28import qualified Control.Applicative as AP
26import qualified Data.Foldable as F
29import qualified Data.Foldable as F
27import qualified Data.Traversable as TR
30import qualified Data.Traversable as TR
28−import qualified Streamly.Data.Parser.ParserK as ParserK
31+import qualified Streamly.Data.Stream as Stream
29−import qualified Streamly.Internal.Data.Fold as FL
32+import qualified Streamly.Data.Fold as FL
30−import qualified Streamly.Internal.Data.Parser.ParserK.Type as PR
33+import qualified Streamly.Data.Parser as PRD
31−import qualified Streamly.Internal.Data.Parser.ParserD as PRD
32−import qualified Streamly.Internal.Data.Stream.StreamD as Stream
34+import qualified Streamly.Data.Parser.ParserK as PR
35+import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
33
36
34import Gauge
37import Gauge
35import Streamly.Benchmark.Common
38import Streamly.Benchmark.Common
@@ -53,48 +56,48 @@ sourceUnfoldrM value n = Stream.unfoldrM step n
53{-# INLINE benchIOSink #-}
56{-# INLINE benchIOSink #-}
54benchIOSink
57benchIOSink
55 :: NFData b
58 :: NFData b
56− => Int -> String -> (Stream IO Int -> IO b) -> Benchmark
59+ => Int -> String -> (StreamK IO (Array Int) -> IO b) -> Benchmark
57benchIOSink value name f =
60benchIOSink value name f =
58− bench name $ nfIO $ randomRIO (1,1) >>= f . sourceUnfoldrM value
61+ bench name $ nfIO $ randomRIO (1,1) >>= f . StreamK.fromStream . Stream.arraysOf 32000 . sourceUnfoldrM value
59
62
60-------------------------------------------------------------------------------
63-------------------------------------------------------------------------------
61-- Parsers
64-- Parsers
62-------------------------------------------------------------------------------
65-------------------------------------------------------------------------------
63
66
64−#define PARSE_OP (Stream.parse . PRD.fromParserK)
67+#define PARSE_OP StreamK.parseKChunks
65
68
66{-# INLINE one #-}
69{-# INLINE one #-}
67−one :: Monad m => Int -> Stream m Int -> m (Either ParseError (Maybe Int))
70+one :: MonadIO m => Int -> StreamK m (Array Int) -> m (Either ParseError (Maybe Int))
68−one value = Stream.parse (ParserK.toParser p)
71+one value = StreamK.parseKChunks p
69
72
70 where
73 where
71
74
72 p = do
75 p = do
73− m <- ParserK.fromFold FL.one
76+ m <- PR.fromFold FL.one
74 case m of
77 case m of
75 Just i -> if i >= value then pure m else p
78 Just i -> if i >= value then pure m else p
76 Nothing -> pure Nothing
79 Nothing -> pure Nothing
77
80
78{-# INLINE satisfy #-}
81{-# INLINE satisfy #-}
79−satisfy :: Monad m => (a -> Bool) -> PR.Parser a m a
82+satisfy :: (MonadIO m, Unbox a) => (a -> Bool) -> PR.Parser a m a
80−satisfy = PRD.toParserK . PRD.satisfy
83+satisfy = PR.fromParser . PRD.satisfy
81
84
82{-# INLINE takeWhile #-}
85{-# INLINE takeWhile #-}
83−takeWhile :: Monad m => (a -> Bool) -> PR.Parser a m ()
86+takeWhile :: (MonadIO m, Unbox a) => (a -> Bool) -> PR.Parser a m ()
84−takeWhile p = PRD.toParserK $ PRD.takeWhile p FL.drain
87+takeWhile p = PR.fromParser $ PRD.takeWhile p FL.drain
85
88
86{-# INLINE takeWhileK #-}
89{-# INLINE takeWhileK #-}
87−takeWhileK :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
90+takeWhileK :: MonadIO m => Int -> StreamK m (Array Int) -> m (Either ParseError ())
88takeWhileK value = PARSE_OP (takeWhile (<= value))
91takeWhileK value = PARSE_OP (takeWhile (<= value))
89
92
90{-# INLINE splitApp #-}
93{-# INLINE splitApp #-}
91−splitApp :: Monad m
94+splitApp :: MonadIO m
92− => Int -> Stream m Int -> m (Either ParseError ((), ()))
95+ => Int -> StreamK m (Array Int) -> m (Either ParseError ((), ()))
93splitApp value =
96splitApp value =
94 PARSE_OP ((,) <$> takeWhile (<= (value `div` 2)) <*> takeWhile (<= value))
97 PARSE_OP ((,) <$> takeWhile (<= (value `div` 2)) <*> takeWhile (<= value))
95
98
96{-# INLINE sequenceA #-}
99{-# INLINE sequenceA #-}
97−sequenceA :: Monad m => Int -> Stream m Int -> m Int
100+sequenceA :: MonadIO m => Int -> StreamK m (Array Int) -> m Int
98sequenceA value xs = do
101sequenceA value xs = do
99 let parser = satisfy (> 0)
102 let parser = satisfy (> 0)
100 list = Prelude.replicate value parser
103 list = Prelude.replicate value parser
@@ -102,14 +105,14 @@ sequenceA value xs = do
102 return $ Prelude.length x
105 return $ Prelude.length x
103
106
104{-# INLINE sequenceA_ #-}
107{-# INLINE sequenceA_ #-}
105−sequenceA_ :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
108+sequenceA_ :: MonadIO m => Int -> StreamK m (Array Int) -> m (Either ParseError ())
106sequenceA_ value xs = do
109sequenceA_ value xs = do
107 let parser = satisfy (> 0)
110 let parser = satisfy (> 0)
108 list = Prelude.replicate value parser
111 list = Prelude.replicate value parser
109 PARSE_OP (F.sequenceA_ list) xs
112 PARSE_OP (F.sequenceA_ list) xs
110
113
111{-# INLINE sequence #-}
114{-# INLINE sequence #-}
112−sequence :: Monad m => Int -> Stream m Int -> m Int
115+sequence :: MonadIO m => Int -> StreamK m (Array Int) -> m Int
113sequence value xs = do
116sequence value xs = do
114 let parser = satisfy (> 0)
117 let parser = satisfy (> 0)
115 list = Prelude.replicate value parser
118 list = Prelude.replicate value parser
@@ -117,26 +120,26 @@ sequence value xs = do
117 return $ Prelude.length x
120 return $ Prelude.length x
118
121
119{-# INLINE sequence_ #-}
122{-# INLINE sequence_ #-}
120−sequence_ :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
123+sequence_ :: MonadIO m => Int -> StreamK m (Array Int) -> m (Either ParseError ())
121sequence_ value =
124sequence_ value =
122 let parser = satisfy (> 0)
125 let parser = satisfy (> 0)
123 list = Prelude.replicate value parser
126 list = Prelude.replicate value parser
124 in PARSE_OP (F.sequence_ list)
127 in PARSE_OP (F.sequence_ list)
125
128
126{-# INLINE manyAlt #-}
129{-# INLINE manyAlt #-}
127−manyAlt :: Monad m => Stream m Int -> m Int
130+manyAlt :: MonadIO m => StreamK m (Array Int) -> m Int
128manyAlt xs = do
131manyAlt xs = do
129 x <- PARSE_OP (AP.many (satisfy (> 0))) xs
132 x <- PARSE_OP (AP.many (satisfy (> 0))) xs
130 return $ Prelude.length x
133 return $ Prelude.length x
131
134
132{-# INLINE someAlt #-}
135{-# INLINE someAlt #-}
133−someAlt :: Monad m => Stream m Int -> m Int
136+someAlt :: MonadIO m => StreamK m (Array Int) -> m Int
134someAlt xs = do
137someAlt xs = do
135 x <- PARSE_OP (AP.some (satisfy (> 0))) xs
138 x <- PARSE_OP (AP.some (satisfy (> 0))) xs
136 return $ Prelude.length x
139 return $ Prelude.length x
137
140
138{-# INLINE choice #-}
141{-# INLINE choice #-}
139−choice :: Monad m => Int -> Stream m Int -> m (Either ParseError Int)
142+choice :: MonadIO m => Int -> StreamK m (Array Int) -> m (Either ParseError Int)
140choice value =
143choice value =
141 PARSE_OP (asum (replicate value (satisfy (< 0)))
144 PARSE_OP (asum (replicate value (satisfy (< 0)))
142 AP.<|> satisfy (> 0))
145 AP.<|> satisfy (> 0))
@@ -159,7 +162,7 @@ o_1_space_serial value =
159 ]
162 ]
160
163
161{-# INLINE sepBy1 #-}
164{-# INLINE sepBy1 #-}
162−sepBy1 :: Monad m => Stream m Int -> m Int
165+sepBy1 :: MonadIO m => StreamK m (Array Int) -> m Int
163sepBy1 xs = do
166sepBy1 xs = do
164 x <- PARSE_OP (parser (satisfy odd) (satisfy even)) xs
167 x <- PARSE_OP (parser (satisfy odd) (satisfy even)) xs
165 return $ Prelude.length x
168 return $ Prelude.length x
core/src/Streamly/Data/Parser/ParserK.hs+6−15
@@ -31,24 +31,15 @@ module Streamly.Data.Parser.ParserK
31
31
32where
32where
33
33
34+import Control.Monad.IO.Class (MonadIO)
34import Streamly.Internal.Data.Fold (Fold)
35import Streamly.Internal.Data.Fold (Fold)
35−import Streamly.Internal.Data.Parser.ParserK.Type
36+import Streamly.Internal.Data.Unboxed (Unbox)
36import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
37import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
37
38
39+import Streamly.Internal.Data.Parser.ParserK.Type
40+
38-- | Convert a 'Fold' to a 'ParserK'.
41-- | Convert a 'Fold' to a 'ParserK'.
39--
42--
40{-# INLINE fromFold #-}
43{-# INLINE fromFold #-}
41−fromFold :: Monad m => Fold m a b -> ParserK a m b
44+fromFold :: (MonadIO m, Unbox a) => Fold m a b -> ParserK a m b
42−fromFold = ParserD.toParserK . ParserD.fromFold
45+fromFold = fromParser . ParserD.fromFold
43−
44−-- | Convert a 'Parser' to a 'ParserK'.
45−--
46−{-# INLINE fromParser #-}
47−fromParser :: Monad m => ParserD.Parser a m b -> ParserK a m b
48−fromParser = ParserD.toParserK
49−
50−-- | Convert a 'ParserK' to a 'Parser'.
51−--
52−{-# INLINE toParser #-}
53−toParser :: Monad m => ParserK a m b -> ParserD.Parser a m b
54−toParser = ParserD.fromParserK
core/src/Streamly/Data/Stream.hs+1−1
@@ -246,7 +246,7 @@ module Streamly.Data.Stream
246
246
247 -- ** Parsing
247 -- ** Parsing
248 , parse
248 , parse
249− , parseBreak
249+ -- , parseBreak
250
250
251 -- -- ** Lazy Right Folds
251 -- -- ** Lazy Right Folds
252 -- Consuming a stream to build a right associated expression, suitable
252 -- Consuming a stream to build a right associated expression, suitable
core/src/Streamly/Data/Stream/StreamK.hs+2−1
@@ -52,7 +52,8 @@ module Streamly.Data.Stream.StreamK
52 -- , foldBreak
52 -- , foldBreak
53
53
54 -- ** Parsing
54 -- ** Parsing
55− , parseBreak
55+ -- , parseBreak
56+ , parseKBreakChunks
56
57
57 -- * Combining Two Streams
58 -- * Combining Two Streams
58 -- ** Appending
59 -- ** Appending
core/src/Streamly/Internal/Data/Parser/Chunked.hs−1
@@ -49,7 +49,6 @@ import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
49import qualified Streamly.Internal.Data.Array as Array
49import qualified Streamly.Internal.Data.Array as Array
50import qualified Streamly.Internal.Data.Parser.Chunked.Type as K
50import qualified Streamly.Internal.Data.Parser.Chunked.Type as K
51import qualified Streamly.Internal.Data.Parser.ParserD as D
51import qualified Streamly.Internal.Data.Parser.ParserD as D
52− hiding (fromParserK, toParserK)
53import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
52import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
54import Streamly.Internal.Data.Parser.ParserD (ParseError(..))
53import Streamly.Internal.Data.Parser.ParserD (ParseError(..))
55
54
core/src/Streamly/Internal/Data/Parser/ParserD.hs−4
@@ -50,10 +50,6 @@ module Streamly.Internal.Data.Parser.ParserD
50 , Step (..)
50 , Step (..)
51 , Initial (..)
51 , Initial (..)
52
52
53− -- * Conversion to/from ParserK
54− , fromParserK
55− , toParserK
56−
57 -- * Downgrade to Fold
53 -- * Downgrade to Fold
58 , toFold
54 , toFold
59
55
core/src/Streamly/Internal/Data/Parser/ParserD/Type.hs−179
@@ -172,10 +172,6 @@ module Streamly.Internal.Data.Parser.ParserD.Type
172 , ParseError (..)
172 , ParseError (..)
173 , rmapM
173 , rmapM
174
174
175− -- * Conversion to/from ParserK
176− , fromParserK
177− , toParserK
178−
179 -- * Constructors
175 -- * Constructors
180
176
181 , fromPure
177 , fromPure
@@ -216,7 +212,6 @@ import Streamly.Internal.Data.Tuple.Strict (Tuple3'(..))
216
212
217import qualified Control.Monad.Fail as Fail
213import qualified Control.Monad.Fail as Fail
218import qualified Streamly.Internal.Data.Fold.Type as FL
214import qualified Streamly.Internal.Data.Fold.Type as FL
219−import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
220
215
221import Prelude hiding (concatMap, filter)
216import Prelude hiding (concatMap, filter)
222--
217--
@@ -449,180 +444,6 @@ instance Functor m => Functor (Parser a m) where
449 fmap2 g = fmap (fmap g)
444 fmap2 g = fmap (fmap g)
450 fmap3 g = fmap2 (fmap g)
445 fmap3 g = fmap2 (fmap g)
451
446
452−-------------------------------------------------------------------------------
453−-- Convert direct style 'Parser' to CPS style 'K.Parser'
454−-------------------------------------------------------------------------------
455−
456−-- XXX Unlike the direct style folds/parsers, the initial action in CPS parsers
457−-- is not performed when the fold is initialized. It is performed when the
458−-- first element is processed by the fold or if no elements are processed then
459−-- at the extraction. We should either make the direct folds like this or make
460−-- the CPS folds behavior also like the direct ones.
461−--
462−-- | Convert a direct style parser ('D.Parser') to a CPS style parser
463−-- ('Parser').
464−--
465−{-# INLINE_NORMAL parseDToK #-}
466−parseDToK
467− :: Monad m
468− => (s -> a -> m (Step s b))
469− -> m (Initial s b)
470− -> (s -> m (Step s b))
471− -> Int
472− -> (Int, Int)
473− -> ((Int, Int) -> K.Parse b -> m (K.Step m a r))
474− -> m (K.Step m a r)
475−
476−-- Non 'Alternative' case.
477−parseDToK pstep initial extract leftover (0, _) cont = do
478− res <- initial
479− case res of
480− IPartial r -> return $ K.Partial leftover (parseCont (return r))
481− IDone b -> cont state (K.Success 0 b)
482− IError err -> cont state (K.Failure err)
483−
484− where
485−
486− -- The continuation is called with (0,0) state i.e. Alternative level
487− -- is 0 and the used count is 0. Alternative level is 0 because the level
488− -- passed in the argument above is 0, the "used" count is 0 because it is
489− -- not useful when Alternative level is 0. We should probably use a Maybe
490− -- type for the state but that might impact performance, need to measure.
491− state = (0,0)
492−
493− parseCont pst (Just x) = do
494− r <- pst
495− pRes <- pstep r x
496− case pRes of
497− Done n b -> cont state (K.Success n b)
498− Error err -> cont state (K.Failure err)
499− Partial n pst1 -> return $ K.Partial n (parseCont (return pst1))
500− Continue n pst1 -> return $ K.Continue n (parseCont (return pst1))
501−
502− parseCont acc Nothing = do
503− pst <- acc
504− r <- extract pst
505− case r of
506− Done n b -> cont state (K.Success n b)
507− Error err -> cont state (K.Failure err)
508− Partial _ _ -> error "Bug: parseDToK Partial unreachable"
509− Continue n pst1 -> return $ K.Continue n (parseCont (return pst1))
510−
511−-- XXX Pass on the stream to parserK and inside parserK drive the parserD
512−-- directly from the stream. That way we can feed full chunks efficiently to
513−-- parserD with fusion. The remaining stream can be passed on to the
514−-- continuation and at the end the leftover stream can be returned.
515−--
516−-- contification of parserD completely breaks fusion. We can avoid that by
517−-- fusing the parserD with the source stream.
518−
519−-- 'Alternative' case. Used count needs to be maintained when inside an
520−-- Alternative.
521−parseDToK pstep initial extract leftover (level, count) cont = do
522− res <- initial
523− case res of
524− IPartial r -> return $ K.Partial leftover (parseCont count (return r))
525− IDone b -> cont (level,count) (K.Success 0 b)
526− IError err -> cont (level,count) (K.Failure err)
527−
528− where
529−
530− parseCont !cnt pst (Just x) = do
531− let !cnt1 = cnt + 1
532− r <- pst
533− pRes <- pstep r x
534− case pRes of
535− Done n b -> do
536− assertM(n <= cnt1)
537− cont (level, cnt1 - n) (K.Success n b)
538− Error err ->
539− cont (level, cnt1) (K.Failure err)
540− Partial n pst1 -> do
541− assertM(n <= cnt1)
542− return $ K.Partial n (parseCont (cnt1 - n) (return pst1))
543− Continue n pst1 -> do
544− assertM(n <= cnt1)
545− return $ K.Continue n (parseCont (cnt1 - n) (return pst1))
546− parseCont cnt acc Nothing = do
547− pst <- acc
548− r <- extract pst
549− let s = (level, cnt)
550− case r of
551− Done n b -> do
552− assertM(n <= cnt)
553− cont s (K.Success n b)
554− Partial _ _ -> error "Bug: parseDToK Partial unreachable"
555− Error e ->
556− cont s (K.Failure e)
557− Continue n pst1 -> do
558− assertM(n <= cnt)
559− return $ K.Continue n (parseCont (cnt - n) (return pst1))
560−
561−-- | Convert a direct style 'Parser' to a CPS style 'K.Parser'.
562−--
563−-- /Pre-release/
564−--
565−{-# INLINE_LATE toParserK #-}
566−toParserK :: Monad m => Parser a m b -> K.Parser a m b
567−toParserK (Parser step initial extract) =
568− K.MkParser $ parseDToK step initial extract
569−
570−-------------------------------------------------------------------------------
571−-- Convert CPS style 'Parser' to direct style 'D.Parser'
572−-------------------------------------------------------------------------------
573−
574−-- | A continuation to extract the result when a CPS parser is done.
575−{-# INLINE parserDone #-}
576−parserDone :: Monad m => (Int, Int) -> K.Parse b -> m (K.Step m a b)
577−parserDone (0,_) (K.Success n b) = return $ K.Done n b
578−parserDone (0,_) (K.Failure e) = return $ K.Error e
579−parserDone st _ =
580− error $ "Bug: fromParserK: parser done inside alternative: " ++ show st
581−
582−-- | Convert a CPS style 'K.Parser' to a direct style 'Parser'.
583−--
584−-- "initial" returns a continuation which can be called one input at a time
585−-- using the "step" function.
586−--
587−-- /Pre-release/
588−--
589−{-# INLINE_LATE fromParserK #-}
590−fromParserK :: Monad m => K.Parser a m b -> Parser a m b
591−fromParserK parser = Parser step initial extract
592−
593− where
594−
595− initial = do
596− r <- K.runParser parser 0 (0,0) parserDone
597− return $ case r of
598− K.Done n b -> assert (n == 0) (IDone b)
599− K.Error e -> IError e
600− K.Partial n cont -> assert (n == 0) (IPartial cont)
601− K.Continue n cont -> assert (n == 0) (IPartial cont)
602−
603− step cont a = do
604− r <- cont (Just a)
605− return $ case r of
606− K.Done n b -> Done n b
607− K.Error e -> Error e
608− K.Partial n cont1 -> Partial n cont1
609− K.Continue n cont1 -> Continue n cont1
610−
611− extract cont = do
612− r <- cont Nothing
613− case r of
614− K.Done n b -> return $ Done n b
615− K.Error e -> return $ Error e
616− K.Partial _ cont1 -> extract cont1
617− K.Continue n cont1 -> return $ Continue n cont1
618−
619−#ifndef DISABLE_FUSION
620−{-# RULES "fromParserK/toParserK fusion" [2]
621− forall s. toParserK (fromParserK s) = s #-}
622−{-# RULES "toParserK/fromParserK fusion" [2]
623− forall s. fromParserK (toParserK s) = s #-}
624−#endif
625−
626------------------------------------------------------------------------------
447------------------------------------------------------------------------------
627-- Mapping on the output
448-- Mapping on the output
628------------------------------------------------------------------------------
449------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Parser/ParserK/Type.hs+291−56
@@ -19,22 +19,36 @@
19module Streamly.Internal.Data.Parser.ParserK.Type
19module Streamly.Internal.Data.Parser.ParserK.Type
20 (
20 (
21 Step (..)
21 Step (..)
22− , Parse (..)
22+ , Input (..)
23− , Parser (..) -- XXX Stop exporting this
23+ , ParseResult (..)
24+ , Parser (..)
24 , ParserK
25 , ParserK
26+ , fromParser
27+ , toParser
25 , fromPure
28 , fromPure
26 , fromEffect
29 , fromEffect
27 , die
30 , die
28 )
31 )
29where
32where
30
33
34+#include "ArrayMacros.h"
35+#include "assert.hs"
31#include "inline.hs"
36#include "inline.hs"
32
37
33import Control.Applicative (Alternative(..), liftA2)
38import Control.Applicative (Alternative(..), liftA2)
34import Control.Monad (MonadPlus(..), ap)
39import Control.Monad (MonadPlus(..), ap)
35import Control.Monad.IO.Class (MonadIO, liftIO)
40import Control.Monad.IO.Class (MonadIO, liftIO)
36-- import Control.Monad.Trans.Class (MonadTrans(lift))
41-- import Control.Monad.Trans.Class (MonadTrans(lift))
42+import Data.Proxy (Proxy(..))
43+import GHC.Types (SPEC(..))
44+import Streamly.Internal.Data.Array.Type (Array(..))
45+import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
46+
37import qualified Control.Monad.Fail as Fail
47import qualified Control.Monad.Fail as Fail
48+import qualified Streamly.Internal.Data.Array.Type as Array
49+import qualified Streamly.Internal.Data.Parser.ParserD.Type as ParserD
50+
51+data Input a = None | Single a | Chunk (Array a)
38
52
39-- | The intermediate result of running a parser step. The parser driver may
53-- | The intermediate result of running a parser step. The parser driver may
40-- stop with a final result, pause with a continuation to resume, or fail with
54-- stop with a final result, pause with a continuation to resume, or fail with
@@ -46,32 +60,45 @@ import qualified Control.Monad.Fail as Fail
46--
60--
47-- /Pre-release/
61-- /Pre-release/
48--
62--
49−data Step m a r =
63+data Step a m r =
64+ -- The Int is the current stream position index wrt to the start of the
65+ -- array.
50 Done !Int r
66 Done !Int r
51 -- XXX we can use a "resume" and a "stop" continuations instead of Maybe.
67 -- XXX we can use a "resume" and a "stop" continuations instead of Maybe.
52 -- measure if that works any better.
68 -- measure if that works any better.
69+ -- Array a -> m (Step a m r), m (Step a m r)
53− | Partial !Int (Maybe a -> m (Step m a r))
70+ | Partial !Int (Input a -> m (Step a m r))
54− | Continue !Int (Maybe a -> m (Step m a r))
71+ | Continue !Int (Input a -> m (Step a m r))
55− | Error String
72+ | Error !Int String
56
73
57−instance Functor m => Functor (Step m a) where
74+instance Functor m => Functor (Step a m) where
58 fmap f (Done n r) = Done n (f r)
75 fmap f (Done n r) = Done n (f r)
59 fmap f (Partial n k) = Partial n (fmap (fmap f) . k)
76 fmap f (Partial n k) = Partial n (fmap (fmap f) . k)
60 fmap f (Continue n k) = Continue n (fmap (fmap f) . k)
77 fmap f (Continue n k) = Continue n (fmap (fmap f) . k)
61− fmap _ (Error e) = Error e
78+ fmap _ (Error n e) = Error n e
62
79
63-- | The parser's result.
80-- | The parser's result.
64--
81--
82+-- Int is the position index into the current input array. Could be negative.
83+-- Cannot be beyond the input array max bound.
84+--
65-- /Pre-release/
85-- /Pre-release/
66--
86--
67−data Parse b =
87+data ParseResult b =
68− Success !Int !b -- Leftover count, result
88+ Success !Int !b -- Position index, result
69− | Failure !String -- Error
89+ | Failure !Int !String -- Position index, error
70
90
71-- | Map a function over 'Success'.
91-- | Map a function over 'Success'.
72−instance Functor Parse where
92+instance Functor ParseResult where
73 fmap f (Success n b) = Success n (f b)
93 fmap f (Success n b) = Success n (f b)
74− fmap _ (Failure e) = Failure e
94+ fmap _ (Failure n e) = Failure n e
95+
96+-- XXX Change the type to the shape (a -> m r -> m r) -> (m r -> m r) -> m r
97+--
98+-- The parse continuation would be: Array a -> m (Step a m r) -> m (Step a m r)
99+-- The extract continuation would be: m (Step a m r) -> m (Step a m r)
100+--
101+-- Use Step itself in place of ParseResult.
75
102
76-- | A continuation passing style parser representation. A continuation of
103-- | A continuation passing style parser representation. A continuation of
77-- 'Step's, each step passes a state and a parse result to the next 'Step'. The
104-- 'Step's, each step passes a state and a parse result to the next 'Step'. The
@@ -82,24 +109,27 @@ instance Functor Parse where
82--
109--
83newtype Parser a m b = MkParser
110newtype Parser a m b = MkParser
84 { runParser :: forall r.
111 { runParser :: forall r.
85− -- leftover: the number of elements that were not used by the
112+ -- XXX Maintain and pass the original position in the stream. that
86− -- previous consumer and should be carried forward.
113+ -- way we can also report better errors. Use a Context structure for
114+ -- passing the state.
115+
116+ -- Stream position index wrt to the current input array start. If
117+ -- negative then backtracking is required before using the array.
118+ -- The parser should use "Continue -n" in this case if it needs to
119+ -- consume input. Negative value cannot be beyond the current
120+ -- backtrack buffer. Positive value cannot be beyond array length.
121+ -- If the parser needs to advance beyond the array length it should
122+ -- use "Continue +n".
87 Int
123 Int
88− -- (alt nesting level, alt used elem count). Nesting level is
89− -- increased whenever we enter an Alternative composition and
90− -- decreased when it is done. The used element count is a count of
91− -- elements consumed by the Alternative. If the Alternative fails we
124+ -- used elem count, a count of elements consumed by the parser. If
92− -- need to backtrack by this amount.
125+ -- an Alternative fails we need to backtrack by this amount.
93− --
94− -- The nesting level is used in parseDToK to optimize the case when
95− -- we are not in an alternative, in that case we do not need to
96− -- maintain the element count for backtracking.
97− -> (Int, Int)
126+ -> Int
98− -- The first argument is the (nest level, used count) tuple as
127+ -- The second argument is the used count as described above. The
99− -- described above. The leftover element count is carried as part of
128+ -- current input position is carried as part of 'Success'
100− -- 'Success' constructor of 'Parse'.
129+ -- constructor of 'ParseResult'.
101− -> ((Int, Int) -> Parse b -> m (Step m a r))
130+ -> Input a
131+ -> (ParseResult b -> Int -> Input a -> m (Step a m r))
102− -> m (Step m a r)
132+ -> m (Step a m r)
103 }
133 }
104
134
105type ParserK = Parser
135type ParserK = Parser
@@ -113,9 +143,9 @@ type ParserK = Parser
113--
143--
114instance Functor m => Functor (Parser a m) where
144instance Functor m => Functor (Parser a m) where
115 {-# INLINE fmap #-}
145 {-# INLINE fmap #-}
116− fmap f parser = MkParser $ \n st k ->
146+ fmap f parser = MkParser $ \n st arr pk ->
117− let k1 s res = k s (fmap f res)
147+ let pk1 res = pk (fmap f res)
118− in runParser parser n st k1
148+ in runParser parser n st arr pk1
119
149
120-------------------------------------------------------------------------------
150-------------------------------------------------------------------------------
121-- Sequential applicative
151-- Sequential applicative
@@ -129,7 +159,7 @@ instance Functor m => Functor (Parser a m) where
129--
159--
130{-# INLINE fromPure #-}
160{-# INLINE fromPure #-}
131fromPure :: b -> Parser a m b
161fromPure :: b -> Parser a m b
132−fromPure b = MkParser $ \n st k -> k st (Success n b)
162+fromPure b = MkParser $ \n st arr pk -> pk (Success n b) st arr
133
163
134-- | See 'Streamly.Internal.Data.Parser.fromEffect'.
164-- | See 'Streamly.Internal.Data.Parser.fromEffect'.
135--
165--
@@ -137,7 +167,8 @@ fromPure b = MkParser $ \n st k -> k st (Success n b)
137--
167--
138{-# INLINE fromEffect #-}
168{-# INLINE fromEffect #-}
139fromEffect :: Monad m => m b -> Parser a m b
169fromEffect :: Monad m => m b -> Parser a m b
170+fromEffect eff =
140−fromEffect eff = MkParser $ \n st k -> eff >>= \b -> k st (Success n b)
171+ MkParser $ \n st arr pk -> eff >>= \b -> pk (Success n b) st arr
141
172
142-- | 'Applicative' form of 'Streamly.Internal.Data.Parser.splitWith'. Note that
173-- | 'Applicative' form of 'Streamly.Internal.Data.Parser.splitWith'. Note that
143-- this operation does not fuse, use 'Streamly.Internal.Data.Parser.splitWith'
174-- this operation does not fuse, use 'Streamly.Internal.Data.Parser.splitWith'
@@ -151,19 +182,19 @@ instance Monad m => Applicative (Parser a m) where
151 (<*>) = ap
182 (<*>) = ap
152
183
153 {-# INLINE (*>) #-}
184 {-# INLINE (*>) #-}
154− p1 *> p2 = MkParser $ \n st k ->
185+ p1 *> p2 = MkParser $ \n st arr k ->
155− let k1 s (Success n1 _) = runParser p2 n1 s k
186+ let k1 (Success n1 _) s input = runParser p2 n1 s input k
156− k1 s (Failure e) = k s (Failure e)
187+ k1 (Failure n1 e) s input = k (Failure n1 e) s input
157− in runParser p1 n st k1
188+ in runParser p1 n st arr k1
158
189
159 {-# INLINE (<*) #-}
190 {-# INLINE (<*) #-}
160− p1 <* p2 = MkParser $ \n st k ->
191+ p1 <* p2 = MkParser $ \n st arr k ->
161− let k1 s1 (Success n1 b) =
192+ let k1 (Success n1 b) s1 input =
162− let k2 s2 (Success n2 _) = k s2 (Success n2 b)
193+ let k2 (Success n2 _) = k (Success n2 b)
163− k2 s2 (Failure e) = k s2 (Failure e)
194+ k2 (Failure n2 e) = k (Failure n2 e)
164− in runParser p2 n1 s1 k2
195+ in runParser p2 n1 s1 input k2
165− k1 s1 (Failure e) = k s1 (Failure e)
196+ k1 (Failure n1 e) s1 input = k (Failure n1 e) s1 input
166− in runParser p1 n st k1
197+ in runParser p1 n st arr k1
167
198
168 {-# INLINE liftA2 #-}
199 {-# INLINE liftA2 #-}
169 liftA2 f p = (<*>) (fmap f p)
200 liftA2 f p = (<*>) (fmap f p)
@@ -181,7 +212,7 @@ instance Monad m => Applicative (Parser a m) where
181--
212--
182{-# INLINE die #-}
213{-# INLINE die #-}
183die :: String -> Parser a m b
214die :: String -> Parser a m b
184−die err = MkParser (\_ st k -> k st (Failure err))
215+die err = MkParser (\n st arr pk -> pk (Failure n err) st arr)
185
216
186-- | Monad composition can be used for lookbehind parsers, we can make the
217-- | Monad composition can be used for lookbehind parsers, we can make the
187-- future parses depend on the previously parsed values.
218-- future parses depend on the previously parsed values.
@@ -230,10 +261,10 @@ instance Monad m => Monad (Parser a m) where
230 return = pure
261 return = pure
231
262
232 {-# INLINE (>>=) #-}
263 {-# INLINE (>>=) #-}
233− p >>= f = MkParser $ \n st k ->
264+ p >>= f = MkParser $ \n st arr pk ->
234− let k1 s1 (Success n1 b) = runParser (f b) n1 s1 k
265+ let pk1 (Success n1 b) s1 inp = runParser (f b) n1 s1 inp pk
235− k1 s1 (Failure e) = k s1 (Failure e)
266+ pk1 (Failure n1 e) s1 inp = pk (Failure n1 e) s1 inp
236− in runParser p n st k1
267+ in runParser p n st arr pk1
237
268
238 {-# INLINE (>>) #-}
269 {-# INLINE (>>) #-}
239 (>>) = (*>)
270 (>>) = (*>)
@@ -274,11 +305,11 @@ instance Monad m => Alternative (Parser a m) where
274 empty = die "empty"
305 empty = die "empty"
275
306
276 {-# INLINE (<|>) #-}
307 {-# INLINE (<|>) #-}
277− p1 <|> p2 = MkParser $ \n (level, _) k ->
308+ p1 <|> p2 = MkParser $ \n _ arr k ->
278− let k1 (0, _) _ = error "Bug: 0 nest level in Alternative"
309+ let
279− k1 (l1, n1) (Failure _) = runParser p2 n1 (l1 - 1, 0) k
310+ k1 (Failure pos _) used input = runParser p2 (pos - used) 0 input k
280− k1 (l1, _) success = k (l1 - 1, 0) success
311+ k1 success _ input = k success 0 input
281− in runParser p1 n (level + 1, 0) k1
312+ in runParser p1 n 0 arr k1
282
313
283 -- some and many are implemented here instead of using default definitions
314 -- some and many are implemented here instead of using default definitions
284 -- so that we can use INLINE on them. It gives 50% performance improvement.
315 -- so that we can use INLINE on them. It gives 50% performance improvement.
@@ -314,3 +345,207 @@ instance MonadTrans (Parser a) where
314 {-# INLINE lift #-}
345 {-# INLINE lift #-}
315 lift = fromEffect
346 lift = fromEffect
316-}
347-}
348+
349+-------------------------------------------------------------------------------
350+-- Convert ParserD to ParserK
351+-------------------------------------------------------------------------------
352+
353+data ChunkResult s b =
354+ ChunkDone !Int !b
355+ | ChunkPartial !Int !s
356+ | ChunkContinue !Int !s
357+ | ChunkError !Int String
358+
359+-- This is very similar to fromParserD in the Array/Unboxed/Fold module.
360+{-# INLINE parseChunk #-}
361+parseChunk
362+ :: forall m a s b. (MonadIO m, Unbox a)
363+ => (s -> a -> m (ParserD.Step s b))
364+ -> s
365+ -> Array a
366+ -> Int
367+ -> m (ChunkResult s b)
368+parseChunk pstep state (Array contents start end) offset = do
369+ if offset >= 0
370+ then go SPEC (start + offset * SIZE_OF(a)) state
371+ else return $ ChunkContinue offset state
372+
373+ where
374+
375+ {-# INLINE onBack #-}
376+ onBack offset1 elemSize constr pst = do
377+ let pos = offset1 - start
378+ in if pos >= 0
379+ then go SPEC offset1 pst
380+ else return $ constr (pos `div` elemSize) pst
381+
382+ -- Note: div may be expensive but the alternative is to maintain an element
383+ -- offset in addition to a byte offset or just the element offset and use
384+ -- multiplication to get the byte offset every time, both these options
385+ -- turned out to be more expensive than using div.
386+ go !_ !cur !pst | cur >= end =
387+ return $ ChunkContinue ((end - start) `div` SIZE_OF(a)) pst
388+ go !_ !cur !pst = do
389+ x <- liftIO $ peekWith contents cur
390+ pRes <- pstep pst x
391+ let elemSize = SIZE_OF(a)
392+ next = INDEX_NEXT(cur,a)
393+ back n = next - n * elemSize
394+ curOff = (cur - start) `div` elemSize
395+ nextOff = (next - start) `div` elemSize
396+ case pRes of
397+ ParserD.Done 0 b ->
398+ return $ ChunkDone nextOff b
399+ ParserD.Done 1 b ->
400+ return $ ChunkDone curOff b
401+ ParserD.Done n b ->
402+ return $ ChunkDone ((back n - start) `div` elemSize) b
403+ ParserD.Partial 0 pst1 ->
404+ go SPEC next pst1
405+ ParserD.Partial 1 pst1 ->
406+ go SPEC cur pst1
407+ ParserD.Partial n pst1 ->
408+ onBack (back n) elemSize ChunkPartial pst1
409+ ParserD.Continue 0 pst1 ->
410+ go SPEC next pst1
411+ ParserD.Continue 1 pst1 ->
412+ go SPEC cur pst1
413+ ParserD.Continue n pst1 ->
414+ onBack (back n) elemSize ChunkContinue pst1
415+ ParserD.Error err ->
416+ return $ ChunkError curOff err
417+
418+{-# INLINE parseDToK #-}
419+parseDToK
420+ :: forall m a s b r. (MonadIO m, Unbox a)
421+ => (s -> a -> m (ParserD.Step s b))
422+ -> m (ParserD.Initial s b)
423+ -> (s -> m (ParserD.Step s b))
424+ -> Int
425+ -> Int
426+ -> Input a
427+ -> (ParseResult b -> Int -> Input a -> m (Step a m r))
428+ -> m (Step a m r)
429+parseDToK pstep initial extract offset usedCount input cont = do
430+ res <- initial
431+ case res of
432+ ParserD.IPartial pst -> do
433+ case input of
434+ Chunk arr -> parseContChunk usedCount offset pst arr
435+ Single x -> parseContSingle usedCount offset pst x
436+ None -> parseContNothing usedCount pst
437+ ParserD.IDone b -> cont (Success offset b) usedCount input
438+ ParserD.IError err -> cont (Failure offset err) usedCount input
439+
440+ where
441+
442+ -- XXX We can maintain an absolute position instead of relative that will
443+ -- help in reporting of error location in the stream.
444+ {-# NOINLINE parseContChunk #-}
445+ parseContChunk count off pst arr = do
446+ pRes <- parseChunk pstep pst arr off
447+ -- The "n" here is stream position index wrt the array start, and not
448+ -- the backtrack count as returned by byte stream parsers.
449+ case pRes of
450+ ChunkDone n b ->
451+ assert (n <= Array.length arr)
452+ (cont (Success n b) (count + n - off) (Chunk arr))
453+ ChunkPartial n pst1 ->
454+ assert (n < 0 || n >= Array.length arr)
455+ (return $ Partial n (parseCont (count + n - off) pst1))
456+ ChunkContinue n pst1 ->
457+ assert (n < 0 || n >= Array.length arr)
458+ (return $ Continue n (parseCont (count + n - off) pst1))
459+ ChunkError n err ->
460+ cont (Failure n err) (count + n - off) (Chunk arr)
461+
462+ -- XXX This is not yet finished
463+ {-# NOINLINE parseContSingle #-}
464+ parseContSingle _count off pst x = do
465+ pRes <- pstep pst x
466+ case pRes of
467+ ParserD.Done _n b -> do
468+ cont (Success (off + 1) b) undefined undefined
469+ _ -> undefined
470+
471+ {-# NOINLINE parseContNothing #-}
472+ parseContNothing count pst = do
473+ r <- extract pst
474+ case r of
475+ -- IMPORTANT: the n here is from the byte stream parser, that means
476+ -- it is the backtrack element count and not the stream position
477+ -- index into the current input array.
478+ ParserD.Done n b ->
479+ assert (n >= 0)
480+ (cont (Success (- n) b) (count - n) None)
481+ ParserD.Continue n pst1 ->
482+ assert (n >= 0)
483+ (return $ Continue (- n) (parseCont (count - n) pst1))
484+ ParserD.Error err ->
485+ -- XXX It is called only when there is no input arr. So using 0
486+ -- as the position is correct?
487+ cont (Failure 0 err) count None
488+ ParserD.Partial _ _ -> error "Bug: parseDToK Partial unreachable"
489+
490+ -- XXX Maybe we can use two separate continuations instead of using
491+ -- Just/Nothing cases here. That may help in avoiding the parseContJust
492+ -- function call.
493+ {-# INLINE parseCont #-}
494+ parseCont cnt pst (Chunk arr) = parseContChunk cnt 0 pst arr
495+ parseCont cnt pst (Single x) = parseContSingle cnt 0 pst x
496+ parseCont cnt pst None = parseContNothing cnt pst
497+
498+-- | Convert a raw byte 'Parser' to a chunked parser.
499+--
500+-- /Pre-release/
501+--
502+{-# INLINE_LATE fromParser #-}
503+fromParser :: (MonadIO m, Unbox a) => ParserD.Parser a m b -> ParserK a m b
504+fromParser (ParserD.Parser step initial extract) =
505+ MkParser $ parseDToK step initial extract
506+
507+-------------------------------------------------------------------------------
508+-- Convert CPS style 'Parser' to direct style 'D.Parser'
509+-------------------------------------------------------------------------------
510+
511+-- | A continuation to extract the result when a CPS parser is done.
512+{-# INLINE parserDone #-}
513+parserDone :: Monad m => ParseResult b -> Int -> Input a -> m (Step a m b)
514+parserDone (Success n b) _ None = return $ Done n b
515+parserDone (Failure n e) _ None = return $ Error n e
516+parserDone _ _ _ = error "Bug: toParser: called with input"
517+
518+-- | Convert a CPS style 'ParserK' to a direct style 'ParserD.Parser'.
519+--
520+-- /Pre-release/
521+--
522+{-# INLINE_LATE toParser #-}
523+toParser :: Monad m => Parser a m b -> ParserD.Parser a m b
524+toParser parser = ParserD.Parser step initial extract
525+
526+ where
527+
528+ initial = pure (ParserD.IPartial (\x -> runParser parser 0 0 x parserDone))
529+
530+ step cont a = do
531+ r <- cont (Single a)
532+ return $ case r of
533+ Done n b -> ParserD.Done n b
534+ Error _ e -> ParserD.Error e
535+ Partial n cont1 -> ParserD.Partial n cont1
536+ Continue n cont1 -> ParserD.Continue n cont1
537+
538+ extract cont = do
539+ r <- cont None
540+ case r of
541+ Done n b -> return $ ParserD.Done n b
542+ Error _ e -> return $ ParserD.Error e
543+ Partial _ cont1 -> extract cont1
544+ Continue n cont1 -> return $ ParserD.Continue n cont1
545+
546+#ifndef DISABLE_FUSION
547+{-# RULES "fromParser/toParser fusion" [2]
548+ forall s. toParser (fromParser s) = s #-}
549+{-# RULES "toParser/fromParser fusion" [2]
550+ forall s. fromParser (toParser s) = s #-}
551+#endif
core/src/Streamly/Internal/Data/Producer/Source.hs+10−8
@@ -41,7 +41,7 @@ import Streamly.Internal.Data.Producer.Type (Producer(..))
41import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
41import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
42
42
43import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
43import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
44−import qualified Streamly.Internal.Data.Parser.ParserK.Type as ParserK
44+-- import qualified Streamly.Internal.Data.Parser.ParserK.Type as ParserK
45
45
46import Prelude hiding (read)
46import Prelude hiding (read)
47
47
@@ -109,14 +109,14 @@ producer (Producer step1 inject1 extract1) = Producer step inject extract
109{-# ANN type List NoSpecConstr #-}
109{-# ANN type List NoSpecConstr #-}
110newtype List a = List {getList :: [a]}
110newtype List a = List {getList :: [a]}
111
111
112−{-# INLINE_NORMAL parseD #-}
112+{-# INLINE_NORMAL parse #-}
113−parseD
113+parse
114 :: Monad m =>
114 :: Monad m =>
115 ParserD.Parser a m b
115 ParserD.Parser a m b
116 -> Producer m (Source s a) a
116 -> Producer m (Source s a) a
117 -> Source s a
117 -> Source s a
118 -> m (Either ParseError b, Source s a)
118 -> m (Either ParseError b, Source s a)
119−parseD
119+parse
120 (ParserD.Parser pstep initial extract)
120 (ParserD.Parser pstep initial extract)
121 (Producer ustep uinject uextract)
121 (Producer ustep uinject uextract)
122 seed = do
122 seed = do
@@ -241,17 +241,19 @@ parseD
241 Error err ->
241 Error err ->
242 return (Left (ParseError err), source Nothing)
242 return (Left (ParseError err), source Nothing)
243
243
244+{-
244-- | Parse a buffered source using a parser, returning the parsed value and the
245-- | Parse a buffered source using a parser, returning the parsed value and the
245-- remaining source.
246-- remaining source.
246--
247--
247-- /Pre-release/
248-- /Pre-release/
248−{-# INLINE [3] parse #-}
249+{-# INLINE [3] parseK #-}
249−parse :: Monad m =>
250+parseK :: Monad m =>
250 ParserK.Parser a m b
251 ParserK.Parser a m b
251 -> Producer m (Source s a) a
252 -> Producer m (Source s a) a
252 -> Source s a
253 -> Source s a
253 -> m (Either ParseError b, Source s a)
254 -> m (Either ParseError b, Source s a)
254−parse = parseD . ParserD.fromParserK
255+parseK = parse . ParserK.toParser
256+-}
255
257
256-------------------------------------------------------------------------------
258-------------------------------------------------------------------------------
257-- Nested parsing
259-- Nested parsing
@@ -271,7 +273,7 @@ parseManyD parser reader = Producer step return return
271 if isEmpty src
273 if isEmpty src
272 then return Stop
274 then return Stop
273 else do
275 else do
274− (b, s1) <- parseD parser reader src
276+ (b, s1) <- parse parser reader src
275 case b of
277 case b of
276 Right b1 -> return $ Yield (Right b1) s1
278 Right b1 -> return $ Yield (Right b1) s1
277 Left _ -> return Stop
279 Left _ -> return Stop
core/src/Streamly/Internal/Data/Stream/StreamK.hs+151
@@ -119,6 +119,8 @@ module Streamly.Internal.Data.Stream.StreamK
119 , foldConcat
119 , foldConcat
120 , parseBreak
120 , parseBreak
121 , parse
121 , parse
122+ , parseKBreakChunks
123+ , parseKChunks
122
124
123 -- ** Specialized Folds
125 -- ** Specialized Folds
124 , drain
126 , drain
@@ -219,18 +221,24 @@ module Streamly.Internal.Data.Stream.StreamK
219 )
221 )
220where
222where
221
223
224+#include "ArrayMacros.h"
222#include "inline.hs"
225#include "inline.hs"
223#include "assert.hs"
226#include "assert.hs"
224
227
225import Control.Monad (void, join)
228import Control.Monad (void, join)
229+import Data.Proxy (Proxy(..))
226import GHC.Types (SPEC(..))
230import GHC.Types (SPEC(..))
231+import Streamly.Internal.Data.Array.Type (Array(..))
227import Streamly.Internal.Data.Fold.Type (Fold(..))
232import Streamly.Internal.Data.Fold.Type (Fold(..))
228import Streamly.Internal.Data.Producer.Type (Producer(..))
233import Streamly.Internal.Data.Producer.Type (Producer(..))
229import Streamly.Internal.Data.SVar.Type (adaptState, defState)
234import Streamly.Internal.Data.SVar.Type (adaptState, defState)
235+import Streamly.Internal.Data.Unboxed (sizeOf, Unbox)
230
236
237+import qualified Streamly.Internal.Data.Array.Type as Array
231import qualified Streamly.Internal.Data.Fold.Type as FL
238import qualified Streamly.Internal.Data.Fold.Type as FL
232import qualified Streamly.Internal.Data.Parser as Parser
239import qualified Streamly.Internal.Data.Parser as Parser
233import qualified Streamly.Internal.Data.Parser.ParserD.Type as PR
240import qualified Streamly.Internal.Data.Parser.ParserD.Type as PR
241+import qualified Streamly.Internal.Data.Parser.ParserK.Type as ParserK
234import qualified Streamly.Internal.Data.Stream.StreamD as Stream
242import qualified Streamly.Internal.Data.Stream.StreamD as Stream
235import qualified Prelude
243import qualified Prelude
236
244
@@ -1233,11 +1241,154 @@ parseBreak :: Monad m =>
1233 Parser.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
1241 Parser.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
1234parseBreak = parseBreakD
1242parseBreak = parseBreakD
1235
1243
1244+-- Using ParserD or ParserK on StreamK may not make much difference. We should
1245+-- perhaps use only chunked parsing on StreamK. We can always convert a stream
1246+-- to chunks before parsing. Or just have a ParserK element parser for StreamK
1247+-- and convert ParserD to ParserK for element parsing using StreamK.
1236{-# INLINE parse #-}
1248{-# INLINE parse #-}
1237parse :: Monad m =>
1249parse :: Monad m =>
1238 Parser.Parser a m b -> Stream m a -> m (Either ParseError b)
1250 Parser.Parser a m b -> Stream m a -> m (Either ParseError b)
1239parse f = fmap fst . parseBreak f
1251parse f = fmap fst . parseBreak f
1240
1252
1253+-------------------------------------------------------------------------------
1254+-- Chunked parsing using ParserK
1255+-------------------------------------------------------------------------------
1256+
1257+-- The backracking buffer consists of arrays in the most-recent-first order. We
1258+-- want to take a total of n array elements from this buffer. Note: when we
1259+-- have to take an array partially, we must take the last part of the array.
1260+{-# INLINE backTrack #-}
1261+backTrack :: forall m a. Unbox a =>
1262+ Int
1263+ -> [Array a]
1264+ -> StreamK m (Array a)
1265+ -> (StreamK m (Array a), [Array a])
1266+backTrack = go
1267+
1268+ where
1269+
1270+ go _ [] stream = (stream, [])
1271+ go n xs stream | n <= 0 = (stream, xs)
1272+ go n (x:xs) stream =
1273+ let len = Array.length x
1274+ in if n > len
1275+ then go (n - len) xs (cons x stream)
1276+ else if n == len
1277+ then (cons x stream, xs)
1278+ else let !(Array contents start end) = x
1279+ !start1 = end - (n * SIZE_OF(a))
1280+ arr1 = Array contents start1 end
1281+ arr2 = Array contents start start1
1282+ in (cons arr1 stream, arr2:xs)
1283+
1284+-- | A continuation to extract the result when a CPS parser is done.
1285+{-# INLINE parserDone #-}
1286+parserDone :: Applicative m =>
1287+ ParserK.ParseResult b -> Int -> ParserK.Input a -> m (ParserK.Step a m b)
1288+parserDone (ParserK.Success n b) _ _ = pure $ ParserK.Done n b
1289+parserDone (ParserK.Failure n e) _ _ = pure $ ParserK.Error n e
1290+
1291+-- | Run a 'ParserK' over a chunked 'StreamK' and return the rest of the Stream.
1292+{-# INLINE_NORMAL parseKBreakChunks #-}
1293+parseKBreakChunks
1294+ :: (Monad m, Unbox a)
1295+ => ParserK.Parser a m b
1296+ -> StreamK m (Array a)
1297+ -> m (Either ParseError b, StreamK m (Array a))
1298+parseKBreakChunks parser input = do
1299+ let parserk = \arr -> ParserK.runParser parser 0 0 arr parserDone
1300+ in go [] parserk input
1301+
1302+ where
1303+
1304+ {-# INLINE goStop #-}
1305+ goStop backBuf parserk = do
1306+ pRes <- parserk ParserK.None
1307+ case pRes of
1308+ -- If we stop in an alternative, it will try calling the next
1309+ -- parser, the next parser may call initial returning Partial and
1310+ -- then immediately we have to call extract on it.
1311+ ParserK.Partial 0 cont1 ->
1312+ go [] cont1 nil
1313+ ParserK.Partial n cont1 -> do
1314+ let n1 = negate n
1315+ assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1316+ let (s1, backBuf1) = backTrack n1 backBuf nil
1317+ in go backBuf1 cont1 s1
1318+ ParserK.Continue 0 cont1 ->
1319+ go backBuf cont1 nil
1320+ ParserK.Continue n cont1 -> do
1321+ let n1 = negate n
1322+ assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1323+ let (s1, backBuf1) = backTrack n1 backBuf nil
1324+ in go backBuf1 cont1 s1
1325+ ParserK.Done 0 b ->
1326+ return (Right b, nil)
1327+ ParserK.Done n b -> do
1328+ let n1 = negate n
1329+ assertM(n1 >= 0 && n1 <= sum (Prelude.map Array.length backBuf))
1330+ let (s1, _) = backTrack n1 backBuf nil
1331+ in return (Right b, s1)
1332+ ParserK.Error _ err -> return (Left (ParseError err), nil)
1333+
1334+ seekErr n len =
1335+ error $ "parseBreak: Partial: forward seek not implemented n = "
1336+ ++ show n ++ " len = " ++ show len
1337+
1338+ yieldk backBuf parserk arr stream = do
1339+ pRes <- parserk (ParserK.Chunk arr)
1340+ let len = Array.length arr
1341+ case pRes of
1342+ ParserK.Partial n cont1 ->
1343+ case compare n len of
1344+ EQ -> go [] cont1 stream
1345+ LT -> do
1346+ if n >= 0
1347+ then yieldk [] cont1 arr stream
1348+ else do
1349+ let n1 = negate n
1350+ bufLen = sum (Prelude.map Array.length backBuf)
1351+ s = cons arr stream
1352+ assertM(n1 >= 0 && n1 <= bufLen)
1353+ let (s1, _) = backTrack n1 backBuf s
1354+ go [] cont1 s1
1355+ GT -> seekErr n len
1356+ ParserK.Continue n cont1 ->
1357+ case compare n len of
1358+ EQ -> go (arr:backBuf) cont1 stream
1359+ LT -> do
1360+ if n >= 0
1361+ then yieldk backBuf cont1 arr stream
1362+ else do
1363+ let n1 = negate n
1364+ bufLen = sum (Prelude.map Array.length backBuf)
1365+ s = cons arr stream
1366+ assertM(n1 >= 0 && n1 <= bufLen)
1367+ let (s1, backBuf1) = backTrack n1 backBuf s
1368+ go backBuf1 cont1 s1
1369+ GT -> seekErr n len
1370+ ParserK.Done n b -> do
1371+ let n1 = len - n
1372+ assertM(n1 <= sum (Prelude.map Array.length (arr:backBuf)))
1373+ let (s1, _) = backTrack n1 (arr:backBuf) stream
1374+ in return (Right b, s1)
1375+ ParserK.Error _ err -> return (Left (ParseError err), nil)
1376+
1377+ go backBuf parserk stream = do
1378+ let stop = goStop backBuf parserk
1379+ single a = yieldk backBuf parserk a nil
1380+ in foldStream
1381+ defState (yieldk backBuf parserk) single stop stream
1382+
1383+{-# INLINE parseKChunks #-}
1384+parseKChunks :: (Monad m, Unbox a) =>
1385+ ParserK.Parser a m b -> Stream m (Array a) -> m (Either ParseError b)
1386+parseKChunks f = fmap fst . parseKBreakChunks f
1387+
1388+-------------------------------------------------------------------------------
1389+-- Sorting
1390+-------------------------------------------------------------------------------
1391+
1241-- | Sort the input stream using a supplied comparison function.
1392-- | Sort the input stream using a supplied comparison function.
1242--
1393--
1243-- Sorting can be achieved by simply:
1394-- Sorting can be achieved by simply:
src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+1−1
@@ -382,7 +382,7 @@ parseD p = D.parseD p . toStreamD
382-- /Internal/
382-- /Internal/
383{-# INLINE parseK #-}
383{-# INLINE parseK #-}
384parseK :: Monad m => PRK.Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
384parseK :: Monad m => PRK.Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
385−parseK p = parse (PRD.fromParserK p)
385+parseK p = parse (PRK.toParser p)
386
386
387-- | Parse a stream using the supplied 'Parser'.
387-- | Parse a stream using the supplied 'Parser'.
388--
388--