@@ -42,9 +42,15 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
43 -- * Random access
43 -- * Random access
44 , getIndexUnsafe
44 , getIndexUnsafe
46 -- * Mutation
49 -- * Mutation
47 , putIndexUnsafe
50 , putIndexUnsafe
48 , snocUnsafe
54 , snocUnsafe
49 , snocWith
55 , snocWith
@@ -56,6 +62,10 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
57 , asPtrUnsafe
63 , asPtrUnsafe
59 -- * Folding
69 -- * Folding
@@ -381,6 +391,63 @@ putIndexUnsafe Array{..} i x =
381 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
391 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
382 liftIO $ poke elemPtr x
392 liftIO $ poke elemPtr x
394+invalidIndex :: String -> Int -> a
395+invalidIndex label i =
396+ error $ label ++ ": invalid array index " ++ show i
398+{-# INLINE putIndexPtr #-}
399+putIndexPtr :: forall m a. (MonadIO m, Storable a) =>
400+ Ptr a -> Ptr a -> Int -> a -> m ()
401+putIndexPtr ptr end i x = do
402+ let elemSize = sizeOf (undefined :: a)
403+ elemPtr = ptr `plusPtr` (elemSize * i)
404+ if i >= 0 && elemPtr `plusPtr` elemSize <= end
405+ then liftIO $ poke elemPtr x
406+ else invalidIndex "putIndexPtr" i
408+-- | /O(1)/ Write the given element at the given index in the array.
409+-- Performs in-place mutation of the array.
411+-- >>> putIndex arr ix val = Array.modifyIndex arr ix (const (val, ()))
414+{-# INLINE putIndex #-}
415+putIndex :: (MonadIO m, Storable a) => Array a -> Int -> a -> m ()
417+ unsafeWithForeignPtrM (aStart arr) $ \p -> putIndexPtr p (aEnd arr) i x
419+-- | Modify a given index of an array using a modifier function.
422+modifyIndexUnsafe :: forall m a b. (MonadIO m, Storable a) =>
423+ Array a -> Int -> (a -> (a, b)) -> m b
424+modifyIndexUnsafe Array{..} i f = do
425+ liftIO $ unsafeWithForeignPtr aStart $ \ptr -> do
426+ let elemSize = sizeOf (undefined :: a)
427+ elemPtr = ptr `plusPtr` (elemSize * i)
428+ assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
434+-- | Modify a given index of an array using a modifier function.
437+modifyIndex :: forall m a b. (MonadIO m, Storable a) =>
438+ Array a -> Int -> (a -> (a, b)) -> m b
439+modifyIndex Array{..} i f = do
440+ liftIO $ unsafeWithForeignPtr aStart $ \ptr -> do
441+ let elemSize = sizeOf (undefined :: a)
442+ elemPtr = ptr `plusPtr` (elemSize * i)
443+ if i >= 0 && elemPtr `plusPtr` elemSize <= aEnd
449+ else invalidIndex "modifyIndex" i
384-------------------------------------------------------------------------------
451-------------------------------------------------------------------------------
385-- Rounding
452-- Rounding
386-------------------------------------------------------------------------------
453-------------------------------------------------------------------------------
@@ -619,6 +686,116 @@ getIndexUnsafe Array {..} i =
619 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
686 assert (i >= 0 && elemPtr `plusPtr` elemSize <= aEnd) (return ())
620 liftIO $ peek elemPtr
687 liftIO $ peek elemPtr
689+{-# INLINE getIndexPtr #-}
690+getIndexPtr :: forall m a. (MonadIO m, Storable a) =>
691+ Ptr a -> Ptr a -> Int -> m a
692+getIndexPtr ptr end i = do
693+ let elemSize = sizeOf (undefined :: a)
694+ elemPtr = ptr `plusPtr` (elemSize * i)
695+ if i >= 0 && elemPtr `plusPtr` elemSize <= end
696+ then liftIO $ peek elemPtr
697+ else invalidIndex "getIndexPtr" i
699+-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
701+{-# INLINE getIndex #-}
702+getIndex :: (MonadIO m, Storable a) => Array a -> Int -> m a
704+ unsafeWithForeignPtrM (aStart arr) $ \p -> getIndexPtr p (aEnd arr) i
706+{-# INLINE getIndexPtrRev #-}
707+getIndexPtrRev :: forall m a. (MonadIO m, Storable a) =>
708+ Ptr a -> Ptr a -> Int -> m a
709+getIndexPtrRev ptr end i = do
710+ let elemSize = sizeOf (undefined :: a)
711+ elemPtr = end `plusPtr` negate (elemSize * (i + 1))
712+ if i >= 0 && elemPtr >= ptr
713+ then liftIO $ peek elemPtr
714+ else invalidIndex "getIndexPtrRev" i
716+-- | /O(1)/ Lookup the element at the given index from the end of the array.
717+-- Index starts from 0.
719+-- Slightly faster than computing the forward index and using getIndex.
721+{-# INLINE getIndexRev #-}
722+getIndexRev :: (MonadIO m, Storable a) => Array a -> Int -> m a
724+ unsafeWithForeignPtrM (aStart arr) $ \p -> getIndexPtrRev p (aEnd arr) i
726+data GetIndicesState fp end st = GetIndicesState fp end st
728+-- | Given an unfold that generates array indices, read the elements on those
729+-- indices from the supplied Array. An error is thrown if an index is out of
733+{-# INLINE getIndices #-}
734+getIndices :: (MonadIO m, Storable a) =>
735+ Unfold m (Array a) Int -> Unfold m (Array a) a
736+getIndices (Unfold stepi injecti) = Unfold step inject
740+ inject arr@(Array fp@(ForeignPtr _ _) (Ptr end) _) = do
742+ return $ GetIndicesState fp (Ptr end) st
744+ {-# INLINE_LATE step #-}
745+ step (GetIndicesState fp@(ForeignPtr start _) end st) = do
749+ x <- liftIO $ getIndexPtr (Ptr start) end i
750+ return $ D.Yield x (GetIndicesState fp end s)
751+ D.Skip s -> return $ D.Skip (GetIndicesState fp end s)
753+ liftIO $ touchForeignPtr fp
756+-------------------------------------------------------------------------------
758+-------------------------------------------------------------------------------
760+-- | /O(1)/ Slice an array in constant time.
762+-- Unsafe: The bounds of the slice are not checked.
767+{-# INLINE getSliceUnsafe #-}
768+getSliceUnsafe :: forall a. Storable a
769+ => Int -- ^ from index
770+ -> Int -- ^ length of the slice
773+getSliceUnsafe index len (Array fp e _) =
774+ let size = sizeOf (undefined :: a)
775+ fp1 = fp `plusForeignPtr` (index * size)
776+ end = unsafeForeignPtrToPtr fp1 `plusPtr` (len * size)
777+ in assert (index >= 0 && len >= 0 && end <= e) (Array fp1 end end)
779+-- | /O(1)/ Slice an array in constant time. Throws an error if the slice
780+-- extends out of the array bounds.
783+{-# INLINE getSlice #-}
784+getSlice :: forall a. Storable a =>
786+ -> Int -- ^ length of the slice
789+getSlice index len (Array fp e _) =
790+ let size = sizeOf (undefined :: a)
791+ fp1 = fp `plusForeignPtr` (index * size)
792+ end = unsafeForeignPtrToPtr fp1 `plusPtr` (len * size)
793+ in if index >= 0 && len >= 0 && end <= e
794+ then Array fp1 end end
796+ $ "getSlice: invalid slice, index "
797+ ++ show index ++ " length " ++ show len
622-------------------------------------------------------------------------------
799-------------------------------------------------------------------------------
624-------------------------------------------------------------------------------
801-------------------------------------------------------------------------------