{- |
Functions that may be useful, but I'm uncertain.
-}
module Data.StorableVector.Private where
import Data.StorableVector (empty, unfoldrN, viewL, length, )
import Data.StorableVector.Base
import qualified Data.Strictness.HT as Strict
import Foreign.Storable (Storable(..))
import qualified System.Unsafe as Unsafe
import Control.DeepSeq (NFData, rnf, deepseq, )
import Prelude hiding (length, )
{- |
This implementation is based on viewL
and thus not as fast as possible.
-}
zipWithViewL :: (Storable a, Storable b, Storable c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
zipWithViewL f ps0 qs0 =
fst $ unfoldrN
(min (length ps0) (length qs0))
(\(ps,qs) ->
do (ph,pt) <- viewL ps
(qh,qt) <- viewL qs
return (f ph qh, (pt,qt)))
(ps0,qs0)
zipWithIndex :: (Storable a, Storable b, Storable c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
zipWithIndex f ps qs =
fst $ unfoldrN
(min (length ps) (length qs))
(\i -> Just (f (unsafeIndex ps i) (unsafeIndex qs i), succ i))
0
unfoldrStrictN :: (Storable b, NFData a) => Int -> (a -> Maybe (b, a)) -> a -> (Vector b, Maybe a)
-- unfoldrStrictN :: (Storable b) => Int -> (a -> Maybe (b, a)) -> a -> (Vector b, Maybe a)
unfoldrStrictN i f x0 =
if i <= 0
then (empty, Just x0)
else Unsafe.performIO $ createAndTrim' i $ \p -> go p 0 x0
{-
go must not be strict in the accumulator
since otherwise packN would be too strict.
-}
where
go = Strict.arguments3 $ \p n -> \x ->
if n == i
then return (0, n, Just x)
else
case f x of
Nothing -> return (0, n, Nothing)
Just (w,x') -> do poke p w
-- go (incPtr p) (n+1) $! x'
go (incPtr p) (n+1) (x' `deepseq` x')
-- seq (rnf x') (((go $! incPtr p) $! n+1) $! x')
{-# INLINE unfoldrStrictN #-}
unfoldrTransitionN :: (Storable b) => Int -> (a -> a) -> (a -> Maybe b) -> a -> (Vector b, a)
unfoldrTransitionN n trans emit x =
if n <= 0
then (empty, x)
else Unsafe.performIO $ createAndTrim' n $ \p ->
case emit x of
Nothing -> return (0, n, x)
Just y0 -> poke p y0 >>
{-
go must not be strict in the accumulator
since otherwise packN would be too strict.
-}
let go = Strict.arguments2 $ \p0 i0 -> \x0 ->
{-
We run 'emit' in order to evaluate the new state.
We need to return this new state
also in case the array is full.
The drawback is, that the whole vector becomes undefined
if only the state after the last element is undefined.
This is the same situation as in an unfoldr with strict state.
-}
let i1 = i0-1
x1 = trans x0
in case emit x1 of
Nothing -> return (0, n-i1, x1)
Just y1 ->
if i1 == 0
then return (0, n, x1)
else
let p1 = incPtr p0
in do poke p1 y1
go p1 i1 x1
{-
let i1 = i0-1
in if i1 == 0
then return (0, n, x0)
else
let x1 = trans x0
p1 = incPtr p0
in case emit x1 of
Nothing -> return (0, n-i1, x1)
Just y1 -> do poke p1 y1
go p1 i1 x1
-}
in go p n x
{-# INLINE unfoldrTransitionN #-}
-- | /O(n)/ Like 'unfoldrN' this function builds a 'Vector' from a seed
-- value. However, it does always return a state value.
-- The vector construction can be aborted either by reaching
-- the given maximum size or by returning 'Nothing' as element.
--
-- The following equation relates 'unfoldrN' and 'unfoldrStateN':
--
-- > unfoldrN n f s ==
-- > unfoldrStateN n
-- > (maybe (error "state will be always Just")
-- > ((\a -> (fmap fst a, fmap snd a)) . f))
-- > (Just s)
--
-- It is not possible to express 'unfoldrNState' in terms of 'unfoldrN'.
--
unfoldrStateN :: (Storable b) => Int -> (a -> (Maybe b, a)) -> a -> (Vector b, a)
unfoldrStateN i f x0 =
if i <= 0
then (empty, x0)
else Unsafe.performIO $ createAndTrim' i $ \p -> go p 0 x0
{-
go must not be strict in the accumulator
since otherwise packN would be too strict.
-}
where
go = Strict.arguments2 $ \p n -> \x ->
if n == i
then return (0, n, x)
else
let (my,x') = f x
in case my of
Nothing -> return (0, n, x)
Just w -> do poke p w
go (incPtr p) (n+1) x'
{-# INLINE unfoldrStateN #-}