@@ -103,7 +103,7 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
103 -- * Eliminating and Reading
103 -- * Eliminating and Reading
105 -- ** To streams
105 -- ** To streams
106− , ReadUState
106+ , ReadUState(..)
108 , readRev
108 , readRev
@@ -212,7 +212,6 @@ import Control.DeepSeq (NFData(..))
212import Control.Monad (when, void)
212import Control.Monad (when, void)
213import Control.Monad.IO.Class (MonadIO(..))
213import Control.Monad.IO.Class (MonadIO(..))
214import Data.Bits ((.&.))
214import Data.Bits ((.&.))
215−import Data.Functor.Identity (Identity(runIdentity))
216#if __GLASGOW_HASKELL__ < 808
215#if __GLASGOW_HASKELL__ < 808
217import Data.Semigroup (Semigroup(..))
216import Data.Semigroup (Semigroup(..))
@@ -225,7 +224,7 @@ import Foreign.Marshal.Alloc (mallocBytes)
225import Foreign.Ptr (plusPtr, minusPtr, castPtr, nullPtr)
224import Foreign.Ptr (plusPtr, minusPtr, castPtr, nullPtr)
226import Foreign.Storable (Storable(..))
225import Foreign.Storable (Storable(..))
227import GHC.Base
226import GHC.Base
228− ( build, touch#, IO(..), byteArrayContents#
227+ ( touch#, IO(..), byteArrayContents#
229 , Int(..), newAlignedPinnedByteArray#
228 , Int(..), newAlignedPinnedByteArray#
231#ifndef USE_FOREIGN_PTR
230#ifndef USE_FOREIGN_PTR
@@ -248,8 +247,7 @@ import Streamly.Internal.Data.Fold.Type (Fold(..))
248import Streamly.Internal.Data.Producer.Type (Producer (..))
247import Streamly.Internal.Data.Producer.Type (Producer (..))
249import Streamly.Internal.Data.SVar.Type (adaptState)
248import Streamly.Internal.Data.SVar.Type (adaptState)
250import Streamly.Internal.Data.Unfold.Type (Unfold(..))
249import Streamly.Internal.Data.Unfold.Type (Unfold(..))
251−import Streamly.Internal.System.IO
250+import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
252− (defaultChunkSize, arrayPayloadSize, unsafeInlineIO)
253import System.IO.Unsafe (unsafePerformIO)
251import System.IO.Unsafe (unsafePerformIO)
255#ifdef DEVBUILD
253#ifdef DEVBUILD
@@ -1371,24 +1369,18 @@ toReadUState (Array contents start end _) = ReadUState contents end start
1371-- | Resumable unfold of an array.
1369-- | Resumable unfold of an array.
1373{-# INLINE_NORMAL producer #-}
1371{-# INLINE_NORMAL producer #-}
1374−producer :: forall m a. (Monad m, Storable a) => Producer m (Array a) a
1372+producer :: forall m a. (MonadIO m, Storable a) => Producer m (Array a) a
1375producer = Producer step (return . toReadUState) extract
1373producer = Producer step (return . toReadUState) extract
1378 {-# INLINE_LATE step #-}
1376 {-# INLINE_LATE step #-}
1379 step (ReadUState contents end cur)
1377 step (ReadUState contents end cur)
1380− | assert (cur <= end) (cur == end) =
1378+ | assert (cur <= end) (cur == end) = do
1381− let x = unsafeInlineIO $ touch contents
1379+ liftIO $ touch contents
1382− in x `seq` return D.Stop
1380+ return D.Stop
1383 step (ReadUState contents end cur) = do
1381 step (ReadUState contents end cur) = do
1384− -- unsafeInlineIO allows us to run this in Identity monad for pure
1385− -- toList/foldr case which makes them much faster due to not
1386− -- accumulating the list and fusing better with the pure consumers.
1388− -- This should be safe as the array contents are guaranteed to be
1389− -- evaluated/written to before we peek at them.
1390− let !x = unsafeInlineIO $ peek cur
1382+ !x <- liftIO $ peek cur
1391− cur1 = cur `plusPtr` sizeOf (undefined :: a)
1383+ let cur1 = cur `plusPtr` sizeOf (undefined :: a)
1392 return $ D.Yield x (ReadUState contents end cur1)
1384 return $ D.Yield x (ReadUState contents end cur1)
1394 extract (ReadUState contents end cur) = return $ Array contents cur end end
1386 extract (ReadUState contents end cur) = return $ Array contents cur end end
@@ -1397,14 +1389,14 @@ producer = Producer step (return . toReadUState) extract
1398-- @since 0.7.0
1390-- @since 0.7.0
1399{-# INLINE_NORMAL read #-}
1391{-# INLINE_NORMAL read #-}
1400−read :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
1392+read :: forall m a. (MonadIO m, Storable a) => Unfold m (Array a) a
1401read = Producer.simplify producer
1393read = Producer.simplify producer
1403-- | Unfold an array into a stream in reverse order.
1395-- | Unfold an array into a stream in reverse order.
1405-- /Pre-release/
1397-- /Pre-release/
1406{-# INLINE_NORMAL readRev #-}
1398{-# INLINE_NORMAL readRev #-}
1407−readRev :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
1399+readRev :: forall m a. (MonadIO m, Storable a) => Unfold m (Array a) a
1408readRev = Unfold step inject
1400readRev = Unfold step inject
@@ -1413,17 +1405,11 @@ readRev = Unfold step inject
1413 in return $ ReadUState contents start p
1405 in return $ ReadUState contents start p
1415 {-# INLINE_LATE step #-}
1407 {-# INLINE_LATE step #-}
1416− step (ReadUState contents start p) | p < start =
1408+ step (ReadUState contents start p) | p < start = do
1417− let x = unsafeInlineIO $ touch contents
1409+ liftIO $ touch contents
1418− in x `seq` return D.Stop
1410+ return D.Stop
1419 step (ReadUState contents start p) = do
1411 step (ReadUState contents start p) = do
1420− -- unsafeInlineIO allows us to run this in Identity monad for pure
1412+ x <- liftIO $ peek p
1421− -- toList/foldr case which makes them much faster due to not
1422− -- accumulating the list and fusing better with the pure consumers.
1424− -- This should be safe as the array contents are guaranteed to be
1425− -- evaluated/written to before we peek at them.
1426− let !x = unsafeInlineIO $ peek p
1427 let cur = p `plusPtr` negate (sizeOf (undefined :: a))
1413 let cur = p `plusPtr` negate (sizeOf (undefined :: a))
1428 return $ D.Yield x (ReadUState contents start cur)
1414 return $ D.Yield x (ReadUState contents start cur)
@@ -1431,6 +1417,7 @@ readRev = Unfold step inject
1431-- to Lists and streams
1417-- to Lists and streams
1432-------------------------------------------------------------------------------
1418-------------------------------------------------------------------------------
1434-- Use foldr/build fusion to fuse with list consumers
1421-- Use foldr/build fusion to fuse with list consumers
1435-- This can be useful when using the IsList instance
1422-- This can be useful when using the IsList instance
1436{-# INLINE_LATE toListFB #-}
1423{-# INLINE_LATE toListFB #-}
@@ -1452,14 +1439,23 @@ toListFB c n Array{..} = go arrStart
1452 touch arrContents
1439 touch arrContents
1453 return r
1440 return r
1454 in c x (go (p `plusPtr` sizeOf (undefined :: a)))
1441 in c x (go (p `plusPtr` sizeOf (undefined :: a)))
1456−-- XXX Should be monadic
1444+-- XXX Monadic foldr/build fusion?
1445+-- Reference: https://www.researchgate.net/publication/220676509_Monadic_augment_and_generalised_short_cut_fusion
1457-- | Convert an 'Array' into a list.
1446-- | Convert an 'Array' into a list.
1459-- @since 0.7.0
1448-- @since 0.7.0
1460{-# INLINE toList #-}
1449{-# INLINE toList #-}
1461−toList :: Storable a => Array a -> [a]
1450+toList :: forall m a. (MonadIO m, Storable a) => Array a -> m [a]
1462−toList s = build (\c n -> toListFB c n s)
1451+toList Array{..} = liftIO $ go arrStart
1454+ go p | assert (p <= aEnd) (p == aEnd) = return []
1458+ (:) x <$> go (p `plusPtr` sizeOf (undefined :: a))
1464-- | Use the 'read' unfold instead.
1460-- | Use the 'read' unfold instead.
@@ -1467,48 +1463,31 @@ toList s = build (\c n -> toListFB c n s)
1468-- We can try this if the unfold has any performance issues.
1464-- We can try this if the unfold has any performance issues.
1469{-# INLINE_NORMAL toStreamD #-}
1465{-# INLINE_NORMAL toStreamD #-}
1470−toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
1466+toStreamD :: forall m a. (MonadIO m, Storable a) => Array a -> D.Stream m a
1471−toStreamD Array{..} =
1467+toStreamD Array{..} = D.Stream step arrStart
1477 {-# INLINE_LATE step #-}
1471 {-# INLINE_LATE step #-}
1478 step _ p | assert (p <= aEnd) (p == aEnd) = return D.Stop
1472 step _ p | assert (p <= aEnd) (p == aEnd) = return D.Stop
1479− step _ p = do
1473+ step _ p = liftIO $ do
1480− -- unsafeInlineIO allows us to run this in Identity monad for pure
1481− -- toList/foldr case which makes them much faster due to not
1482− -- accumulating the list and fusing better with the pure consumers.
1484− -- This should be safe as the array contents are guaranteed to be
1485− -- evaluated/written to before we peek at them.
1487− -- XXX This may not be safe for mutable arrays.
1489− let !x = unsafeInlineIO $ do
1490− r <- peek p
1474+ r <- peek p
1491− touch arrContents
1475+ touch arrContents
1493− return $ D.Yield x (p `plusPtr` sizeOf (undefined :: a))
1476+ return $ D.Yield r (p `plusPtr` sizeOf (undefined :: a))
1495{-# INLINE toStreamK #-}
1478{-# INLINE toStreamK #-}
1496−toStreamK :: forall m a. Storable a => Array a -> K.Stream m a
1479+toStreamK :: forall m a. (MonadIO m, Storable a) => Array a -> K.Stream m a
1497−toStreamK Array{..} =
1480+toStreamK Array{..} = go arrStart
1503 go p | assert (p <= aEnd) (p == aEnd) = K.nil
1484 go p | assert (p <= aEnd) (p == aEnd) = K.nil
1504 | otherwise =
1485 | otherwise =
1505− -- See Note in toStreamD.
1486+ let elemM = do
1506− -- XXX May not be safe for mutable arrays.
1507− let !x = unsafeInlineIO $ do
1508− r <- peek p
1487+ r <- peek p
1509− touch arrContents
1488+ touch arrContents
1510− return r
1489+ return r
1511− in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
1490+ in liftIO elemM `K.consM` go (p `plusPtr` sizeOf (undefined :: a))
1513-- | Use the 'readRev' unfold instead.
1492-- | Use the 'readRev' unfold instead.
@@ -1516,7 +1495,7 @@ toStreamK Array{..} =
1517-- We can try this if the unfold has any perf issues.
1496-- We can try this if the unfold has any perf issues.
1518{-# INLINE_NORMAL toStreamDRev #-}
1497{-# INLINE_NORMAL toStreamDRev #-}
1519−toStreamDRev :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
1498+toStreamDRev :: forall m a. (MonadIO m, Storable a) => Array a -> D.Stream m a
1520toStreamDRev Array{..} =
1499toStreamDRev Array{..} =
1521 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
1500 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
1522 in D.Stream step p
1501 in D.Stream step p
@@ -1525,17 +1504,13 @@ toStreamDRev Array{..} =
1526 {-# INLINE_LATE step #-}
1505 {-# INLINE_LATE step #-}
1527 step _ p | p < arrStart = return D.Stop
1506 step _ p | p < arrStart = return D.Stop
1528− step _ p = do
1507+ step _ p = liftIO $ do
1529− -- See comments in toStreamD for why we use unsafeInlineIO
1531− let !x = unsafeInlineIO $ do
1532− r <- peek p
1508+ r <- peek p
1533− touch arrContents
1509+ touch arrContents
1535− return $ D.Yield x (p `plusPtr` negate (sizeOf (undefined :: a)))
1510+ return $ D.Yield r (p `plusPtr` negate (sizeOf (undefined :: a)))
1537{-# INLINE toStreamKRev #-}
1512{-# INLINE toStreamKRev #-}
1538−toStreamKRev :: forall m a. Storable a => Array a -> K.Stream m a
1513+toStreamKRev :: forall m a. (MonadIO m, Storable a) => Array a -> K.Stream m a
1539toStreamKRev Array {..} =
1514toStreamKRev Array {..} =
1540 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
1515 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
@@ -1544,12 +1519,11 @@ toStreamKRev Array {..} =
1545 go p | p < arrStart = K.nil
1520 go p | p < arrStart = K.nil
1546 | otherwise =
1521 | otherwise =
1547− -- XXX
1522+ let elemM = do
1548− let !x = unsafeInlineIO $ do
1549− r <- peek p
1523+ r <- peek p
1550− touch arrContents
1524+ touch arrContents
1551− return r
1525+ return r
1552− in x `K.cons` go (p `plusPtr` negate (sizeOf (undefined :: a)))
1526+ in liftIO elemM `K.consM` go (p `plusPtr` negate (sizeOf (undefined :: a)))
1554-------------------------------------------------------------------------------
1528-------------------------------------------------------------------------------
1555-- Folding
1529-- Folding
@@ -1560,15 +1534,13 @@ toStreamKRev Array {..} =
1561-- | Strict left fold of an array.
1535-- | Strict left fold of an array.
1562{-# INLINE_NORMAL foldl' #-}
1536{-# INLINE_NORMAL foldl' #-}
1563−foldl' :: forall a b. Storable a => (b -> a -> b) -> b -> Array a -> b
1537+foldl' :: (MonadIO m, Storable a) => (b -> a -> b) -> b -> Array a -> m b
1564−-- XXX Should be monadic
1565−foldl' f z arr = runIdentity $ D.foldl' f z $ toStreamD arr
1538+foldl' f z arr = D.foldl' f z $ toStreamD arr
1567-- | Right fold of an array.
1540-- | Right fold of an array.
1568{-# INLINE_NORMAL foldr #-}
1541{-# INLINE_NORMAL foldr #-}
1569−-- XXX Should be monadic
1570−foldr :: Storable a => (a -> b -> b) -> b -> Array a -> b
1542+foldr :: (MonadIO m, Storable a) => (a -> b -> b) -> b -> Array a -> m b
1571−foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
1543+foldr f z arr = D.foldr f z $ toStreamD arr
1573-------------------------------------------------------------------------------
1545-------------------------------------------------------------------------------