@@ -1,3 +1,4 @@
1+{-# LANGUAGE UnboxedTuples #-}
2-- Module : Streamly.Internal.Data.Array.Foreign.Mut.Type
3-- Module : Streamly.Internal.Data.Array.Foreign.Mut.Type
3-- Copyright : (c) 2020 Composewell Technologies
4-- Copyright : (c) 2020 Composewell Technologies
@@ -16,6 +17,12 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
17 -- $arrayNotes
18 -- $arrayNotes
18 Array (..)
19 Array (..)
21+ , arrayToFptrContents
22+ , fptrToArrayContents
23+ , unsafeWithArrayContents
20 -- * Constructing and Writing
27 -- * Constructing and Writing
21 -- ** Construction
28 -- ** Construction
@@ -196,6 +203,10 @@ where
197#include "inline.hs"
204#include "inline.hs"
207+#define USE_FOREIGN_PTR
199import Control.Exception (assert)
210import Control.Exception (assert)
200import Control.DeepSeq (NFData(..))
211import Control.DeepSeq (NFData(..))
201import Control.Monad (when, void)
212import Control.Monad (when, void)
@@ -207,17 +218,29 @@ import Data.Semigroup (Semigroup(..))
208import Data.Word (Word8)
219import Data.Word (Word8)
209import Foreign.C.Types (CSize(..), CInt(..))
220import Foreign.C.Types (CSize(..), CInt(..))
210−import Foreign.ForeignPtr (touchForeignPtr, castForeignPtr)
211import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
221import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
222+#ifndef USE_FOREIGN_PTR
223+import Foreign.Marshal.Alloc (mallocBytes)
212import Foreign.Ptr (plusPtr, minusPtr, castPtr, nullPtr)
225import Foreign.Ptr (plusPtr, minusPtr, castPtr, nullPtr)
213import Foreign.Storable (Storable(..))
226import Foreign.Storable (Storable(..))
214−import GHC.Base (build)
227+import GHC.Base
228+ ( build, touch#, IO(..), byteArrayContents#
229+ , Int(..), newAlignedPinnedByteArray#
231+#ifndef USE_FOREIGN_PTR
232+import GHC.Base (RealWorld, MutableByteArray#)
215#if __GLASGOW_HASKELL__ < 802
234#if __GLASGOW_HASKELL__ < 802
216#define noinline
235#define noinline
218import GHC.Base (noinline)
237import GHC.Base (noinline)
239+import GHC.Exts (unsafeCoerce#)
220−import GHC.ForeignPtr (ForeignPtr(..))
240+import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents(..))
242+import GHC.ForeignPtr (mallocForeignPtrAlignedBytes)
221import GHC.Ptr (Ptr(..))
244import GHC.Ptr (Ptr(..))
223import Streamly.Internal.BaseCompat
246import Streamly.Internal.BaseCompat
@@ -225,9 +248,9 @@ import Streamly.Internal.Data.Fold.Type (Fold(..))
225import Streamly.Internal.Data.Producer.Type (Producer (..))
248import Streamly.Internal.Data.Producer.Type (Producer (..))
226import Streamly.Internal.Data.SVar.Type (adaptState)
249import Streamly.Internal.Data.SVar.Type (adaptState)
227import Streamly.Internal.Data.Unfold.Type (Unfold(..))
250import Streamly.Internal.Data.Unfold.Type (Unfold(..))
229import Streamly.Internal.System.IO
251import Streamly.Internal.System.IO
230 (defaultChunkSize, arrayPayloadSize, unsafeInlineIO)
252 (defaultChunkSize, arrayPayloadSize, unsafeInlineIO)
253+import System.IO.Unsafe (unsafePerformIO)
232#ifdef DEVBUILD
255#ifdef DEVBUILD
233import qualified Data.Foldable as F
256import qualified Data.Foldable as F
@@ -236,20 +259,13 @@ import qualified Streamly.Internal.Data.Fold.Type as FL
236import qualified Streamly.Internal.Data.Producer as Producer
259import qualified Streamly.Internal.Data.Producer as Producer
237import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
260import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
238import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
261import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
262+#ifdef USE_FOREIGN_PTR
239import qualified Streamly.Internal.Foreign.Malloc as Malloc
263import qualified Streamly.Internal.Foreign.Malloc as Malloc
241import Prelude hiding
266import Prelude hiding
242 (length, foldr, read, unlines, splitAt, reverse, truncate)
267 (length, foldr, read, unlines, splitAt, reverse, truncate)
244−#if MIN_VERSION_base(4,10,0)
245−import Foreign.ForeignPtr (plusForeignPtr)
247−import GHC.Base (Int(..), plusAddr#)
248−import GHC.ForeignPtr (ForeignPtr(..))
249−plusForeignPtr :: ForeignPtr a -> Int -> ForeignPtr b
250−plusForeignPtr (ForeignPtr addr c) (I# d) = ForeignPtr (plusAddr# addr d) c
255-- >>> import qualified Streamly.Internal.Data.Array.Foreign.Mut.Type as Array
271-- >>> import qualified Streamly.Internal.Data.Array.Foreign.Mut.Type as Array
@@ -292,12 +308,44 @@ memcmp p1 p2 len = do
292 r <- c_memcmp p1 p2 (fromIntegral len)
308 r <- c_memcmp p1 p2 (fromIntegral len)
293 return $ r == 0
309 return $ r == 0
295−-- | Same as unsafeWithForeignPtr but lifted to any MonadIO monad.
311+-------------------------------------------------------------------------------
296−{-# INLINE unsafeWithForeignPtrM #-}
312+-- Array Contents
297−unsafeWithForeignPtrM :: MonadIO m => ForeignPtr a -> (Ptr a -> m b) -> m b
313+-------------------------------------------------------------------------------
298−unsafeWithForeignPtrM fo f = do
314+
299− r <- f (unsafeForeignPtrToPtr fo)
315+-- We support using ForeignPtrContents or MutableByteArray.
300− liftIO $ touchForeignPtr fo
316+
317+#ifdef USE_FOREIGN_PTR
318+newtype ArrayContents = ArrayContents ForeignPtrContents
321+-- XXX can use UnliftedNewtypes
322+data ArrayContents = ArrayContents !(MutableByteArray# RealWorld)
323+#define UNPACKIF {-# UNPACK #-}
327+touch :: ArrayContents -> IO ()
328+touch (ArrayContents contents) =
329+ IO $ \s -> case touch# contents s of s' -> (# s', () #)
331+fptrToArrayContents :: ForeignPtrContents -> ArrayContents
332+arrayToFptrContents :: ArrayContents -> ForeignPtrContents
333+#ifdef USE_FOREIGN_PTR
334+fptrToArrayContents = ArrayContents
335+arrayToFptrContents (ArrayContents contents) = contents
337+fptrToArrayContents (PlainPtr mbarr) = ArrayContents mbarr
338+fptrToArrayContents _ = error "Unsupported foreign ptr"
339+arrayToFptrContents (ArrayContents contents) = PlainPtr contents
342+-- | Similar to unsafeWithForeignPtr.
343+{-# INLINE unsafeWithArrayContents #-}
344+unsafeWithArrayContents :: MonadIO m =>
345+ ArrayContents -> Ptr a -> (Ptr a -> m b) -> m b
346+unsafeWithArrayContents contents ptr f = do
348+ liftIO $ touch contents
303-------------------------------------------------------------------------------
351-------------------------------------------------------------------------------
@@ -335,7 +383,8 @@ data Array a =
335 Storable a =>
383 Storable a =>
386+ { arrContents :: UNPACKIF !ArrayContents
338− { aStart :: {-# UNPACK #-} !(ForeignPtr a) -- ^ first address
387+ , arrStart :: {-# UNPACK #-} !(Ptr a) -- ^ first address
339 , aEnd :: {-# UNPACK #-} !(Ptr a) -- ^ first unused address
388 , aEnd :: {-# UNPACK #-} !(Ptr a) -- ^ first unused address
340 , aBound :: {-# UNPACK #-} !(Ptr a) -- ^ first address beyond allocated memory
389 , aBound :: {-# UNPACK #-} !(Ptr a) -- ^ first address beyond allocated memory
@@ -345,7 +394,8 @@ data Array a =
345-- address, and @bound@ is the first address beyond the allocated memory.
394-- address, and @bound@ is the first address beyond the allocated memory.
347-- Unsafe: Make sure that foreignPtr <= end <= bound and (end - start) is an
396-- Unsafe: Make sure that foreignPtr <= end <= bound and (end - start) is an
348−-- integral multiple of the element size.
397+-- integral multiple of the element size. Only PlainPtr type ForeignPtr is
350-- /Pre-release/
400-- /Pre-release/
@@ -355,9 +405,9 @@ fromForeignPtrUnsafe ::
355 Storable a =>
405 Storable a =>
357 ForeignPtr a -> Ptr a -> Ptr a -> Array a
407 ForeignPtr a -> Ptr a -> Ptr a -> Array a
358−fromForeignPtrUnsafe fp end bound =
408+fromForeignPtrUnsafe fp@(ForeignPtr start contents) end bound =
359 assert (unsafeForeignPtrToPtr fp <= end && end <= bound)
409 assert (unsafeForeignPtrToPtr fp <= end && end <= bound)
360− (Array fp end bound)
410+ (Array (fptrToArrayContents contents) (Ptr start) end bound)
362-------------------------------------------------------------------------------
412-------------------------------------------------------------------------------
363-- Construction
413-- Construction
@@ -385,17 +435,42 @@ fromForeignPtrUnsafe fp end bound =
385-- /Pre-release/
435-- /Pre-release/
386{-# INLINE newArrayWith #-}
436{-# INLINE newArrayWith #-}
387newArrayWith :: forall m a. (MonadIO m, Storable a)
437newArrayWith :: forall m a. (MonadIO m, Storable a)
388− => (Int -> Int -> m (ForeignPtr a)) -> Int -> Int -> m (Array a)
438+ => (Int -> Int -> m (ArrayContents, Ptr a)) -> Int -> Int -> m (Array a)
389newArrayWith alloc alignSize count = do
439newArrayWith alloc alignSize count = do
390 let size = max (count * sizeOf (undefined :: a)) 0
440 let size = max (count * sizeOf (undefined :: a)) 0
391− fptr <- alloc size alignSize
441+ (contents, p) <- alloc size alignSize
392− let p = unsafeForeignPtrToPtr fptr
393 return $ Array
442 return $ Array
394− { aStart = fptr
443+ { arrContents = contents
395 , aEnd = p
445 , aEnd = p
396 , aBound = p `plusPtr` size
446 , aBound = p `plusPtr` size
449+newAlignedArrayContents :: Int -> Int -> IO (ArrayContents, Ptr a)
451+newAlignedArrayContents size align = do
452+ ForeignPtr addr contents = mallocForeignPtrAlignedBytes size align
453+ return (ArrayContents contents, Ptr addr)
455+newAlignedArrayContents size _align | size < 0 =
456+ errorWithoutStackTrace "newAlignedArrayContents: size must be >= 0"
457+newAlignedArrayContents (I# size) (I# align) = IO $ \s ->
458+ case newAlignedPinnedByteArray# size align s of
460+ let p = Ptr (byteArrayContents# (unsafeCoerce# mbarr#))
461+#ifdef USE_FOREIGN_PTR
462+ c = ArrayContents (PlainPtr mbarr#)
464+ c = ArrayContents mbarr#
469+{-# NOINLINE nilArrayContents #-}
470+nilArrayContents :: ArrayContents
472+ fst $ unsafePerformIO $ newAlignedArrayContents 0 0
399-- | Like 'newArrayWith' but using an allocator that allocates unmanaged pinned
474-- | Like 'newArrayWith' but using an allocator that allocates unmanaged pinned
400-- memory. The memory will never be freed by GHC. This could be useful in
475-- memory. The memory will never be freed by GHC. This could be useful in
401-- allocate-once global data structures. Use carefully as incorrect use can
476-- allocate-once global data structures. Use carefully as incorrect use can
@@ -403,14 +478,29 @@ newArrayWith alloc alignSize count = do
404-- /Internal/
479-- /Internal/
405{-# INLINE newArrayAlignedUnmanaged #-}
480{-# INLINE newArrayAlignedUnmanaged #-}
406−newArrayAlignedUnmanaged :: (MonadIO m, Storable a) =>
481+newArrayAlignedUnmanaged :: forall m a. (MonadIO m, Storable a) =>
407 Int -> Int -> m (Array a)
482 Int -> Int -> m (Array a)
483+#ifdef USE_FOREIGN_PTR
484+newArrayAlignedUnmanaged = do
408−newArrayAlignedUnmanaged = newArrayWith mallocForeignPtrAlignedUnmanagedBytes
485+ newArrayWith mallocForeignPtrAlignedUnmanagedBytes
412− mallocForeignPtrAlignedUnmanagedBytes size alignSize =
489+ mallocForeignPtrAlignedUnmanagedBytes size align = do
490+ ForeignPtr addr contents <-
413− liftIO $ Malloc.mallocForeignPtrAlignedUnmanagedBytes size alignSize
491+ liftIO $ Malloc.mallocForeignPtrAlignedUnmanagedBytes size align
492+ return (ArrayContents contents, Ptr addr)
494+newArrayAlignedUnmanaged _align count = do
495+ let size = max (count * sizeOf (undefined :: a)) 0
496+ p <- liftIO $ mallocBytes size
498+ { arrContents = nilArrayContents
501+ , aBound = p `plusPtr` size
415-- | Like 'newArrayWith' but using an allocator that aligns the memory to the
505-- | Like 'newArrayWith' but using an allocator that aligns the memory to the
416-- alignment dictated by the 'Storable' instance of the type.
506-- alignment dictated by the 'Storable' instance of the type.
@@ -418,12 +508,7 @@ newArrayAlignedUnmanaged = newArrayWith mallocForeignPtrAlignedUnmanagedBytes
418-- /Internal/
508-- /Internal/
419{-# INLINE newArrayAligned #-}
509{-# INLINE newArrayAligned #-}
420newArrayAligned :: (MonadIO m, Storable a) => Int -> Int -> m (Array a)
510newArrayAligned :: (MonadIO m, Storable a) => Int -> Int -> m (Array a)
421−newArrayAligned = newArrayWith mallocForeignPtrAlignedBytes
511+newArrayAligned = newArrayWith (\s a -> liftIO $ newAlignedArrayContents s a)
425− mallocForeignPtrAlignedBytes size alignSize =
426− liftIO $ Malloc.mallocForeignPtrAlignedBytes size alignSize
428-- XXX can unaligned allocation be more efficient when alignment is not needed?
513-- XXX can unaligned allocation be more efficient when alignment is not needed?
@@ -445,7 +530,8 @@ withNewArrayUnsafe ::
445 (MonadIO m, Storable a) => Int -> (Ptr a -> m ()) -> m (Array a)
530 (MonadIO m, Storable a) => Int -> (Ptr a -> m ()) -> m (Array a)
446withNewArrayUnsafe count f = do
531withNewArrayUnsafe count f = do
447 arr <- newArray count
532 arr <- newArray count
533+ unsafeWithArrayContents (arrContents arr) (arrStart arr)
448− unsafeWithForeignPtrM (aStart arr) $ \p -> f p >> return arr
534+ $ \p -> f p >> return arr
450-------------------------------------------------------------------------------
536-------------------------------------------------------------------------------
451-- Random writes
537-- Random writes
@@ -467,7 +553,7 @@ putIndices = undefined
467putIndexUnsafe :: forall m a. (MonadIO m, Storable a)
553putIndexUnsafe :: forall m a. (MonadIO m, Storable a)
468 => Array a -> Int -> a -> m ()
554 => Array a -> Int -> a -> m ()
469putIndexUnsafe Array{..} i x =
555putIndexUnsafe Array{..} i x =
470− unsafeWithForeignPtrM aStart $ \ptr -> do
556+ unsafeWithArrayContents arrContents arrStart $ \ptr -> do
471 let elemSize = sizeOf (undefined :: a)
557 let elemSize = sizeOf (undefined :: a)
472 elemPtr = ptr `plusPtr` (elemSize * i)
558 elemPtr = ptr `plusPtr` (elemSize * i)
473 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
559 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
@@ -498,7 +584,8 @@ putIndexPtr ptr end i x = do
498{-# INLINE putIndex #-}
584{-# INLINE putIndex #-}
499putIndex :: (MonadIO m, Storable a) => Array a -> Int -> a -> m ()
585putIndex :: (MonadIO m, Storable a) => Array a -> Int -> a -> m ()
500putIndex arr i x =
586putIndex arr i x =
587+ unsafeWithArrayContents (arrContents arr) (arrStart arr)
501− unsafeWithForeignPtrM (aStart arr) $ \p -> putIndexPtr p (aEnd arr) i x
588+ $ \p -> putIndexPtr p (aEnd arr) i x
503-- | Modify a given index of an array using a modifier function.
590-- | Modify a given index of an array using a modifier function.
@@ -506,7 +593,7 @@ putIndex arr i x =
506modifyIndexUnsafe :: forall m a b. (MonadIO m, Storable a) =>
593modifyIndexUnsafe :: forall m a b. (MonadIO m, Storable a) =>
507 Array a -> Int -> (a -> (a, b)) -> m b
594 Array a -> Int -> (a -> (a, b)) -> m b
508modifyIndexUnsafe Array{..} i f = do
595modifyIndexUnsafe Array{..} i f = do
509− liftIO $ unsafeWithForeignPtr aStart $ \ptr -> do
596+ liftIO $ unsafeWithArrayContents arrContents arrStart $ \ptr -> do
510 let elemSize = sizeOf (undefined :: a)
597 let elemSize = sizeOf (undefined :: a)
511 elemPtr = ptr `plusPtr` (elemSize * i)
598 elemPtr = ptr `plusPtr` (elemSize * i)
512 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
599 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
@@ -521,7 +608,7 @@ modifyIndexUnsafe Array{..} i f = do
521modifyIndex :: forall m a b. (MonadIO m, Storable a) =>
608modifyIndex :: forall m a b. (MonadIO m, Storable a) =>
522 Array a -> Int -> (a -> (a, b)) -> m b
609 Array a -> Int -> (a -> (a, b)) -> m b
523modifyIndex Array{..} i f = do
610modifyIndex Array{..} i f = do
524− liftIO $ unsafeWithForeignPtr aStart $ \ptr -> do
611+ liftIO $ unsafeWithArrayContents arrContents arrStart $ \ptr -> do
525 let elemSize = sizeOf (undefined :: a)
612 let elemSize = sizeOf (undefined :: a)
526 elemPtr = ptr `plusPtr` (elemSize * i)
613 elemPtr = ptr `plusPtr` (elemSize * i)
527 if i >= 0 && elemPtr `plusPtr` elemSize <= aEnd
614 if i >= 0 && elemPtr `plusPtr` elemSize <= aEnd
@@ -635,7 +722,7 @@ snocNewEnd :: (MonadIO m, Storable a) => Ptr a -> Array a -> a -> m (Array a)
635snocNewEnd newEnd arr@Array{..} x = liftIO $ do
722snocNewEnd newEnd arr@Array{..} x = liftIO $ do
636 assert (newEnd <= aBound) (return ())
723 assert (newEnd <= aBound) (return ())
637 poke aEnd x
724 poke aEnd x
638− touchForeignPtr aStart
725+ touch arrContents
639 return $ arr {aEnd = newEnd}
726 return $ arr {aEnd = newEnd}
641-- | Really really unsafe, appends the element into the first array, may
728-- | Really really unsafe, appends the element into the first array, may
@@ -669,7 +756,7 @@ reallocWith :: forall m a. (MonadIO m , Storable a) =>
669 -> Array a
756 -> Array a
670 -> m (Array a)
757 -> m (Array a)
671reallocWith label sizer reqSize arr = do
758reallocWith label sizer reqSize arr = do
672− let oldSize = aEnd arr `minusPtr` unsafeForeignPtrToPtr (aStart arr)
759+ let oldSize = aEnd arr `minusPtr` arrStart arr
673 newSize = sizer oldSize
760 newSize = sizer oldSize
674 safeSize = max newSize (oldSize + reqSize)
761 safeSize = max newSize (oldSize + reqSize)
675 rounded = roundUpLargeArray safeSize
762 rounded = roundUpLargeArray safeSize
@@ -767,21 +854,21 @@ snoc = snocWith (* 2)
767reallocAligned :: Int -> Int -> Int -> Array a -> IO (Array a)
854reallocAligned :: Int -> Int -> Int -> Array a -> IO (Array a)
768reallocAligned elemSize alignSize newSize Array{..} = do
855reallocAligned elemSize alignSize newSize Array{..} = do
769 assert (aEnd <= aBound) (return ())
856 assert (aEnd <= aBound) (return ())
770− let oldStart = unsafeForeignPtrToPtr aStart
857+ let oldStart = arrStart
771 oldSize = aEnd `minusPtr` oldStart
858 oldSize = aEnd `minusPtr` oldStart
772 assert (oldSize `mod` elemSize == 0) (return ())
859 assert (oldSize `mod` elemSize == 0) (return ())
773− newPtr <- Malloc.mallocForeignPtrAlignedBytes newSize alignSize
860+ (contents, pNew) <- newAlignedArrayContents newSize alignSize
774− unsafeWithForeignPtr newPtr $ \pNew -> do
775− let size = min oldSize newSize
861+ let size = min oldSize newSize
776− assert (size >= 0) (return ())
862+ assert (size >= 0) (return ())
777− assert (size `mod` elemSize == 0) (return ())
863+ assert (size `mod` elemSize == 0) (return ())
778− memcpy (castPtr pNew) (castPtr oldStart) size
864+ memcpy (castPtr pNew) (castPtr oldStart) size
779− touchForeignPtr aStart
865+ touch arrContents
780− return $ Array
866+ return $ Array
781− { aStart = newPtr
867+ { arrStart = pNew
868+ , arrContents = contents
782− , aEnd = pNew `plusPtr` (size - (size `mod` elemSize))
869+ , aEnd = pNew `plusPtr` (size - (size `mod` elemSize))
783− , aBound = pNew `plusPtr` newSize
870+ , aBound = pNew `plusPtr` newSize
786{-# INLINABLE realloc #-}
873{-# INLINABLE realloc #-}
787realloc :: forall m a. (MonadIO m, Storable a) => Int -> Array a -> m (Array a)
874realloc :: forall m a. (MonadIO m, Storable a) => Int -> Array a -> m (Array a)
@@ -824,7 +911,7 @@ resizeExp = undefined
824rightSize :: forall m a. (MonadIO m, Storable a) => Array a -> m (Array a)
911rightSize :: forall m a. (MonadIO m, Storable a) => Array a -> m (Array a)
825rightSize arr@Array{..} = do
912rightSize arr@Array{..} = do
826 assert (aEnd <= aBound) (return ())
913 assert (aEnd <= aBound) (return ())
827− let start = unsafeForeignPtrToPtr aStart
914+ let start = arrStart
828 len = aEnd `minusPtr` start
915 len = aEnd `minusPtr` start
829 capacity = aBound `minusPtr` start
916 capacity = aBound `minusPtr` start
830 target = roundUpLargeArray len
917 target = roundUpLargeArray len
@@ -878,7 +965,7 @@ truncateExp = undefined
878{-# INLINE_NORMAL getIndexUnsafe #-}
965{-# INLINE_NORMAL getIndexUnsafe #-}
879getIndexUnsafe :: forall m a. (MonadIO m, Storable a) => Array a -> Int -> m a
966getIndexUnsafe :: forall m a. (MonadIO m, Storable a) => Array a -> Int -> m a
880getIndexUnsafe Array {..} i =
967getIndexUnsafe Array {..} i =
881− unsafeWithForeignPtrM aStart $ \ptr -> do
968+ unsafeWithArrayContents arrContents arrStart $ \ptr -> do
882 let elemSize = sizeOf (undefined :: a)
969 let elemSize = sizeOf (undefined :: a)
883 elemPtr = ptr `plusPtr` (elemSize * i)
970 elemPtr = ptr `plusPtr` (elemSize * i)
884 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
971 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
@@ -899,7 +986,8 @@ getIndexPtr ptr end i = do
899{-# INLINE getIndex #-}
986{-# INLINE getIndex #-}
900getIndex :: (MonadIO m, Storable a) => Array a -> Int -> m a
987getIndex :: (MonadIO m, Storable a) => Array a -> Int -> m a
901getIndex arr i =
988getIndex arr i =
989+ unsafeWithArrayContents (arrContents arr) (arrStart arr)
902− unsafeWithForeignPtrM (aStart arr) $ \p -> getIndexPtr p (aEnd arr) i
990+ $ \p -> getIndexPtr p (aEnd arr) i
904{-# INLINE getIndexPtrRev #-}
992{-# INLINE getIndexPtrRev #-}
905getIndexPtrRev :: forall m a. (MonadIO m, Storable a) =>
993getIndexPtrRev :: forall m a. (MonadIO m, Storable a) =>
@@ -919,9 +1007,11 @@ getIndexPtrRev ptr end i = do
919{-# INLINE getIndexRev #-}
1007{-# INLINE getIndexRev #-}
920getIndexRev :: (MonadIO m, Storable a) => Array a -> Int -> m a
1008getIndexRev :: (MonadIO m, Storable a) => Array a -> Int -> m a
921getIndexRev arr i =
1009getIndexRev arr i =
1010+ unsafeWithArrayContents (arrContents arr) (arrStart arr)
922− unsafeWithForeignPtrM (aStart arr) $ \p -> getIndexPtrRev p (aEnd arr) i
1011+ $ \p -> getIndexPtrRev p (aEnd arr) i
924−data GetIndicesState fp end st = GetIndicesState fp end st
1013+data GetIndicesState contents start end st =
1014+ GetIndicesState contents start end st
926-- | Given an unfold that generates array indices, read the elements on those
1016-- | Given an unfold that generates array indices, read the elements on those
927-- indices from the supplied Array. An error is thrown if an index is out of
1017-- indices from the supplied Array. An error is thrown if an index is out of
@@ -935,20 +1025,20 @@ getIndices (Unfold stepi injecti) = Unfold step inject
938− inject arr@(Array fp@(ForeignPtr _ _) (Ptr end) _) = do
1028+ inject arr@(Array contents start (Ptr end) _) = do
939 st <- injecti arr
1029 st <- injecti arr
940− return $ GetIndicesState fp (Ptr end) st
1030+ return $ GetIndicesState contents start (Ptr end) st
942 {-# INLINE_LATE step #-}
1032 {-# INLINE_LATE step #-}
943− step (GetIndicesState fp@(ForeignPtr start _) end st) = do
1033+ step (GetIndicesState contents start end st) = do
944 r <- stepi st
1034 r <- stepi st
945 case r of
1035 case r of
946 D.Yield i s -> do
1036 D.Yield i s -> do
947− x <- liftIO $ getIndexPtr (Ptr start) end i
1037+ x <- liftIO $ getIndexPtr start end i
948− return $ D.Yield x (GetIndicesState fp end s)
1038+ return $ D.Yield x (GetIndicesState contents start end s)
949− D.Skip s -> return $ D.Skip (GetIndicesState fp end s)
1039+ D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
950 D.Stop -> do
1040 D.Stop -> do
951− liftIO $ touchForeignPtr fp
1041+ liftIO $ touch contents
952 return D.Stop
1042 return D.Stop
954-------------------------------------------------------------------------------
1044-------------------------------------------------------------------------------
@@ -970,11 +1060,13 @@ getSliceUnsafe :: forall a. Storable a
970 -> Int -- ^ length of the slice
1060 -> Int -- ^ length of the slice
971 -> Array a
1061 -> Array a
972 -> Array a
1062 -> Array a
973−getSliceUnsafe index len (Array fp e _) =
1063+getSliceUnsafe index len (Array contents start e _) =
974 let size = sizeOf (undefined :: a)
1064 let size = sizeOf (undefined :: a)
975− fp1 = fp `plusForeignPtr` (index * size)
1065+ fp1 = start `plusPtr` (index * size)
976− end = unsafeForeignPtrToPtr fp1 `plusPtr` (len * size)
1066+ end = fp1 `plusPtr` (len * size)
977− in assert (index >= 0 && len >= 0 && end <= e) (Array fp1 end end)
1068+ (index >= 0 && len >= 0 && end <= e)
1069+ (Array contents fp1 end end)
979-- | /O(1)/ Slice an array in constant time. Throws an error if the slice
1071-- | /O(1)/ Slice an array in constant time. Throws an error if the slice
980-- extends out of the array bounds.
1072-- extends out of the array bounds.
@@ -986,12 +1078,12 @@ getSlice :: forall a. Storable a =>
986 -> Int -- ^ length of the slice
1078 -> Int -- ^ length of the slice
987 -> Array a
1079 -> Array a
988 -> Array a
1080 -> Array a
989−getSlice index len (Array fp e _) =
1081+getSlice index len (Array contents start e _) =
990 let size = sizeOf (undefined :: a)
1082 let size = sizeOf (undefined :: a)
991− fp1 = fp `plusForeignPtr` (index * size)
1083+ fp1 = start `plusPtr` (index * size)
992− end = unsafeForeignPtrToPtr fp1 `plusPtr` (len * size)
1084+ end = fp1 `plusPtr` (len * size)
993 in if index >= 0 && len >= 0 && end <= e
1085 in if index >= 0 && len >= 0 && end <= e
994− then Array fp1 end end
1086+ then Array contents fp1 end end
995 else error
1087 else error
996 $ "getSlice: invalid slice, index "
1088 $ "getSlice: invalid slice, index "
997 ++ show index ++ " length " ++ show len
1089 ++ show index ++ " length " ++ show len
@@ -1077,8 +1169,7 @@ mergeBy = undefined
1077{-# INLINE byteLength #-}
1169{-# INLINE byteLength #-}
1078byteLength :: Array a -> Int
1170byteLength :: Array a -> Int
1079byteLength Array{..} =
1171byteLength Array{..} =
1080− let p = unsafeForeignPtrToPtr aStart
1081− len = aEnd `minusPtr` p
1172+ let len = aEnd `minusPtr` arrStart
1082 in assert (len >= 0) len
1173 in assert (len >= 0) len
1084-- Note: try to avoid the use of length in performance sensitive internal
1175-- Note: try to avoid the use of length in performance sensitive internal
@@ -1106,8 +1197,7 @@ length arr =
1106{-# INLINE byteCapacity #-}
1197{-# INLINE byteCapacity #-}
1107byteCapacity :: Array a -> Int
1198byteCapacity :: Array a -> Int
1108byteCapacity Array{..} =
1199byteCapacity Array{..} =
1109− let p = unsafeForeignPtrToPtr aStart
1110− len = aBound `minusPtr` p
1200+ let len = aBound `minusPtr` arrStart
1111 in assert (len >= 0) len
1201 in assert (len >= 0) len
1113-- | The remaining capacity in the array for appending more elements without
1203-- | The remaining capacity in the array for appending more elements without
@@ -1124,10 +1214,11 @@ bytesFree Array{..} =
1124-- Streams of arrays - Creation
1214-- Streams of arrays - Creation
1125-------------------------------------------------------------------------------
1215-------------------------------------------------------------------------------
1127−data GroupState s start end bound
1217+data GroupState s contents start end bound
1128 = GroupStart s
1218 = GroupStart s
1129− | GroupBuffer s start end bound
1219+ | GroupBuffer s contents start end bound
1130− | GroupYield start end bound (GroupState s start end bound)
1221+ contents start end bound (GroupState s contents start end bound)
1131 | GroupFinish
1222 | GroupFinish
1133-- | @arraysOf n stream@ groups the input stream into a stream of
1224-- | @arraysOf n stream@ groups the input stream into a stream of
@@ -1155,10 +1246,10 @@ arraysOf n (D.Stream step state) =
1155 error $ "Streamly.Internal.Data.Array.Foreign.Mut.Type.arraysOf: "
1246 error $ "Streamly.Internal.Data.Array.Foreign.Mut.Type.arraysOf: "
1156 ++ "the size of arrays [" ++ show n
1247 ++ "the size of arrays [" ++ show n
1157 ++ "] must be a natural number"
1248 ++ "] must be a natural number"
1158− Array start end bound <- liftIO $ newArray n
1249+ Array contents start end bound <- liftIO $ newArray n
1159− return $ D.Skip (GroupBuffer st start end bound)
1250+ return $ D.Skip (GroupBuffer st contents start end bound)
1161− step' gst (GroupBuffer st start end bound) = do
1252+ step' gst (GroupBuffer st contents start end bound) = do
1162 r <- step (adaptState gst) st
1253 r <- step (adaptState gst) st
1163 case r of
1254 case r of
1164 D.Yield x s -> do
1255 D.Yield x s -> do
@@ -1166,13 +1257,18 @@ arraysOf n (D.Stream step state) =
1166 let end' = end `plusPtr` sizeOf (undefined :: a)
1257 let end' = end `plusPtr` sizeOf (undefined :: a)
1167 return $
1258 return $
1168 if end' >= bound
1259 if end' >= bound
1169− then D.Skip (GroupYield start end' bound (GroupStart s))
1262+ contents start end' bound (GroupStart s))
1170− else D.Skip (GroupBuffer s start end' bound)
1263+ else D.Skip (GroupBuffer s contents start end' bound)
1171− D.Skip s -> return $ D.Skip (GroupBuffer s start end bound)
1265+ return $ D.Skip (GroupBuffer s contents start end bound)
1172− D.Stop -> return $ D.Skip (GroupYield start end bound GroupFinish)
1268+ $ D.Skip (GroupYield contents start end bound GroupFinish)
1174− step' _ (GroupYield start end bound next) =
1270+ step' _ (GroupYield contents start end bound next) =
1175− return $ D.Yield (Array start end bound) next
1271+ return $ D.Yield (Array contents start end bound) next
1177 step' _ GroupFinish = return D.Stop
1273 step' _ GroupFinish = return D.Stop
@@ -1189,9 +1285,9 @@ arrayStreamKFromStreamD =
1189-- Streams of arrays - Flattening
1285-- Streams of arrays - Flattening
1190-------------------------------------------------------------------------------
1286-------------------------------------------------------------------------------
1192−data FlattenState s a =
1288+data FlattenState s contents a =
1193 OuterLoop s
1289 OuterLoop s
1194− | InnerLoop s !(ForeignPtr a) !(Ptr a) !(Ptr a)
1290+ | InnerLoop s contents !(Ptr a) !(Ptr a)
1196-- | Use the "read" unfold instead.
1292-- | Use the "read" unfold instead.
@@ -1211,20 +1307,19 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1211 r <- step (adaptState gst) st
1307 r <- step (adaptState gst) st
1212 return $ case r of
1308 return $ case r of
1213 D.Yield Array{..} s ->
1309 D.Yield Array{..} s ->
1214− let p = unsafeForeignPtrToPtr aStart
1215− in D.Skip (InnerLoop s aStart p aEnd)
1310+ D.Skip (InnerLoop s arrContents arrStart aEnd)
1216 D.Skip s -> D.Skip (OuterLoop s)
1311 D.Skip s -> D.Skip (OuterLoop s)
1217 D.Stop -> D.Stop
1312 D.Stop -> D.Stop
1219 step' _ (InnerLoop st _ p end) | assert (p <= end) (p == end) =
1314 step' _ (InnerLoop st _ p end) | assert (p <= end) (p == end) =
1220 return $ D.Skip $ OuterLoop st
1315 return $ D.Skip $ OuterLoop st
1222− step' _ (InnerLoop st startf p end) = do
1317+ step' _ (InnerLoop st contents p end) = do
1223 x <- liftIO $ do
1318 x <- liftIO $ do
1224 r <- peek p
1319 r <- peek p
1225− touchForeignPtr startf
1320+ touch contents
1226 return r
1321 return r
1227− return $ D.Yield x (InnerLoop st startf
1322+ return $ D.Yield x (InnerLoop st contents
1228 (p `plusPtr` sizeOf (undefined :: a)) end)
1323 (p `plusPtr` sizeOf (undefined :: a)) end)
1230-- | Use the "readRev" unfold instead.
1325-- | Use the "readRev" unfold instead.
@@ -1246,58 +1341,57 @@ flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1246 return $ case r of
1341 return $ case r of
1247 D.Yield Array{..} s ->
1342 D.Yield Array{..} s ->
1248 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
1343 let p = aEnd `plusPtr` negate (sizeOf (undefined :: a))
1249− -- XXX we do not need aEnd
1250− in D.Skip (InnerLoop s aStart p aEnd)
1344+ in D.Skip (InnerLoop s arrContents p arrStart)
1251 D.Skip s -> D.Skip (OuterLoop s)
1345 D.Skip s -> D.Skip (OuterLoop s)
1252 D.Stop -> D.Stop
1346 D.Stop -> D.Stop
1254− step' _ (InnerLoop st start p _) | p < unsafeForeignPtrToPtr start =
1348+ step' _ (InnerLoop st _ p start) | p < start =
1255 return $ D.Skip $ OuterLoop st
1349 return $ D.Skip $ OuterLoop st
1257− step' _ (InnerLoop st startf p end) = do
1351+ step' _ (InnerLoop st contents p start) = do
1258 x <- liftIO $ do
1352 x <- liftIO $ do
1259 r <- peek p
1353 r <- peek p
1260− touchForeignPtr startf
1354+ touch contents
1261 return r
1355 return r
1356+ let cur = p `plusPtr` negate (sizeOf (undefined :: a))
1262− return $ D.Yield x (InnerLoop st startf
1357+ return $ D.Yield x (InnerLoop st contents cur start)
1263− (p `plusPtr` negate (sizeOf (undefined :: a))) end)
1265-------------------------------------------------------------------------------
1359-------------------------------------------------------------------------------
1266-- Unfolds
1360-- Unfolds
1267-------------------------------------------------------------------------------
1361-------------------------------------------------------------------------------
1269data ReadUState a = ReadUState
1363data ReadUState a = ReadUState
1270− {-# UNPACK #-} !(ForeignPtr a) -- foreign ptr with end of array pointer
1364+ UNPACKIF !ArrayContents -- contents
1365+ !(Ptr a) -- end address
1271− {-# UNPACK #-} !(Ptr a) -- current pointer
1366+ !(Ptr a) -- current address
1368+toReadUState :: Array a -> ReadUState a
1369+toReadUState (Array contents start end _) = ReadUState contents end start
1273-- | Resumable unfold of an array.
1371-- | Resumable unfold of an array.
1275{-# INLINE_NORMAL producer #-}
1373{-# INLINE_NORMAL producer #-}
1276producer :: forall m a. (Monad m, Storable a) => Producer m (Array a) a
1374producer :: forall m a. (Monad m, Storable a) => Producer m (Array a) a
1277−producer = Producer step inject extract
1375+producer = Producer step (return . toReadUState) extract
1280− inject (Array (ForeignPtr start contents) (Ptr end) _) =
1281− return $ ReadUState (ForeignPtr end contents) (Ptr start)
1283 {-# INLINE_LATE step #-}
1378 {-# INLINE_LATE step #-}
1284− step (ReadUState fp@(ForeignPtr end _) p)
1379+ step (ReadUState contents end cur)
1285− | assert (p <= Ptr end) (p == Ptr end) =
1380+ | assert (cur <= end) (cur == end) =
1286− let x = unsafeInlineIO $ touchForeignPtr fp
1381+ let x = unsafeInlineIO $ touch contents
1287 in x `seq` return D.Stop
1382 in x `seq` return D.Stop
1288− step (ReadUState fp p) = do
1383+ step (ReadUState contents end cur) = do
1289 -- unsafeInlineIO allows us to run this in Identity monad for pure
1384 -- unsafeInlineIO allows us to run this in Identity monad for pure
1290 -- toList/foldr case which makes them much faster due to not
1385 -- toList/foldr case which makes them much faster due to not
1291 -- accumulating the list and fusing better with the pure consumers.
1386 -- accumulating the list and fusing better with the pure consumers.
1293 -- This should be safe as the array contents are guaranteed to be
1388 -- This should be safe as the array contents are guaranteed to be
1294 -- evaluated/written to before we peek at them.
1389 -- evaluated/written to before we peek at them.
1295− let !x = unsafeInlineIO $ peek p
1390+ let !x = unsafeInlineIO $ peek cur
1297− (ReadUState fp (p `plusPtr` sizeOf (undefined :: a)))
1391+ cur1 = cur `plusPtr` sizeOf (undefined :: a)
1392+ return $ D.Yield x (ReadUState contents end cur1)
1299− extract (ReadUState (ForeignPtr end contents) (Ptr p)) =
1300− return $ Array (ForeignPtr p contents) (Ptr end) (Ptr end)
1394+ extract (ReadUState contents end cur) = return $ Array contents cur end end
1302-- | Unfold an array into a stream.
1396-- | Unfold an array into a stream.
@@ -1314,15 +1408,15 @@ readRev :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
1314readRev = Unfold step inject
1408readRev = Unfold step inject
1317− inject (Array fp end _) =
1411+ inject (Array contents start end _) =
1318 let p = end `plusPtr` negate (sizeOf (undefined :: a))
1412 let p = end `plusPtr` negate (sizeOf (undefined :: a))
1319− in return $ ReadUState fp p
1413+ in return $ ReadUState contents start p
1321 {-# INLINE_LATE step #-}
1415 {-# INLINE_LATE step #-}
1322− step (ReadUState fp@(ForeignPtr start _) p) | p < Ptr start =
1416+ step (ReadUState contents start p) | p < start =
1323− let x = unsafeInlineIO $ touchForeignPtr fp
1417+ let x = unsafeInlineIO $ touch contents
1324 in x `seq` return D.Stop
1418 in x `seq` return D.Stop
1325− step (ReadUState fp p) = do
1419+ step (ReadUState contents start p) = do
1326 -- unsafeInlineIO allows us to run this in Identity monad for pure
1420 -- unsafeInlineIO allows us to run this in Identity monad for pure
1327 -- toList/foldr case which makes them much faster due to not
1421 -- toList/foldr case which makes them much faster due to not
1328 -- accumulating the list and fusing better with the pure consumers.
1422 -- accumulating the list and fusing better with the pure consumers.
@@ -1330,8 +1424,8 @@ readRev = Unfold step inject
1330 -- This should be safe as the array contents are guaranteed to be
1424 -- This should be safe as the array contents are guaranteed to be
1331 -- evaluated/written to before we peek at them.
1425 -- evaluated/written to before we peek at them.
1332 let !x = unsafeInlineIO $ peek p
1426 let !x = unsafeInlineIO $ peek p
1334− (ReadUState fp (p `plusPtr` negate (sizeOf (undefined :: a))))
1427+ let cur = p `plusPtr` negate (sizeOf (undefined :: a))
1428+ return $ D.Yield x (ReadUState contents start cur)
1336-------------------------------------------------------------------------------
1430-------------------------------------------------------------------------------
1337-- to Lists and streams
1431-- to Lists and streams
@@ -1341,7 +1435,7 @@ readRev = Unfold step inject
1341-- This can be useful when using the IsList instance
1435-- This can be useful when using the IsList instance
1342{-# INLINE_LATE toListFB #-}
1436{-# INLINE_LATE toListFB #-}
1343toListFB :: forall a b. Storable a => (a -> b -> b) -> b -> Array a -> b
1437toListFB :: forall a b. Storable a => (a -> b -> b) -> b -> Array a -> b
1344−toListFB c n Array{..} = go (unsafeForeignPtrToPtr aStart)
1438+toListFB c n Array{..} = go arrStart
1347 go p | assert (p <= aEnd) (p == aEnd) = n
1441 go p | assert (p <= aEnd) (p == aEnd) = n
@@ -1355,7 +1449,7 @@ toListFB c n Array{..} = go (unsafeForeignPtrToPtr aStart)
1356 let !x = unsafeInlineIO $ do
1450 let !x = unsafeInlineIO $ do
1357 r <- peek p
1451 r <- peek p
1358− touchForeignPtr aStart
1452+ touch arrContents
1359 return r
1453 return r
1360 in c x (go (p `plusPtr` sizeOf (undefined :: a)))
1454 in c x (go (p `plusPtr` sizeOf (undefined :: a)))
@@ -1375,7 +1469,7 @@ toList s = build (\c n -> toListFB c n s)
1375{-# INLINE_NORMAL toStreamD #-}
1469{-# INLINE_NORMAL toStreamD #-}
1376toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
1470toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
1377toStreamD Array{..} =
1471toStreamD Array{..} =
1378− let p = unsafeForeignPtrToPtr aStart
1472+ let p = arrStart
1379 in D.Stream step p
1473 in D.Stream step p
@@ -1394,14 +1488,14 @@ toStreamD Array{..} =
1395 let !x = unsafeInlineIO $ do
1489 let !x = unsafeInlineIO $ do
1396 r <- peek p
1490 r <- peek p
1397− touchForeignPtr aStart
1491+ touch arrContents
1398 return r
1492 return r
1399 return $ D.Yield x (p `plusPtr` sizeOf (undefined :: a))
1493 return $ D.Yield x (p `plusPtr` sizeOf (undefined :: a))
1401{-# INLINE toStreamK #-}
1495{-# INLINE toStreamK #-}
1402toStreamK :: forall m a. Storable a => Array a -> K.Stream m a
1496toStreamK :: forall m a. Storable a => Array a -> K.Stream m a
1403toStreamK Array{..} =
1497toStreamK Array{..} =
1404− let p = unsafeForeignPtrToPtr aStart
1498+ let p = arrStart
@@ -1412,7 +1506,7 @@ toStreamK Array{..} =
1412 -- XXX May not be safe for mutable arrays.
1506 -- XXX May not be safe for mutable arrays.
1413 let !x = unsafeInlineIO $ do
1507 let !x = unsafeInlineIO $ do
1414 r <- peek p
1508 r <- peek p
1415− touchForeignPtr aStart
1509+ touch arrContents
1416 return r
1510 return r
1417 in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
1511 in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
@@ -1430,13 +1524,13 @@ toStreamDRev Array{..} =
1432 {-# INLINE_LATE step #-}
1526 {-# INLINE_LATE step #-}
1433− step _ p | p < unsafeForeignPtrToPtr aStart = return D.Stop
1527+ step _ p | p < arrStart = return D.Stop
1434 step _ p = do
1528 step _ p = do
1435 -- See comments in toStreamD for why we use unsafeInlineIO
1529 -- See comments in toStreamD for why we use unsafeInlineIO
1437 let !x = unsafeInlineIO $ do
1531 let !x = unsafeInlineIO $ do
1438 r <- peek p
1532 r <- peek p
1439− touchForeignPtr aStart
1533+ touch arrContents
1440 return r
1534 return r
1441 return $ D.Yield x (p `plusPtr` negate (sizeOf (undefined :: a)))
1535 return $ D.Yield x (p `plusPtr` negate (sizeOf (undefined :: a)))
@@ -1448,12 +1542,12 @@ toStreamKRev Array {..} =
1451− go p | p < unsafeForeignPtrToPtr aStart = K.nil
1545+ go p | p < arrStart = K.nil
1452 | otherwise =
1546 | otherwise =
1454 let !x = unsafeInlineIO $ do
1548 let !x = unsafeInlineIO $ do
1455 r <- peek p
1549 r <- peek p
1456− touchForeignPtr aStart
1550+ touch arrContents
1457 return r
1551 return r
1458 in x `K.cons` go (p `plusPtr` negate (sizeOf (undefined :: a)))
1552 in x `K.cons` go (p `plusPtr` negate (sizeOf (undefined :: a)))
@@ -1481,8 +1575,17 @@ foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
1481-------------------------------------------------------------------------------
1575-------------------------------------------------------------------------------
1483data ArrayUnsafe a = ArrayUnsafe
1577data ArrayUnsafe a = ArrayUnsafe
1578+ UNPACKIF !ArrayContents -- contents
1484− {-# UNPACK #-} !(ForeignPtr a) -- first address
1579+ {-# UNPACK #-} !(Ptr a) -- start address
1485− {-# UNPACK #-} !(Ptr a) -- first unused address
1580+ {-# UNPACK #-} !(Ptr a) -- first unused address
1582+toArrayUnsafe :: Array a -> ArrayUnsafe a
1583+toArrayUnsafe (Array contents start end _) =
1584+ ArrayUnsafe contents start end
1586+fromArrayUnsafe :: ArrayUnsafe a -> Array a
1587+fromArrayUnsafe (ArrayUnsafe contents start end) =
1588+ Array contents start end end
1487-- Note: Arrays may be allocated with a specific alignment at the beginning of
1590-- Note: Arrays may be allocated with a specific alignment at the beginning of
1488-- the array. If you need to maintain that alignment on reallocations then you
1591-- the array. If you need to maintain that alignment on reallocations then you
@@ -1505,29 +1608,28 @@ appendNUnsafe :: forall m a. (MonadIO m, Storable a) =>
1506 -> Fold m a (Array a)
1609 -> Fold m a (Array a)
1507appendNUnsafe action n =
1610appendNUnsafe action n =
1508− fmap extract $ FL.foldlM' step initial
1611+ fmap fromArrayUnsafe $ FL.foldlM' step initial
1512 initial = do
1615 initial = do
1513 assert (n >= 0) (return ())
1616 assert (n >= 0) (return ())
1514− arr@(Array _ end bound) <- action
1617+ arr@(Array _ _ end bound) <- action
1515 let free = bound `minusPtr` end
1618 let free = bound `minusPtr` end
1516 elemSize = sizeOf (undefined :: a)
1619 elemSize = sizeOf (undefined :: a)
1517 needed = n * elemSize
1620 needed = n * elemSize
1518 -- XXX We can also reallocate if the array has too much free space,
1621 -- XXX We can also reallocate if the array has too much free space,
1519 -- otherwise we lose that space.
1622 -- otherwise we lose that space.
1520− (Array start1 end1 _) <-
1623+ arr1 <-
1521 if free < needed
1624 if free < needed
1522 then noinline reallocWith "appendNUnsafeWith" (+ needed) needed arr
1625 then noinline reallocWith "appendNUnsafeWith" (+ needed) needed arr
1523 else return arr
1626 else return arr
1524− return $ ArrayUnsafe start1 end1
1627+ return $ toArrayUnsafe arr1
1526− step (ArrayUnsafe start end) x = do
1527− liftIO $ poke end x >> touchForeignPtr start
1528− return $ ArrayUnsafe start (end `plusPtr` sizeOf (undefined :: a))
1530− extract (ArrayUnsafe start end) = Array start end end
1629+ step (ArrayUnsafe contents start end) x = do
1630+ liftIO $ poke end x >> touch contents
1631+ let end1 = end `plusPtr` sizeOf (undefined :: a)
1632+ return $ ArrayUnsafe contents start end1
1532-- | Append @n@ elements to an existing array. Any free space left in the array
1634-- | Append @n@ elements to an existing array. Any free space left in the array
1533-- after appending @n@ elements is lost.
1635-- after appending @n@ elements is lost.
@@ -1634,27 +1736,17 @@ writeNAlignedUnmanaged align = writeNWith (newArrayAlignedUnmanaged align)
1634{-# INLINE_NORMAL writeNWithUnsafe #-}
1736{-# INLINE_NORMAL writeNWithUnsafe #-}
1635writeNWithUnsafe :: forall m a. (MonadIO m, Storable a)
1737writeNWithUnsafe :: forall m a. (MonadIO m, Storable a)
1636 => (Int -> m (Array a)) -> Int -> Fold m a (Array a)
1738 => (Int -> m (Array a)) -> Int -> Fold m a (Array a)
1637−writeNWithUnsafe alloc n = Fold step initial extract
1739+writeNWithUnsafe alloc n = Fold step initial (return . fromArrayUnsafe)
1641− initial = do
1743+ initial = FL.Partial . toArrayUnsafe <$> alloc (max n 0)
1642− (Array start end _) <- alloc (max n 0)
1643− return $ FL.Partial $ ArrayUnsafe start end
1645− -- This condition is always true, but compiler does not know that.
1646− step (ArrayUnsafe start end) x | end /= nullPtr = do
1745+ step (ArrayUnsafe contents start end) x = do
1647− liftIO $ poke end x
1746+ liftIO $ poke end x >> touch contents
1649 $ FL.Partial
1748 $ FL.Partial
1650− $ ArrayUnsafe start (end `plusPtr` sizeOf (undefined :: a))
1749+ $ ArrayUnsafe contents start (end `plusPtr` sizeOf (undefined :: a))
1651− -- This condition is never met, just a hack to insert a touchForeignPtr.
1652− -- This condition increases the cputime by around 50% in several benchmarks
1653− -- but there seem to be no better way. XXX An unconditional touch increases
1654− -- the allocations and time by a very large amount, need to investigate.
1655− step (ArrayUnsafe start _) _ = liftIO $ touchForeignPtr start >> undefined
1657− extract (ArrayUnsafe start end) = return $ Array start end end -- liftIO . shrinkToFit
1659-- | Like 'writeN' but does not check the array bounds when writing. The fold
1751-- | Like 'writeN' but does not check the array bounds when writing. The fold
1660-- driver must not call the step function more than 'n' times otherwise it will
1752-- driver must not call the step function more than 'n' times otherwise it will
@@ -1725,17 +1817,17 @@ writeWith elemCount =
1728− insertElem (Array start end bound) x = do
1820+ insertElem (Array contents start end bound) x = do
1729 liftIO $ poke end x
1821 liftIO $ poke end x
1730− return $ Array start (end `plusPtr` sizeOf (undefined :: a)) bound
1822+ let end1 = end `plusPtr` sizeOf (undefined :: a)
1823+ return $ Array contents start end1 bound
1732 initial = do
1825 initial = do
1733 when (elemCount < 0) $ error "writeWith: elemCount is negative"
1826 when (elemCount < 0) $ error "writeWith: elemCount is negative"
1734 liftIO $ newArrayAligned (alignment (undefined :: a)) elemCount
1827 liftIO $ newArrayAligned (alignment (undefined :: a)) elemCount
1735− step arr@(Array start end bound) x
1828+ step arr@(Array _ start end bound) x
1736 | end `plusPtr` sizeOf (undefined :: a) > bound = do
1829 | end `plusPtr` sizeOf (undefined :: a) > bound = do
1737− let p = unsafeForeignPtrToPtr start
1738− oldSize = end `minusPtr` p
1830+ let oldSize = end `minusPtr` start
1739 newSize = max (oldSize * 2) 1
1831 newSize = max (oldSize * 2) 1
@@ -1842,21 +1934,21 @@ fromList xs = fromStreamD $ D.fromList xs
1842{-# INLINE spliceCopy #-}
1934{-# INLINE spliceCopy #-}
1843spliceCopy :: (MonadIO m, Storable a) => Array a -> Array a -> m (Array a)
1935spliceCopy :: (MonadIO m, Storable a) => Array a -> Array a -> m (Array a)
1844spliceCopy arr1 arr2 = do
1936spliceCopy arr1 arr2 = do
1845− let src1 = unsafeForeignPtrToPtr (aStart arr1)
1937+ let src1 = arrStart arr1
1846− src2 = unsafeForeignPtrToPtr (aStart arr2)
1938+ src2 = arrStart arr2
1847 len1 = aEnd arr1 `minusPtr` src1
1939 len1 = aEnd arr1 `minusPtr` src1
1848 len2 = aEnd arr2 `minusPtr` src2
1940 len2 = aEnd arr2 `minusPtr` src2
1850 arr <- liftIO $ newArray (len1 + len2)
1942 arr <- liftIO $ newArray (len1 + len2)
1851− let dst = unsafeForeignPtrToPtr (aStart arr)
1943+ let dst = arrStart arr
1853 -- XXX Should we use copyMutableByteArray# instead? Is there an overhead to
1945 -- XXX Should we use copyMutableByteArray# instead? Is there an overhead to
1854 -- ccall?
1946 -- ccall?
1855 liftIO $ do
1947 liftIO $ do
1856 memcpy (castPtr dst) (castPtr src1) len1
1948 memcpy (castPtr dst) (castPtr src1) len1
1857− touchForeignPtr (aStart arr1)
1949+ touch (arrContents arr1)
1858 memcpy (castPtr (dst `plusPtr` len1)) (castPtr src2) len2
1950 memcpy (castPtr (dst `plusPtr` len1)) (castPtr src2) len2
1859− touchForeignPtr (aStart arr2)
1951+ touch (arrContents arr2)
1860 return arr { aEnd = dst `plusPtr` (len1 + len2) }
1952 return arr { aEnd = dst `plusPtr` (len1 + len2) }
1862-- | Really really unsafe, appends the second array into the first array. If
1954-- | Really really unsafe, appends the second array into the first array. If
@@ -1866,12 +1958,13 @@ spliceCopy arr1 arr2 = do
1866spliceUnsafe :: MonadIO m => Array a -> (Array a, Int) -> m (Array a)
1958spliceUnsafe :: MonadIO m => Array a -> (Array a, Int) -> m (Array a)
1867spliceUnsafe dst (src, srcLen) =
1959spliceUnsafe dst (src, srcLen) =
1868 liftIO $ do
1960 liftIO $ do
1869− unsafeWithForeignPtr (aStart dst) $ \_ ->
1961+ let psrc = arrStart src
1870− unsafeWithForeignPtr (aStart src) $ \psrc -> do
1871− let pdst = aEnd dst
1962+ let pdst = aEnd dst
1872− assert (pdst `plusPtr` srcLen <= aBound dst) (return ())
1963+ assert (pdst `plusPtr` srcLen <= aBound dst) (return ())
1873− memcpy (castPtr pdst) (castPtr psrc) srcLen
1964+ memcpy (castPtr pdst) (castPtr psrc) srcLen
1965+ touch (arrContents src)
1966+ touch (arrContents dst)
1874− return $ dst {aEnd = pdst `plusPtr` srcLen}
1967+ return $ dst {aEnd = pdst `plusPtr` srcLen}
1876-- | @spliceWith sizer dst src@ mutates @dst@ to append @src@. If there is no
1969-- | @spliceWith sizer dst src@ mutates @dst@ to append @src@. If there is no
1877-- reserved space available in @dst@ it is reallocated to a size determined by
1970-- reserved space available in @dst@ it is reallocated to a size determined by
@@ -1884,19 +1977,18 @@ spliceUnsafe dst (src, srcLen) =
1884{-# INLINE spliceWith #-}
1977{-# INLINE spliceWith #-}
1885spliceWith :: forall m a. (MonadIO m, Storable a) =>
1978spliceWith :: forall m a. (MonadIO m, Storable a) =>
1886 (Int -> Int -> Int) -> Array a -> Array a -> m (Array a)
1979 (Int -> Int -> Int) -> Array a -> Array a -> m (Array a)
1887−spliceWith sizer dst@(Array start end bound) src = do
1980+spliceWith sizer dst@(Array _ start end bound) src = do
1889 let f = appendWith (`sizer` byteLength src) (return dst)
1982 let f = appendWith (`sizer` byteLength src) (return dst)
1890 in D.fold f (toStreamD src)
1983 in D.fold f (toStreamD src)
1892 assert (end <= bound) (return ())
1985 assert (end <= bound) (return ())
1893− let srcLen = aEnd src `minusPtr` unsafeForeignPtrToPtr (aStart src)
1986+ let srcLen = aEnd src `minusPtr` arrStart src
1896 if end `plusPtr` srcLen >= bound
1989 if end `plusPtr` srcLen >= bound
1898− let oldStart = unsafeForeignPtrToPtr start
1899− oldSize = end `minusPtr` oldStart
1991+ let oldSize = end `minusPtr` start
1900 newSize = sizer oldSize srcLen
1992 newSize = sizer oldSize srcLen
1901 when (newSize < oldSize + srcLen)
1993 when (newSize < oldSize + srcLen)
@@ -1943,19 +2035,21 @@ spliceExp = spliceWith (\l1 l2 -> max (l1 * 2) (l1 + l2))
1943breakOn :: MonadIO m
2035breakOn :: MonadIO m
1944 => Word8 -> Array Word8 -> m (Array Word8, Maybe (Array Word8))
2036 => Word8 -> Array Word8 -> m (Array Word8, Maybe (Array Word8))
1945breakOn sep arr@Array{..} = liftIO $ do
2037breakOn sep arr@Array{..} = liftIO $ do
1946− let p = unsafeForeignPtrToPtr aStart
2038+ let p = arrStart
1947 loc <- c_memchr p sep (fromIntegral $ aEnd `minusPtr` p)
2039 loc <- c_memchr p sep (fromIntegral $ aEnd `minusPtr` p)
1948 return $
2040 return $
1949 if loc == nullPtr
2041 if loc == nullPtr
1950 then (arr, Nothing)
2042 then (arr, Nothing)
1953− { aStart = aStart
2045+ { arrContents = arrContents
2046+ , arrStart = arrStart
1954 , aEnd = loc
2047 , aEnd = loc
1955 , aBound = loc
2048 , aBound = loc
1957 , Just $ Array
2050 , Just $ Array
1958− { aStart = aStart `plusForeignPtr` (loc `minusPtr` p + 1)
2051+ { arrContents = arrContents
2052+ , arrStart = arrStart `plusPtr` (loc `minusPtr` p + 1)
1959 , aEnd = aEnd
2053 , aEnd = aEnd
1960 , aBound = aBound
2054 , aBound = aBound
@@ -1974,14 +2068,16 @@ splitAt i arr@Array{..} =
1974 then error $ "sliceAt: specified array index " ++ show i
2068 then error $ "sliceAt: specified array index " ++ show i
1975 ++ " is beyond the maximum index " ++ show maxIndex
2069 ++ " is beyond the maximum index " ++ show maxIndex
1976 else let off = i * sizeOf (undefined :: a)
2070 else let off = i * sizeOf (undefined :: a)
1977− p = unsafeForeignPtrToPtr aStart `plusPtr` off
2071+ p = arrStart `plusPtr` off
1978 in ( Array
2072 in ( Array
1979− { aStart = aStart
2073+ { arrContents = arrContents
2074+ , arrStart = arrStart
1980 , aEnd = p
2075 , aEnd = p
1981 , aBound = p
2076 , aBound = p
1984− { aStart = aStart `plusForeignPtr` off
2079+ { arrContents = arrContents
2080+ , arrStart = arrStart `plusPtr` off
1985 , aEnd = aEnd
2081 , aEnd = aEnd
1986 , aBound = aBound
2082 , aBound = aBound
@@ -2003,8 +2099,8 @@ castUnsafe ::
2003 Storable b =>
2099 Storable b =>
2005 Array a -> Array b
2101 Array a -> Array b
2006−castUnsafe (Array start end bound) =
2102+castUnsafe (Array contents start end bound) =
2007− Array (castForeignPtr start) (castPtr end) (castPtr bound)
2103+ Array contents (castPtr start) (castPtr end) (castPtr bound)
2009-- | Cast an @Array a@ into an @Array Word8@.
2105-- | Cast an @Array a@ into an @Array Word8@.
@@ -2035,7 +2131,7 @@ cast arr =
2036asPtrUnsafe :: Array a -> (Ptr b -> IO c) -> IO c
2132asPtrUnsafe :: Array a -> (Ptr b -> IO c) -> IO c
2037asPtrUnsafe Array{..} act = do
2133asPtrUnsafe Array{..} act = do
2038− unsafeWithForeignPtr aStart $ \ptr -> act (castPtr ptr)
2134+ unsafeWithArrayContents arrContents arrStart $ \ptr -> act (castPtr ptr)
2040-------------------------------------------------------------------------------
2136-------------------------------------------------------------------------------
2041-- Equality
2137-- Equality
@@ -2048,8 +2144,8 @@ asPtrUnsafe Array{..} act = do
2048cmp :: MonadIO m => Array a -> Array a -> m Bool
2144cmp :: MonadIO m => Array a -> Array a -> m Bool
2049cmp arr1 arr2 =
2145cmp arr1 arr2 =
2050 liftIO $ do
2146 liftIO $ do
2051− let ptr1 = unsafeForeignPtrToPtr $ aStart arr1
2147+ let ptr1 = arrStart arr1
2052− let ptr2 = unsafeForeignPtrToPtr $ aStart arr2
2148+ let ptr2 = arrStart arr2
2053 let len1 = aEnd arr1 `minusPtr` ptr1
2149 let len1 = aEnd arr1 `minusPtr` ptr1
2054 let len2 = aEnd arr2 `minusPtr` ptr2
2150 let len2 = aEnd arr2 `minusPtr` ptr2
@@ -2059,8 +2155,8 @@ cmp arr1 arr2 =
2059 then return True
2155 then return True
2061 r <- memcmp (castPtr ptr1) (castPtr ptr2) len1
2157 r <- memcmp (castPtr ptr1) (castPtr ptr2) len1
2062− touchForeignPtr $ aStart arr1
2158+ touch (arrContents arr1)
2063− touchForeignPtr $ aStart arr2
2159+ touch (arrContents arr2)
2064 return r
2160 return r
2065 else return False
2161 else return False