----------------------------------------------------------------------------- -- | -- Module : Data.Array.Parallel.BBArr -- Copyright : (c) [2001..2002] Manuel M T Chakravarty & Gabriele Keller -- (c) [2006..2007] Manuel M T Chakravarty & Roman Leshchinskiy -- License : see libraries/ndp/LICENSE -- -- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au> -- Stability : internal -- Portability : non-portable -- -- -- This module defines two-phase boxed arrays which are strict in all -- elements which have been initialised. It is ok not to initialise some -- elements as long as we don't access them. Initialising an element with -- bottom diverges. -- -- This means that in -- -- > let arr = runST (newMBB n >>= unsafeFreezeMBB) -- -- @arr@ itself is defined but @arr `indexBB` i@ diverges for all @i@. In -- -- > let brr = runST (do mb <- newMBB n -- > <initialise all elements except at index 2> -- > unsafeFreezeMBB mb) -- -- @brr `indexBB` i@ diverges for @i=2@ and converges otherwise. -- -- Thus, our arrays effectively model strict collections of (index,value) -- pairs but do not require the indices to be contiguous. -- -- Internally, we do use bottoms for uninitialised elements in the underlying -- GHC array; however, @writeMBB@ is strict in the value being written. -- Indexing into the array can never yield a thunk if the elements are -- hyperstrict but can diverge (which is ok). Hence, we can say that the -- arrays are hyperstrict for hyperstrict elements even though the underlying -- representation is not. -- -- The reason for this slightly peculiar (but sound, in my opinion) model are -- distributed 'MaybeS's. -- module Data.Array.Parallel.Arr.BBArr ( -- * Types BBArr, MBBArr, -- * Operations on immutable arrays lengthBB, indexBB, extractBB, -- * Operations on mutable arrays newMBB, lengthMBB, readMBB, writeMBB, unsafeFreezeMBB, unsafeFreezeAllMBB, extractMBB, copyMBB ) where -- standard library import Control.Monad (liftM) -- GHC-internal definitions import GHC.Prim (unsafeFreezeArray#) import GHC.Arr (Array(..), STArray(..), bounds, boundsSTArray, (!), newSTArray, readSTArray, writeSTArray) -- NDP library import Data.Array.Parallel.Base ( HS, ST(..), runST, checkLen) infixl 9 `indexBB`, `readMBB` -- Boxed arrays -- ------------ -- | Immutable boxed arrays -- newtype BBArr e = BBArr (Array Int e) -- |Mutable boxed arrays -- newtype MBBArr s e = MBBArr (STArray s Int e) instance HS e => HS (BBArr e) -- |Length of an immutable boxed array -- lengthBB :: BBArr e -> Int lengthBB (BBArr arr) = (+ 1) . snd . bounds $ arr -- |Length of a mutable boxed array -- lengthMBB :: MBBArr s e -> Int lengthMBB (MBBArr marr) = (+ 1) . snd . boundsSTArray $ marr -- |Allocate a boxed array -- newMBB :: Int -> ST s (MBBArr s e) newMBB n = liftM MBBArr (newSTArray (0, n - 1) bottomBBArrElem) -- |Access an element in an immutable, boxed array -- indexBB :: BBArr e -> Int -> e indexBB (BBArr arr) = (arr!) -- |Access an element in an mutable, boxed array -- readMBB :: MBBArr s e -> Int -> ST s e readMBB (MBBArr marr) = readSTArray marr -- |Update an element in an mutable, boxed array -- writeMBB :: MBBArr s e -> Int -> e -> ST s () writeMBB (MBBArr marr) e = e `seq` writeSTArray marr e -- |Turn a mutable into an immutable array WITHOUT copying its contents, which -- implies that the mutable array must not be mutated anymore after this -- operation has been executed. -- -- * The explicit size parameter supports partially filled arrays (and must be -- less than or equal the size used when allocating the mutable array) -- unsafeFreezeMBB :: MBBArr s e -> Int -> ST s (BBArr e) {-# INLINE unsafeFreezeMBB #-} unsafeFreezeMBB (MBBArr (STArray _ m1 _ marr#)) n = checkLen "PAPrim.unsafeFreezeMB: " (m1 + 1) n $ ST $ \s1# -> case unsafeFreezeArray# marr# s1# of {(# s2#, arr# #) -> (# s2#, BBArr (Array 0 (n - 1) n arr#) #)} -- |Turn a mutable into an immutable array WITHOUT copying its contents, which -- implies that the mutable array must not be mutated anymore after this -- operation has been executed. -- -- * In contrast to 'unsafeFreezeMBB', this operation always freezes the -- entire array. -- unsafeFreezeAllMBB :: MBBArr s e -> ST s (BBArr e) unsafeFreezeAllMBB marr = unsafeFreezeMBB marr (lengthMBB marr) -- |Extract a slice from an array (given by its start index and length) -- extractBB :: BBArr e -> Int -> Int -> BBArr e {-# INLINE extractBB #-} extractBB arr i n = runST (do ma@(MBBArr sta) <- newMBB n copy0 sta unsafeFreezeMBB ma n ) where fence = n `min` (lengthBB arr - i) copy0 sta = copy 0 where copy off | off == fence = return () | otherwise = do -- Do not use writeMBB here because it is -- strict but we want to be able to copy -- arrays with uninitialised elements. -- This is ok because we know that -- initialised elements in the original -- array have already been evaluated by a -- writeMBB. writeSTArray sta off (arr `indexBB` (i + off)) copy (off + 1) bottomBBArrElem = error "PAPrim: Touched an uninitialised element in a `BBArr'" -- |Extract a slice from a mutable array (the slice is immutable) -- extractMBB :: MBBArr s e -> Int -> Int -> ST s (BBArr e) extractMBB arr i n = do arr' <- unsafeFreezeMBB arr (i + n) return $ extractBB arr' i n -- |Copy a the contents of an immutable array into a mutable array from the -- specified position on -- copyMBB :: MBBArr s e -> Int -> BBArr e -> ST s () copyMBB marr i arr = ins i 0 where n = lengthBB arr -- ins i j | j == n = return () | otherwise = do writeMBB marr i (arr `indexBB` j) ins (i + 1) (j + 1) -- Show instance -- instance Show e => Show (BBArr e) where showsPrec _ a = showString "toBB " . showList [a `indexBB` i | i <- [0..lengthBB a - 1]]