{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE CPP #-}
module Data.Grid.Storable
(
Grid
, InternalGrid
, I.length
, (I.!) , (I.!?), I.head, I.last
, I.unsafeIndex, I.unsafeHead, I.unsafeLast
, I.slice, I.init, I.tail, I.take, I.drop
, fromVector
, toList
, reverse
, unsafeToForeignPtr0
)
where
import Control.Monad
import Control.DeepSeq
import Control.Exception
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid
#endif
#if !MIN_VERSION_base(4,8,0)
import Data.Functor( (<$>) )
#endif
import qualified Data.Vector as V
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as VSM
import Foreign ( ForeignPtr, Storable , advancePtr
, touchForeignPtr , newForeignPtr_
, withForeignPtr
)
import System.IO.Unsafe
import qualified Data.Grid.Storable.Internal as I
type InternalGrid = I.Grid
type Grid a = InternalGrid a (VS.Vector a)
{-# ANN module ("HLint: ignore Eta reduce"::String) #-}
{-# ANN module ("HLint: ignore Use camelCase"::String) #-}
fromVector :: (Storable el) =>
Int -> Int -> VS.Vector el -> Grid el
fromVector w h vec = unsafePerformIO $ do
when (w < 1 || h < 1) $
error $ "width and height must be > 0, were: " <> show (w,h)
when ( (w * h) > VS.length vec ) $
error $ "vec not big enough to hold width " <> show w
<> " x height " <> show h
mvec <- VS.thaw vec
let (fptr, _flen) = VSM.unsafeToForeignPtr0 mvec
offsets = take h [0, 0+w ..]
rows <- withForeignPtr fptr $ \mptr ->
mapM (mk_row . advancePtr mptr) offsets
let g = I.Grid (V.fromList rows) fptr
return g
where
mk_row ptr = (`VS.unsafeFromForeignPtr0` w) <$> newForeignPtr_ ptr
toList ::
(Storable a, NFData a) => Grid a -> IO [V.Vector a]
toList grid = do
let
vecs = map VS.convert $ I.toList grid
fptr = unsafeToForeignPtr0 grid
vecs <- evaluate $ force vecs
touchForeignPtr fptr
return vecs
unsafeToForeignPtr0 :: Grid el -> ForeignPtr el
unsafeToForeignPtr0 (I.Grid _ ptr) = ptr