content: -- |
  -- 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)
  