pvector-0.1.0.0: src/Data/Vector/Persistent/Internal/Array.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedSums #-}
{-# LANGUAGE UnboxedTuples #-}
module Data.Vector.Persistent.Internal.Array
( Array,
MArray,
nullSmallArray,
lastSmallArray,
singletonSmallArray,
twoSmallArray,
updateSmallArray,
modifySmallArray,
modifySmallArrayF,
modifySmallArray',
updateResizeSmallArray,
popSmallArray,
undefinedElem,
ifoldrStepSmallArray,
ifoldlStepSmallArray,
ifoldrStepSmallArray',
ifoldlStepSmallArray',
imapStepSmallArray,
imapStepSmallArray',
itraverseStepSmallArray,
modifySmallArray#,
mapSmallArray#,
shrinkSmallMutableArray_,
)
where
import Control.Applicative (liftA2)
import Control.Monad (when)
import Control.Monad.Primitive (PrimMonad, PrimState)
import Control.Monad.ST (ST, runST)
import Data.Coerce (coerce)
import Data.Functor (($>))
import Data.Functor.Identity (Identity (..))
import qualified Data.Primitive as Primitive
import Data.Primitive.SmallArray
import GHC.Exts (SmallMutableArray#)
type Array = SmallArray
type MArray = SmallMutableArray
-- | Used to support older ghcs.
shrinkSmallMutableArray_ :: PrimMonad m => MArray (PrimState m) a -> Int -> m (MArray (PrimState m) a)
#if __GLASGOW_HASKELL__ >= 810
shrinkSmallMutableArray_ marr n = Primitive.shrinkSmallMutableArray marr n $> marr
#else
shrinkSmallMutableArray_ mary n = Primitive.cloneSmallMutableArray mary 0 n
#endif
{-# INLINE shrinkSmallMutableArray_ #-}
mapSmallArray# :: (a -> (# b #)) -> SmallArray a -> SmallArray b
mapSmallArray# f sa = createSmallArray (length sa) (error "mapSmallArray#") $ \smb -> do
let go i =
when (i < length sa) $ do
x <- indexSmallArrayM sa i
let !(# y #) = f x
writeSmallArray smb i y *> go (i + 1)
go 0
{-# INLINE mapSmallArray# #-}
nullSmallArray :: SmallArray a -> Bool
nullSmallArray arr = sizeofSmallArray arr == 0
{-# INLINE nullSmallArray #-}
lastSmallArray :: SmallArray a -> a
lastSmallArray arr = indexSmallArray arr $ sizeofSmallArray arr
singletonSmallArray :: a -> Array a
singletonSmallArray a = runSmallArray $ newSmallArray 1 a
{-# INLINE singletonSmallArray #-}
twoSmallArray :: a -> a -> Array a
twoSmallArray x y = runSmallArray $ do
marr <- newSmallArray 2 x
writeSmallArray marr 1 y
pure marr
{-# INLINE twoSmallArray #-}
updateSmallArray :: Array a -> Int -> a -> Array a
updateSmallArray arr i x = modifySmallArray# arr i $ \_ -> (# x #)
{-# INLINE updateSmallArray #-}
modifySmallArray :: Array a -> Int -> (a -> a) -> Array a
modifySmallArray arr i f = modifySmallArray# arr i $ \x -> (# f x #)
{-# INLINE modifySmallArray #-}
modifySmallArrayF :: Functor f => Array a -> Int -> (a -> f a) -> f (Array a)
modifySmallArrayF arr i f | (# x #) <- indexSmallArray## arr i = updateSmallArray arr i <$> f x
{-# INLINE modifySmallArrayF #-}
modifySmallArray' :: Array a -> Int -> (a -> a) -> Array a
modifySmallArray' arr i f = modifySmallArray# arr i $ \x -> let !x' = f x in (# x' #)
{-# INLINE modifySmallArray' #-}
modifySmallArray# :: Array a -> Int -> (a -> (# a #)) -> Array a
modifySmallArray# arr i f = runSmallArray $ do
marr <- thawSmallArray arr 0 $ sizeofSmallArray arr
x <- indexSmallArrayM arr i
let !(# x' #) = f x
writeSmallArray marr i x'
pure marr
{-# INLINE modifySmallArray# #-}
updateResizeSmallArray :: Array a -> Int -> a -> Array a
updateResizeSmallArray arr i a = runSmallArray $ do
marr <- thawSmallArray arr 0 (max len (i + 1))
writeSmallArray marr i a
pure marr
where
len = sizeofSmallArray arr
{-# INLINE updateResizeSmallArray #-}
popSmallArray :: Array a -> Array a
popSmallArray arr = runSmallArray $ thawSmallArray arr 0 (sizeofSmallArray arr - 1)
{-# INLINE popSmallArray #-}
undefinedElem :: forall a. a
undefinedElem = error "undefined element"
{-# NOINLINE undefinedElem #-}
ifoldrStepSmallArray :: Int -> Int -> (Int -> a -> b -> b) -> b -> SmallArray a -> b
ifoldrStepSmallArray i0 step f z arr = do
let len = sizeofSmallArray arr
go i j
| i == len = z
| (# x #) <- indexSmallArray## arr i = f j x (go (i + 1) $! j + step)
go 0 i0
{-# INLINE ifoldrStepSmallArray #-}
ifoldlStepSmallArray :: Int -> Int -> (Int -> b -> a -> b) -> b -> SmallArray a -> b
ifoldlStepSmallArray i0 step f z arr = do
let len = sizeofSmallArray arr
go i j
| i < 0 = z
| (# x #) <- indexSmallArray## arr i = f j (go (i - 1) $! j - step) x
go (len - 1) i0
{-# INLINE ifoldlStepSmallArray #-}
ifoldrStepSmallArray' :: Int -> Int -> (Int -> a -> b -> b) -> b -> SmallArray a -> b
ifoldrStepSmallArray' i0 step f z arr = do
let go i j acc
| i < 0 = acc
| (# x #) <- indexSmallArray## arr i = (go (i - 1) $! (j - step)) $! f j x acc
go (sizeofSmallArray arr) i0 z
{-# INLINE ifoldrStepSmallArray' #-}
ifoldlStepSmallArray' :: Int -> Int -> (Int -> b -> a -> b) -> b -> SmallArray a -> b
ifoldlStepSmallArray' i0 step f z arr = do
let go i j acc
| i == sizeofSmallArray arr = acc
| (# x #) <- indexSmallArray## arr i = (go (i + 1) $! (j + step)) $! f j acc x
go 0 i0 z
{-# INLINE ifoldlStepSmallArray' #-}
imapStepSmallArray :: Int -> Int -> (Int -> a -> b) -> SmallArray a -> SmallArray b
imapStepSmallArray i0 step f arr = createSmallArray len undefinedElem $ \marr -> do
let go i k = when (i < len) $ do
x <- indexSmallArrayM arr i
writeSmallArray marr i (f k x)
go (i + 1) $! k + step
go 0 i0
where
len = sizeofSmallArray arr
{-# INLINE imapStepSmallArray #-}
imapStepSmallArray' :: Int -> (a -> Int) -> (Int -> a -> b) -> SmallArray a -> SmallArray b
imapStepSmallArray' i0 step f arr = createSmallArray len undefinedElem $ \marr -> do
let go i k = when (i < len) $ do
x <- indexSmallArrayM arr i
writeSmallArray marr i $! f k x
go (i + 1) $! k + step x
go 0 i0
where
len = sizeofSmallArray arr
{-# INLINE imapStepSmallArray' #-}
newtype STA a = STA {_runSTA :: forall s. SmallMutableArray# s a -> ST s (SmallArray a)}
runSTA :: Int -> STA a -> SmallArray a
runSTA !sz = \(STA m) ->
runST $
newSmallArray sz undefinedElem
>>= \(SmallMutableArray ar#) -> m ar#
itraverseStepSmallArray :: Applicative f => Int -> Int -> (Int -> a -> f b) -> SmallArray a -> f (SmallArray b)
itraverseStepSmallArray i0 step f = \ !arr -> do
let len = sizeofSmallArray arr
go i k
| i == len =
pure $ STA $ \marr -> unsafeFreezeSmallArray (SmallMutableArray marr)
| (# x #) <- indexSmallArray## arr i =
liftA2
(\b (STA m) -> STA $ \marr -> writeSmallArray (SmallMutableArray marr) i b >> m marr)
(f k x)
(go (i + 1) $! k + step)
if len == 0
then pure emptySmallArray
else runSTA len <$> go 0 i0
{-# INLINE [1] itraverseStepSmallArray #-}
{-# RULES
"itraverseStepSmallArray/ST" forall i0 step (f :: Int -> a -> ST s b).
itraverseStepSmallArray i0 step f =
itraverseStepSmallArrayP i0 step f
"itraverseStepSmallArray/IO" forall i0 step (f :: Int -> a -> IO b).
itraverseStepSmallArray i0 step f =
itraverseStepSmallArrayP i0 step f
"itraverseStepSmallArray/Id" forall i0 step (f :: Int -> a -> Identity b).
itraverseStepSmallArray i0 step f =
( coerce ::
(SmallArray a -> SmallArray (Identity b)) ->
SmallArray a ->
Identity (SmallArray b)
)
(imapStepSmallArray i0 step f)
#-}
-- | This is the fastest, most straightforward way to traverse
-- an array, but it only works correctly with a sufficiently
-- "affine" 'PrimMonad' instance. In particular, it must only produce
-- /one/ result array. 'Control.Monad.Trans.List.ListT'-transformed
-- monads, for example, will not work right at all.
itraverseStepSmallArrayP :: PrimMonad m => Int -> Int -> (Int -> a -> m b) -> SmallArray a -> m (SmallArray b)
itraverseStepSmallArrayP i0 step f = \ !ary -> do
let len = sizeofSmallArray ary
go i k marr
| i == len = unsafeFreezeSmallArray marr
| otherwise = do
a <- indexSmallArrayM ary i
b <- f k a
writeSmallArray marr i b
(go (i + 1) $! k + step) marr
marr <- newSmallArray len undefinedElem
go 0 i0 marr
{-# INLINE itraverseStepSmallArrayP #-}