sdp-0.2: src/SDP/Prim/TArray.hs
{-# LANGUAGE Trustworthy, MagicHash, MultiParamTypeClasses, FlexibleInstances #-}
{- |
Module : SDP.Prim.TArray
Copyright : (c) Andrey Mulik 2020
License : BSD-style
Maintainer : work.a.mulik@gmail.com
Portability : non-portable
"SDP.Prim.TArray" provides lazy boxed array of @stm@ 'TVar's.
Note that 'TArray#' stores each element in 'TVar'.
-}
module SDP.Prim.TArray
(
-- TArray
TArray# (..), STM, TVar
)
where
import Prelude ()
import SDP.SafePrelude
import SDP.Prim.SArray
import GHC.Conc
import Control.Exception.SDP
default ()
--------------------------------------------------------------------------------
-- | 'SArray#' of @stm@ 'TVar's.
newtype TArray# e = TArray# (SArray# (TVar e)) deriving ( Eq )
--------------------------------------------------------------------------------
{- Nullable, Estimate, Bordered and BorderedM instances. -}
instance Nullable (TArray# e)
where
isNull = \ (TArray# es) -> isNull es
lzero = TArray# Z
instance Estimate (TArray# e)
where
(<==>) = on (<=>) sizeOf
(.<=.) = on (<=) sizeOf
(.>=.) = on (>=) sizeOf
(.>.) = on (>) sizeOf
(.<.) = on (<) sizeOf
(<.=>) = (<=>) . sizeOf
(.>=) = (>=) . sizeOf
(.<=) = (<=) . sizeOf
(.>) = (>) . sizeOf
(.<) = (<) . sizeOf
instance Bordered (TArray# e) Int
where
lower _ = 0
upper (TArray# arr) = upper arr
sizeOf (TArray# arr) = sizeOf arr
bounds (TArray# arr) = (0, upper arr)
indices (TArray# arr) = [0 .. upper arr]
indexOf (TArray# arr) = index (0, upper arr)
offsetOf (TArray# arr) = offset (0, upper arr)
indexIn (TArray# arr) = \ i -> i >= 0 && i < sizeOf arr
instance BorderedM STM (TArray# e) Int
where
getIndexOf = return ... indexOf
getIndices = return . indices
getBounds = return . bounds
getSizeOf = return . sizeOf
getUpper = return . upper
getLower _ = return 0
--------------------------------------------------------------------------------
{- LinearM and SplitM instances. -}
instance LinearM STM (TArray# e) e
where
newNull = return (TArray# Z)
nowNull = return . isNull . unpack
getHead = readTVar . head . unpack
getLast = readTVar . last . unpack
singleM = fmap (TArray# . single) . newTVar
prepend e es = TArray# . (:> unpack es) <$> newTVar e
append es e = TArray# . (unpack es :<) <$> newTVar e
newLinear = fmap (TArray# . fromList) . mapM newTVar
newLinearN n = fmap (TArray# . fromListN n) . mapM newTVar
fromFoldableM = fmap (TArray# . fromList) . foldr (liftA2 (:) . newTVar) (return [])
(!#>) = readTVar ... (!^) . unpack
writeM = writeM'
getLeft = mapM readTVar . listL . unpack
getRight = mapM readTVar . listR . unpack
merged = return . TArray# . concatMap unpack
reversed = return . TArray# . reverse . unpack
filled n = fmap (TArray# . fromList) . replicateM n . newTVar
copyTo src so trg to n = when (n > 0) $ do
when (so < 0 || to < 0) $ underEx "copyTo"
when (so + n > n1 || to + n > n2) $ overEx "copyTo"
go so to n
where
go _ _ 0 = return ()
go i j c = do e <- src !#> i; writeM trg j e; go (i + 1) (j + 1) (c - 1)
n1 = sizeOf src
n2 = sizeOf trg
ofoldlM f base = ofoldl (\ i es -> ($ f i) . (es >>=<<) . readTVar) (return base) . unpack
ofoldrM f base = ofoldr (\ i -> ($ f i) ... (>>=<<) . readTVar) (return base) . unpack
foldlM f base = foldl (\ es -> ($ f) . (es >>=<<) . readTVar) (return base) . unpack
foldrM f base = foldr (($ f) ... (>>=<<) . readTVar) (return base) . unpack
instance SplitM STM (TArray# e) e
where
takeM n = return . TArray# . take n . unpack
dropM n = return . TArray# . drop n . unpack
keepM n = return . TArray# . keep n . unpack
sansM n = return . TArray# . sans n . unpack
prefixM p es =
let
go i = i >= c ? return c $ do e <- es !#> i; p e ? go (succ 1) $ return i
c = sizeOf es
in go 0
suffixM p es =
let
go i = i < 0 ? return c $ do e <- es !#> i; p e ? go (pred i) $ return (c - i - 1)
c = sizeOf es
in go (c - 1)
mprefix p es =
let
go i = i >= c ? return c $ do e <- es !#> i; p e ?^ go (succ 1) $ return i
c = sizeOf es
in go 0
msuffix p es =
let
go i = i < 0 ? return c $ do e <- es !#> i; p e ?^ go (pred i) $ return (c - i - 1)
c = sizeOf es
in go (c - 1)
--------------------------------------------------------------------------------
{- MapM and IndexedM instances. -}
instance MapM STM (TArray# e) Int e
where
newMap' defvalue ascs = fromAssocs' (ascsBounds ascs) defvalue ascs
(>!) = (!#>)
overwrite es ascs = do
mapM_ (uncurry $ writeM es) (filter (indexIn es . fst) ascs)
return es
kfoldrM = ofoldrM
kfoldlM = ofoldlM
instance IndexedM STM (TArray# e) Int e
where
fromAssocs' bnds defvalue ascs = size bnds `filled` defvalue >>= (`overwrite` ascs)
{-# INLINE writeM' #-}
writeM' = writeTVar ... (!^) . unpack
fromIndexed' es = do
let n = sizeOf es
copy <- filled n (unreachEx "fromIndexed'")
forM_ [0 .. n - 1] $ \ i -> writeM copy i (es !^ i)
return copy
fromIndexedM es = do
n <- getSizeOf es
copy <- filled n (unreachEx "fromIndexedM")
forM_ [0 .. n - 1] $ \ i -> es !#> i >>= writeM copy i
return copy
--------------------------------------------------------------------------------
{- Freeze and Thaw instances. -}
instance Thaw STM (SArray# e) (TArray# e) where thaw = fmap TArray# . mapM newTVar
instance Freeze STM (TArray# e) (SArray# e) where freeze = mapM readTVar . unpack
--------------------------------------------------------------------------------
ascsBounds :: (Ord a) => [(a, b)] -> (a, a)
ascsBounds = \ ((x, _) : xs) -> foldr (\ (e, _) (mn, mx) -> (min mn e, max mx e)) (x, x) xs
unpack :: TArray# e -> SArray# (TVar e)
unpack = \ (TArray# arr) -> arr
overEx :: String -> a
overEx = throw . IndexOverflow . showString "in SDP.Prim.TArray."
underEx :: String -> a
underEx = throw . IndexUnderflow . showString "in SDP.Prim.TArray."
unreachEx :: String -> a
unreachEx = throw . UnreachableException . showString "in SDP.Prim.TArray."