{-# LANGUAGE UndecidableInstances #-}

-- | Low level interface to parallel array filling operators.
module Data.Array.Repa.Eval
        ( -- * Element types
          Elt       (..)

        -- * Parallel array filling
        , Fillable  (..)
        , Fill      (..)
        , FillRange (..)
        , fromList
        
        -- * Converting between representations
        , computeP, computeS
        , copyP,    copyS
        , now
        
        -- * Chunked filling
        , fillChunkedS
        , fillChunkedP
        , fillChunkedIOP

        -- * Blockwise filling
        , fillBlock2P
        , fillBlock2S
        
        -- * Cursored blockwise filling
        , fillCursoredBlock2S
        , fillCursoredBlock2P
        
        -- * Chunked selection
        , selectChunkedS
        , selectChunkedP)
where
import Data.Array.Repa.Eval.Elt
import Data.Array.Repa.Eval.Fill
import Data.Array.Repa.Eval.Chunked
import Data.Array.Repa.Eval.Cursored
import Data.Array.Repa.Eval.Selection
import Data.Array.Repa.Repr.Delayed
import Data.Array.Repa.Base
import Data.Array.Repa.Shape
import System.IO.Unsafe


-- | Parallel computation of array elements.
--
--   * The `Fill` class is defined so that the source array must have a
--     delayed representation (`D` or `C`)
--
--   * If you want to copy data between manifest representations then use
--    `copyP` instead.
--
--   * If you want to convert a manifest array back to a delayed representation
--     then use `delay` instead.
--
computeP :: Fill r1 r2 sh e
        => Array r1 sh e -> Array r2 sh e
{-# INLINE [4] computeP #-}
computeP arr1
 = arr1 `deepSeqArray` 
   unsafePerformIO
 $ do   marr2    <- newMArr (size $ extent arr1) 
        fillP arr1 marr2
        unsafeFreezeMArr (extent arr1) marr2


-- | Sequential computation of array elements.
computeS 
        :: Fill r1 r2 sh e
        => Array r1 sh e -> Array r2 sh e
{-# INLINE [4] computeS #-}
computeS arr1
 = arr1 `deepSeqArray` 
   unsafePerformIO
 $ do   marr2    <- newMArr (size $ extent arr1) 
        fillS arr1 marr2
        unsafeFreezeMArr (extent arr1) marr2




-- | Parallel copying of arrays.
--
--   * This is a wrapper that delays an array before calling `computeP`. 
-- 
--   * You can use it to copy manifest arrays between representations.
--
--   * You can also use it to compute elements, but doing this may not be as
--     efficient. This is because delaying it the second time can hide
--     information about the structure of the original computation.
--
copyP   :: (Repr r1 e, Fill D r2 sh e)
        => Array r1 sh e -> Array r2 sh e
{-# INLINE [4] copyP #-}
copyP arr1 = computeP $ delay arr1


-- | Sequential copying of arrays.
copyS   :: (Repr r1 e, Fill D r2 sh e)
        => Array r1 sh e -> Array r2 sh e
{-# INLINE [4] copyS #-}
copyS arr1 = computeS $ delay arr1


        

-- | Apply `deepSeqArray` to an array so the result is actually constructed
--   at this point in a monadic computation. 
--
--   * Haskell's laziness means that applications of `computeP` and `copyP` are
--     automatically suspended.
--
--   * Laziness can be problematic for data parallel programs, because we want
--     each array to be constructed in parallel before moving onto the next one.
--   
--   For example:
--
--   @ do  arr2 <- now $ computeP $ map f arr1
--     arr3 <- now $ computeP $ zipWith arr2 arr1
--     return arr3
--   @
--
now     :: (Shape sh, Repr r e, Monad m)
        => Array r sh e -> m (Array r sh e)
{-# INLINE [4] now #-}
now arr
 = do   arr `deepSeqArray` return ()
        return arr