@@ -22,6 +22,11 @@ module Streamly.Internal.Data.Array.Stream.Foreign
24 -- * Elimination
24 -- * Elimination
25 -- ** Array Folds
30 -- ** Array Folds
27 , foldArr_
32 , foldArr_
@@ -50,6 +55,9 @@ import Data.Bifunctor (second)
50import Control.Exception (assert)
55import Control.Exception (assert)
51import Control.Monad.Catch (MonadThrow, throwM)
56import Control.Monad.Catch (MonadThrow, throwM)
52import Control.Monad.IO.Class (MonadIO(..))
57import Control.Monad.IO.Class (MonadIO(..))
58+#if __GLASGOW_HASKELL__ < 808
59+import Data.Semigroup (Semigroup(..))
53import Data.Word (Word8)
61import Data.Word (Word8)
54import Foreign.ForeignPtr (touchForeignPtr)
62import Foreign.ForeignPtr (touchForeignPtr)
55import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
63import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
@@ -317,7 +325,65 @@ splitOnSuffix byte s =
317 D.fromStreamD $ D.splitInnerBySuffix (A.breakOn byte) A.spliceTwo $ D.toStreamD s
325 D.fromStreamD $ D.splitInnerBySuffix (A.breakOn byte) A.spliceTwo $ D.toStreamD s
319-------------------------------------------------------------------------------
327-------------------------------------------------------------------------------
320−-- Elimination
328+-- Elimination - Running folds
329+-------------------------------------------------------------------------------
331+-- XXX This should be written using CPS (as foldK) if we want it to scale wrt
332+-- to the number of times it can be called on the same stream.
334+{-# INLINE_NORMAL foldD #-}
335+foldD :: forall m a b. (MonadIO m, Storable a) =>
336+ Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
337+foldD (Fold fstep initial extract) stream@(D.Stream step state) = do
340+ FL.Partial fs -> go SPEC state fs
341+ FL.Done fb -> return $! (fb, stream)
347+ r <- step defState st
349+ D.Yield (Array (ForeignPtr start contents) (Ptr end)) s ->
350+ goArray SPEC s (ForeignPtr end contents) (Ptr start) fs
351+ D.Skip s -> go SPEC s fs
356+ goArray !_ s fp@(ForeignPtr end _) !cur !fs
357+ | cur == Ptr end = do
358+ liftIO $ touchForeignPtr fp
360+ goArray !_ st fp@(ForeignPtr end contents) !cur !fs = do
361+ x <- liftIO $ peek cur
363+ let elemSize = sizeOf (undefined :: a)
364+ next = cur `plusPtr` elemSize
367+ let !(Ptr curAddr) = next
368+ arr = Array (ForeignPtr curAddr contents) (Ptr end)
369+ return $! (b, D.cons arr (D.Stream step st))
370+ FL.Partial fs1 -> goArray SPEC st fp next fs1
372+-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
373+-- and the unconsumed stream.
377+{-# INLINE_NORMAL fold #-}
379+ (MonadIO m, Storable a)
381+ -> SerialT m (A.Array a)
382+ -> m (b, SerialT m (A.Array a))
383+fold f s = fmap D.fromStreamD <$> foldD f (D.toStreamD s)
385+-------------------------------------------------------------------------------
386+-- Fold to a single Array
321-------------------------------------------------------------------------------
387-------------------------------------------------------------------------------
323-- When we have to take an array partially, take the last part of the array.
389-- When we have to take an array partially, take the last part of the array.
@@ -459,7 +525,7 @@ _toArraysOf n = FL.chunksOf n (A.writeNF n) FL.toStream
461-------------------------------------------------------------------------------
527-------------------------------------------------------------------------------
462−-- Parsing
528+-- Elimination - running element parsers
463-------------------------------------------------------------------------------
529-------------------------------------------------------------------------------
465-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
531-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
@@ -467,6 +533,110 @@ _toArraysOf n = FL.chunksOf n (A.writeNF n) FL.toStream
467{-# ANN type List NoSpecConstr #-}
533{-# ANN type List NoSpecConstr #-}
468newtype List a = List {getList :: [a]}
534newtype List a = List {getList :: [a]}
536+-- This can be generalized to any type provided it can be unfolded to a stream
537+-- and it can be combined using a semigroup operation.
539+-- XXX This should be written using CPS (as parseK) if we want it to scale wrt
540+-- to the number of times it can be called on the same stream.
541+{-# INLINE_NORMAL parseD #-}
543+ forall m a b. (MonadIO m, MonadThrow m, Storable a)
545+ -> D.Stream m (Array.Array a)
546+ -> m (b, D.Stream m (Array.Array a))
547+parseD (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
550+ PRD.IPartial s -> go SPEC state (List []) s
551+ PRD.IDone b -> return (b, stream)
552+ PRD.IError err -> throwM $ ParseError err
556+ -- "backBuf" contains last few items in the stream that we may have to
559+ -- XXX currently we are using a dumb list based approach for backtracking
560+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
561+ -- That will allow us more efficient random back and forth movement.
563+ go !_ st backBuf !pst = do
564+ r <- step defState st
566+ D.Yield (Array (ForeignPtr start contents) (Ptr end)) s ->
567+ gobuf SPEC s backBuf (ForeignPtr end contents) (Ptr start) pst
568+ D.Skip s -> go SPEC s backBuf pst
573+ -- Use strictness on "cur" to keep it unboxed
574+ gobuf !_ s backBuf fp@(ForeignPtr end _) !cur !pst
575+ | cur == Ptr end = do
576+ liftIO $ touchForeignPtr fp
577+ go SPEC s backBuf pst
578+ gobuf !_ s backBuf fp@(ForeignPtr end contents) !cur !pst = do
579+ x <- liftIO $ peek cur
581+ let elemSize = sizeOf (undefined :: a)
582+ next = cur `plusPtr` elemSize
584+ PR.Partial 0 pst1 ->
585+ gobuf SPEC s (List []) fp next pst1
586+ PR.Partial n pst1 -> do
587+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
588+ let src0 = Prelude.take n (x:getList backBuf)
589+ arr0 = A.fromListN n (Prelude.reverse src0)
590+ !(Ptr curAddr) = next
591+ arr1 = Array (ForeignPtr curAddr contents) (Ptr end)
593+ let !(Array (ForeignPtr start cont1) (Ptr end1)) = src
594+ gobuf SPEC s (List []) (ForeignPtr end1 cont1) (Ptr start) pst1
595+ PR.Continue 0 pst1 ->
596+ gobuf SPEC s (List (x:getList backBuf)) fp next pst1
597+ PR.Continue n pst1 -> do
598+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
599+ let (src0, buf1) = splitAt n (x:getList backBuf)
600+ arr0 = A.fromListN n (Prelude.reverse src0)
601+ !(Ptr curAddr) = next
602+ arr1 = Array (ForeignPtr curAddr contents) (Ptr end)
604+ let !(Array (ForeignPtr start cont1) (Ptr end1)) = src
605+ gobuf SPEC s (List buf1) (ForeignPtr end1 cont1) (Ptr start) pst1
607+ let !(Ptr curAddr) = next
608+ arr = Array (ForeignPtr curAddr contents) (Ptr end)
609+ return (b, D.cons arr (D.Stream step s))
611+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
612+ let src0 = Prelude.take n (x:getList backBuf)
613+ -- XXX create the array in reverse instead
614+ arr0 = A.fromListN n (Prelude.reverse src0)
615+ !(Ptr curAddr) = next
616+ arr1 = Array (ForeignPtr curAddr contents) (Ptr end)
617+ -- XXX Use StreamK to avoid adding arbitrary layers of
618+ -- constructors every time.
619+ str = D.cons arr0 (D.cons arr1 (D.Stream step s))
621+ PR.Error err -> throwM $ ParseError err
623+-- | Parse an array stream using the supplied 'Parser'. Returns the parse
624+-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
628+{-# INLINE_NORMAL parse #-}
630+ (MonadIO m, MonadThrow m, Storable a)
632+ -> SerialT m (A.Array a)
633+ -> m (b, SerialT m (A.Array a))
634+parse p s = fmap D.fromStreamD <$> parseD p (D.toStreamD s)
636+-------------------------------------------------------------------------------
637+-- Elimination - Running Array Folds and parsers
638+-------------------------------------------------------------------------------
470{-# INLINE_NORMAL parseArrD #-}
640{-# INLINE_NORMAL parseArrD #-}
471parseArrD ::
641parseArrD ::
472 forall m a b. (MonadIO m, MonadThrow m, Storable a)
642 forall m a b. (MonadIO m, MonadThrow m, Storable a)
@@ -540,7 +710,7 @@ parseArrD (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
540{-# INLINE parseArr #-}
710{-# INLINE parseArr #-}
541parseArr ::
711parseArr ::
542 (MonadIO m, MonadThrow m, Storable a)
712 (MonadIO m, MonadThrow m, Storable a)
543− => PRD.Parser m a b
713+ => ASF.Parser m a b
544 -> SerialT m (A.Array a)
714 -> SerialT m (A.Array a)
545 -> m (b, SerialT m (A.Array a))
715 -> m (b, SerialT m (A.Array a))
546parseArr p s = fmap D.fromStreamD <$> parseD p (D.toStreamD s)
716parseArr p s = fmap D.fromStreamD <$> parseD p (D.toStreamD s)