-- | -- Copyright: (C) 2013 Amgen, Inc. -- 2016 Tweag I/O Limited. -- -- Vectors that can be passed to and from R with no copying at all. These -- vectors are wrappers over SEXP vectors used by R. Memory for vectors is -- allocated from the R heap, and in such way that they can be converted to -- a 'SEXP' by simple pointer arithmetic (see 'toSEXP'). -- -- Like "Data.Vector.Storable.Mutable" vectors, the vector type in this module -- adds one extra level of indirection and a small amount of storage overhead -- for maintainging lengths and slice offsets. If you're keeping a very large -- number of tiny vectors in memory, you're better off keeping them as 'SEXP's -- and calling 'fromSEXP' on-the-fly. {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} module Data.Vector.SEXP.Mutable ( -- * Mutable slices of 'SEXP' vector types MVector , fromSEXP , toSEXP , release , unsafeRelease -- * Accessors -- ** Length information , length , null -- * Construction -- ** Initialisation , new , unsafeNew , replicate , replicateM , clone -- ** Extracting subvectors , slice , init , tail , take , drop , splitAt , unsafeSlice , unsafeInit , unsafeTail , unsafeTake , unsafeDrop -- ** Overlapping , overlaps -- ** Restricting memory usage , clear -- * Accessing individual elements , read , write , swap , unsafeRead , unsafeWrite , unsafeSwap -- * Modifying vectors -- ** Filling and copying , set , copy , move , unsafeCopy , unsafeMove ) where import Control.Monad.R.Class import Control.Monad.R.Internal import Data.Vector.SEXP.Base import Data.Vector.SEXP.Mutable.Internal import qualified Foreign.R as R import Foreign.R (SEXP) import Internal.Error import qualified Data.Vector.Generic.Mutable as G import Control.Applicative import Control.Arrow ((>>>), (***)) import Data.Proxy (Proxy(..)) import Data.Reflection (Reifies(..), reify) import System.IO.Unsafe (unsafePerformIO) import Prelude hiding ( length, drop, init, null, read, replicate, splitAt, tail, take ) -- Internal helpers -- ---------------- phony :: forall s ty a b. (VECTOR s ty a) => (forall t. Reifies t (AcquireIO s) => W t ty s a -> b) -> MVector s ty a -> b phony f v = reify (AcquireIO acquireIO) $ \(Proxy :: Proxy t) -> do f (W v :: W t ty s a) where acquireIO = violation "phony" "phony acquire called." phony2 :: forall s ty a b. (VECTOR s ty a) => (forall t. Reifies t (AcquireIO s) => W t ty s a -> W t ty s a -> b) -> MVector s ty a -> MVector s ty a -> b phony2 f v1 v2 = reify (AcquireIO acquireIO) $ \(Proxy :: Proxy t) -> do f (W $ v1 :: W t ty s a) (W $ v2 :: W t ty s a) where acquireIO = violation "phony2" "phony acquire called." -- Conversions -- ----------- -- | /O(1)/ Create a vector from a 'SEXP'. fromSEXP :: VECTOR s ty a => SEXP s ty -> MVector s ty a fromSEXP sx = MVector sx 0 $ unsafePerformIO $ do fromIntegral <$> R.length sx -- | /O(1)/ in the common case, /O(n)/ for proper slices. Convert a mutable -- vector to a 'SEXP'. This can be done efficiently, without copy, because -- vectors in this module always include a 'SEXP' header immediately before the -- vector data in memory. toSEXP :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> m (SEXP (Region m) ty) toSEXP (MVector sx 0 len) | len == sexplen = return sx where sexplen = unsafePerformIO $ do fromIntegral <$> R.length sx toSEXP v = toSEXP =<< clone v -- yield a zero based slice. -- Length information -- ------------------ -- | Length of the mutable vector. length :: VECTOR s ty a => MVector s ty a -> Int {-# INLINE length #-} length = phony G.length -- | Check whether the vector is empty. null :: VECTOR s ty a => MVector s ty a -> Bool {-# INLINE null #-} null = phony G.null -- Extracting subvectors -- --------------------- -- | Yield a part of the mutable vector without copying it. slice :: VECTOR s ty a => Int -> Int -> MVector s ty a -> MVector s ty a {-# INLINE slice #-} slice i j = phony (unW . G.slice i j) take :: VECTOR s ty a => Int -> MVector s ty a -> MVector s ty a {-# INLINE take #-} take n = phony (unW . G.take n) drop :: VECTOR s ty a => Int -> MVector s ty a -> MVector s ty a {-# INLINE drop #-} drop n = phony (unW . G.drop n) splitAt :: VECTOR s ty a => Int -> MVector s ty a -> (MVector s ty a, MVector s ty a) {-# INLINE splitAt #-} splitAt n = phony (G.splitAt n >>> unW *** unW) init :: VECTOR s ty a => MVector s ty a -> MVector s ty a {-# INLINE init #-} init = phony (unW . G.init) tail :: VECTOR s ty a => MVector s ty a -> MVector s ty a {-# INLINE tail #-} tail = phony (unW . G.tail) -- | Yield a part of the mutable vector without copying it. No bounds checks -- are performed. unsafeSlice :: VECTOR s ty a => Int -- ^ starting index -> Int -- ^ length of the slice -> MVector s ty a -> MVector s ty a {-# INLINE unsafeSlice #-} unsafeSlice i j = phony (unW . G.unsafeSlice i j) unsafeTake :: VECTOR s ty a => Int -> MVector s ty a -> MVector s ty a {-# INLINE unsafeTake #-} unsafeTake n = phony (unW . G.unsafeTake n) unsafeDrop :: VECTOR s ty a => Int -> MVector s ty a -> MVector s ty a {-# INLINE unsafeDrop #-} unsafeDrop n = phony (unW . G.unsafeDrop n) unsafeInit :: VECTOR s ty a => MVector s ty a -> MVector s ty a {-# INLINE unsafeInit #-} unsafeInit = phony (unW . G.unsafeInit) unsafeTail :: VECTOR s ty a => MVector s ty a -> MVector s ty a {-# INLINE unsafeTail #-} unsafeTail = phony (unW . G.unsafeTail) -- Overlapping -- ----------- -- | Check whether two vectors overlap. overlaps :: VECTOR s ty a => MVector s ty a -> MVector s ty a -> Bool {-# INLINE overlaps #-} overlaps = phony2 G.overlaps -- Initialisation -- -------------- -- | Create a mutable vector of the given length. new :: forall m ty a. (MonadR m, VECTOR (Region m) ty a) => Int -> m (MVector (Region m) ty a) {-# INLINE new #-} new n = withAcquire $ proxyW $ G.new n -- | Create a mutable vector of the given length. The length is not checked. unsafeNew :: (MonadR m, VECTOR (Region m) ty a) => Int -> m (MVector (Region m) ty a) {-# INLINE unsafeNew #-} unsafeNew n = withAcquire $ proxyW $ G.unsafeNew n -- | Create a mutable vector of the given length (0 if the length is negative) -- and fill it with an initial value. replicate :: (MonadR m, VECTOR (Region m) ty a) => Int -> a -> m (MVector (Region m) ty a) {-# INLINE replicate #-} replicate n x = withAcquire $ proxyW $ G.replicate n x -- | Create a mutable vector of the given length (0 if the length is negative) -- and fill it with values produced by repeatedly executing the monadic action. replicateM :: (MonadR m, VECTOR (Region m) ty a) => Int -> m a -> m (MVector (Region m) ty a) {-# INLINE replicateM #-} replicateM n m = withAcquire $ proxyW $ G.replicateM n m -- | Create a copy of a mutable vector. clone :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> m (MVector (Region m) ty a) {-# INLINE clone #-} clone v = withAcquire $ proxyW $ G.clone (W v) -- Restricting memory usage -- ------------------------ -- | Reset all elements of the vector to some undefined value, clearing all -- references to external objects. This is usually a noop for unboxed vectors. clear :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> m () {-# INLINE clear #-} clear v = withAcquire $ \p -> G.clear (withW p v) -- Accessing individual elements -- ----------------------------- -- | Yield the element at the given position. read :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> m a {-# INLINE read #-} read v i = withAcquire $ \p -> G.read (withW p v) i -- | Replace the element at the given position. write :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> a -> m () {-# INLINE write #-} write v i x = withAcquire $ \p -> G.write (withW p v) i x -- | Swap the elements at the given positions. swap :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> Int -> m () {-# INLINE swap #-} swap v i j = withAcquire $ \p -> G.swap (withW p v) i j -- | Yield the element at the given position. No bounds checks are performed. unsafeRead :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> m a {-# INLINE unsafeRead #-} unsafeRead v i = withAcquire $ \p -> G.unsafeRead (withW p v) i -- | Replace the element at the given position. No bounds checks are performed. unsafeWrite :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> a -> m () {-# INLINE unsafeWrite #-} unsafeWrite v i x = withAcquire $ \p -> G.unsafeWrite (withW p v) i x -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> Int -> Int -> m () {-# INLINE unsafeSwap #-} unsafeSwap v i j = withAcquire $ \p -> G.unsafeSwap (withW p v) i j -- Filling and copying -- ------------------- -- | Set all elements of the vector to the given value. set :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> a -> m () {-# INLINE set #-} set v x = withAcquire $ \p -> G.set (withW p v) x -- | Copy a vector. The two vectors must have the same length and may not -- overlap. copy :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> MVector (Region m) ty a -> m () {-# INLINE copy #-} copy v1 v2 = withAcquire $ \p -> G.copy (withW p v1) (withW p v2) -- | Copy a vector. The two vectors must have the same length and may not -- overlap. This is not checked. unsafeCopy :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -- ^ target -> MVector (Region m) ty a -- ^ source -> m () {-# INLINE unsafeCopy #-} unsafeCopy v1 v2 = withAcquire $ \p -> G.unsafeCopy (withW p v1) (withW p v2) -- | Move the contents of a vector. The two vectors must have the same -- length. -- -- If the vectors do not overlap, then this is equivalent to 'copy'. -- Otherwise, the copying is performed as if the source vector were -- copied to a temporary vector and then the temporary vector was copied -- to the target vector. move :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -> MVector (Region m) ty a -> m () {-# INLINE move #-} move v1 v2 = withAcquire $ \p -> G.move (withW p v1) (withW p v2) -- | Move the contents of a vector. The two vectors must have the same -- length, but this is not checked. -- -- If the vectors do not overlap, then this is equivalent to 'unsafeCopy'. -- Otherwise, the copying is performed as if the source vector were -- copied to a temporary vector and then the temporary vector was copied -- to the target vector. unsafeMove :: (MonadR m, VECTOR (Region m) ty a) => MVector (Region m) ty a -- ^ target -> MVector (Region m) ty a -- ^ source -> m () {-# INLINE unsafeMove #-} unsafeMove v1 v2 = withAcquire $ \p -> G.unsafeMove (withW p v1) (withW p v2)