{-# LANGUAGE CPP, MultiParamTypeClasses, BangPatterns, TypeFamilies #-}
-- |
-- Module      : Data.Vector.Generic.Mutable.Base
-- Copyright   : (c) Roman Leshchinskiy 2008-2011
-- License     : BSD-style
--
-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
-- Stability   : experimental
-- Portability : non-portable
--
-- Class of mutable vectors
--

module Data.Vector.Generic.Mutable.Base (
  MVector(..)
) where

import Control.Monad.Primitive ( PrimMonad, PrimState )

-- Data.Vector.Internal.Check is unused
#define NOT_VECTOR_MODULE
#include "vector.h"

-- | Class of mutable vectors parametrised with a primitive state token.
--
class MVector v a where
  -- | Length of the mutable vector. This method should not be
  -- called directly, use 'length' instead.
  basicLength       :: v s a -> Int

  -- | Yield a part of the mutable vector without copying it. This method
  -- should not be called directly, use 'unsafeSlice' instead.
  basicUnsafeSlice :: Int  -- ^ starting index
                   -> Int  -- ^ length of the slice
                   -> v s a
                   -> v s a

  -- | Check whether two vectors overlap. This method should not be
  -- called directly, use 'overlaps' instead.
  basicOverlaps    :: v s a -> v s a -> Bool

  -- | Create a mutable vector of the given length. This method should not be
  -- called directly, use 'unsafeNew' instead.
  basicUnsafeNew   :: PrimMonad m => Int -> m (v (PrimState m) a)

  -- | Initialize a vector to a standard value. This is intended to be called as
  -- part of the safe new operation (and similar operations), to properly blank
  -- the newly allocated memory if necessary.
  --
  -- Vectors that are necessarily initialized as part of creation may implement
  -- this as a no-op.
  --
  -- @since 0.11.0.0
  basicInitialize :: PrimMonad m => v (PrimState m) a -> m ()

  -- | Create a mutable vector of the given length and fill it with an
  -- initial value. This method should not be called directly, use
  -- 'replicate' instead.
  basicUnsafeReplicate :: PrimMonad m => Int -> a -> m (v (PrimState m) a)

  -- | Yield the element at the given position. This method should not be
  -- called directly, use 'unsafeRead' instead.
  basicUnsafeRead  :: PrimMonad m => v (PrimState m) a -> Int -> m a

  -- | Replace the element at the given position. This method should not be
  -- called directly, use 'unsafeWrite' instead.
  basicUnsafeWrite :: PrimMonad m => v (PrimState m) a -> Int -> a -> m ()

  -- | Reset all elements of the vector to some undefined value, clearing all
  -- references to external objects. This is usually a noop for unboxed
  -- vectors. This method should not be called directly, use 'clear' instead.
  basicClear       :: PrimMonad m => v (PrimState m) a -> m ()

  -- | Set all elements of the vector to the given value. This method should
  -- not be called directly, use 'set' instead.
  basicSet         :: PrimMonad m => v (PrimState m) a -> a -> m ()

  -- | Copy a vector. The two vectors may not overlap. This method should not
  -- be called directly, use 'unsafeCopy' instead.
  basicUnsafeCopy  :: PrimMonad m => v (PrimState m) a   -- ^ target
                                  -> v (PrimState m) a   -- ^ source
                                  -> m ()

  -- | Move the contents of a vector. The two vectors may overlap. This method
  -- should not be called directly, use 'unsafeMove' instead.
  basicUnsafeMove  :: PrimMonad m => v (PrimState m) a   -- ^ target
                                  -> v (PrimState m) a   -- ^ source
                                  -> m ()

  -- | Grow a vector by the given number of elements. Allocates a new vector and
  -- copies all of the elements over starting at 0 index. This method should not
  -- be called directly, use 'grow'\/'unsafeGrow' instead.
  basicUnsafeGrow  :: PrimMonad m => v (PrimState m) a
                                  -> Int
                                  -> m (v (PrimState m) a)

  {-# INLINE basicUnsafeReplicate #-}
  basicUnsafeReplicate Int
n a
x
    = do
        v (PrimState m) a
v <- Int -> m (v (PrimState m) a)
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
Int -> m (v (PrimState m) a)
basicUnsafeNew Int
n
        v (PrimState m) a -> a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> a -> m ()
basicSet v (PrimState m) a
v a
x
        v (PrimState m) a -> m (v (PrimState m) a)
forall (m :: * -> *) a. Monad m => a -> m a
return v (PrimState m) a
v

  {-# INLINE basicClear #-}
  basicClear v (PrimState m) a
_ = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

  {-# INLINE basicSet #-}
  basicSet !v (PrimState m) a
v a
x
    | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0    = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    | Bool
otherwise = do
                    v (PrimState m) a -> Int -> a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> Int -> a -> m ()
basicUnsafeWrite v (PrimState m) a
v Int
0 a
x
                    Int -> m ()
do_set Int
1
    where
      !n :: Int
n = v (PrimState m) a -> Int
forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
basicLength v (PrimState m) a
v

      do_set :: Int -> m ()
do_set Int
i | Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n = do v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy (Int -> Int -> v (PrimState m) a -> v (PrimState m) a
forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
basicUnsafeSlice Int
i Int
i v (PrimState m) a
v)
                                              (Int -> Int -> v (PrimState m) a -> v (PrimState m) a
forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
basicUnsafeSlice Int
0 Int
i v (PrimState m) a
v)
                              Int -> m ()
do_set (Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
i)
               | Bool
otherwise = v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy (Int -> Int -> v (PrimState m) a -> v (PrimState m) a
forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
basicUnsafeSlice Int
i (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
i) v (PrimState m) a
v)
                                             (Int -> Int -> v (PrimState m) a -> v (PrimState m) a
forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
basicUnsafeSlice Int
0 (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
i) v (PrimState m) a
v)

  {-# INLINE basicUnsafeCopy #-}
  basicUnsafeCopy !v (PrimState m) a
dst !v (PrimState m) a
src = Int -> m ()
do_copy Int
0
    where
      !n :: Int
n = v (PrimState m) a -> Int
forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
basicLength v (PrimState m) a
src

      do_copy :: Int -> m ()
do_copy Int
i | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n = do
                            a
x <- v (PrimState m) a -> Int -> m a
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> Int -> m a
basicUnsafeRead v (PrimState m) a
src Int
i
                            v (PrimState m) a -> Int -> a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> Int -> a -> m ()
basicUnsafeWrite v (PrimState m) a
dst Int
i a
x
                            Int -> m ()
do_copy (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
                | Bool
otherwise = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

  {-# INLINE basicUnsafeMove #-}
  basicUnsafeMove !v (PrimState m) a
dst !v (PrimState m) a
src
    | v (PrimState m) a -> v (PrimState m) a -> Bool
forall (v :: * -> * -> *) a s.
MVector v a =>
v s a -> v s a -> Bool
basicOverlaps v (PrimState m) a
dst v (PrimState m) a
src = do
        v (PrimState m) a
srcCopy <- Int -> m (v (PrimState m) a)
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
Int -> m (v (PrimState m) a)
basicUnsafeNew (v (PrimState m) a -> Int
forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
basicLength v (PrimState m) a
src)
        v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy v (PrimState m) a
srcCopy v (PrimState m) a
src
        v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy v (PrimState m) a
dst v (PrimState m) a
srcCopy
    | Bool
otherwise = v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy v (PrimState m) a
dst v (PrimState m) a
src

  {-# INLINE basicUnsafeGrow #-}
  basicUnsafeGrow v (PrimState m) a
v Int
by
    = do
        v (PrimState m) a
v' <- Int -> m (v (PrimState m) a)
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
Int -> m (v (PrimState m) a)
basicUnsafeNew (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
by)
        v (PrimState m) a -> v (PrimState m) a -> m ()
forall (v :: * -> * -> *) a (m :: * -> *).
(MVector v a, PrimMonad m) =>
v (PrimState m) a -> v (PrimState m) a -> m ()
basicUnsafeCopy (Int -> Int -> v (PrimState m) a -> v (PrimState m) a
forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
basicUnsafeSlice Int
0 Int
n v (PrimState m) a
v') v (PrimState m) a
v
        v (PrimState m) a -> m (v (PrimState m) a)
forall (m :: * -> *) a. Monad m => a -> m a
return v (PrimState m) a
v'
    where
      n :: Int
n = v (PrimState m) a -> Int
forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
basicLength v (PrimState m) a
v

  {-# MINIMAL basicLength, basicUnsafeSlice, basicOverlaps,
              basicUnsafeNew, basicInitialize, basicUnsafeRead,
              basicUnsafeWrite #-}