packages feed

grow-vector 0.1.2.0 → 0.1.3.0

raw patch · 6 files changed

+786/−2 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Vector.Grow: GrowVector :: !MutVar s (MVector s a) -> !MutVar s Int -> GrowVector s a
+ Data.Vector.Grow: [growVectorLength] :: GrowVector s a -> !MutVar s Int
+ Data.Vector.Grow: [growVector] :: GrowVector s a -> !MutVar s (MVector s a)
+ Data.Vector.Grow: capacity :: PrimMonad m => GrowVector (PrimState m) a -> m Int
+ Data.Vector.Grow: data GrowVector s a
+ Data.Vector.Grow: ensure :: PrimMonad m => GrowVector (PrimState m) a -> Int -> m ()
+ Data.Vector.Grow: ensureAppend :: PrimMonad m => GrowVector (PrimState m) a -> Int -> m ()
+ Data.Vector.Grow: freeze :: PrimMonad m => GrowVector (PrimState m) a -> m (Vector a)
+ Data.Vector.Grow: instance GHC.Generics.Generic (Data.Vector.Grow.GrowVector s a)
+ Data.Vector.Grow: length :: PrimMonad m => GrowVector (PrimState m) a -> m Int
+ Data.Vector.Grow: new :: PrimMonad m => Int -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow: newSized :: PrimMonad m => Int -> Int -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow: null :: PrimMonad m => GrowVector (PrimState m) a -> m Bool
+ Data.Vector.Grow: pushBack :: PrimMonad m => GrowVector (PrimState m) a -> a -> m ()
+ Data.Vector.Grow: read :: PrimMonad m => GrowVector (PrimState m) a -> Int -> m a
+ Data.Vector.Grow: slice :: PrimMonad m => Int -> Int -> GrowVector (PrimState m) a -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow: thaw :: PrimMonad m => Vector a -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow: type IOGrowVector a = GrowVector RealWorld a
+ Data.Vector.Grow: unsafePushBack :: PrimMonad m => GrowVector (PrimState m) a -> a -> m ()
+ Data.Vector.Grow: unsafeRead :: PrimMonad m => GrowVector (PrimState m) a -> Int -> m a
+ Data.Vector.Grow: unsafeWrite :: PrimMonad m => GrowVector (PrimState m) a -> Int -> a -> m ()
+ Data.Vector.Grow: write :: PrimMonad m => GrowVector (PrimState m) a -> Int -> a -> m ()
+ Data.Vector.Grow.Storable: GrowVector :: !MutVar s (MVector s a) -> !MutVar s Int -> GrowVector s a
+ Data.Vector.Grow.Storable: [growVectorLength] :: GrowVector s a -> !MutVar s Int
+ Data.Vector.Grow.Storable: [growVector] :: GrowVector s a -> !MutVar s (MVector s a)
+ Data.Vector.Grow.Storable: capacity :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Int
+ Data.Vector.Grow.Storable: data GrowVector s a
+ Data.Vector.Grow.Storable: ensure :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> m ()
+ Data.Vector.Grow.Storable: ensureAppend :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> m ()
+ Data.Vector.Grow.Storable: freeze :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m (Vector a)
+ Data.Vector.Grow.Storable: instance GHC.Generics.Generic (Data.Vector.Grow.Storable.GrowVector s a)
+ Data.Vector.Grow.Storable: length :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Int
+ Data.Vector.Grow.Storable: new :: (Storable a, PrimMonad m) => Int -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow.Storable: newSized :: (Storable a, PrimMonad m) => Int -> Int -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow.Storable: null :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Bool
+ Data.Vector.Grow.Storable: pushBack :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> a -> m ()
+ Data.Vector.Grow.Storable: read :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> m a
+ Data.Vector.Grow.Storable: slice :: (Storable a, PrimMonad m) => Int -> Int -> GrowVector (PrimState m) a -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow.Storable: thaw :: (Storable a, PrimMonad m) => Vector a -> m (GrowVector (PrimState m) a)
+ Data.Vector.Grow.Storable: type IOGrowVector a = GrowVector RealWorld a
+ Data.Vector.Grow.Storable: unsafePushBack :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> a -> m ()
+ Data.Vector.Grow.Storable: unsafeRead :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> m a
+ Data.Vector.Grow.Storable: unsafeWrite :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> a -> m ()
+ Data.Vector.Grow.Storable: write :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> Int -> a -> m ()

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+# 0.1.3.0++* Add modules for `Storable` and boxed vectors.+ # 0.1.2.0  * Add liquid haskell refinement for `new`.
grow-vector.cabal view
@@ -1,7 +1,7 @@ name:                grow-vector synopsis:            Mutable vector with efficient appends description:         Mutable vector with efficient updates. Simple implementation on partially filled array with capacity tracking and resizing.-version:             0.1.2.0+version:             0.1.3.0 license:             MIT license-file:        LICENSE copyright:           2020 Anton Gushcha@@ -26,6 +26,8 @@ library   hs-source-dirs:      src   exposed-modules:+    Data.Vector.Grow+    Data.Vector.Grow.Storable     Data.Vector.Grow.Unboxed    build-depends:@@ -50,7 +52,9 @@   main-is:             Driver.hs   hs-source-dirs:      test   other-modules:-      Data.Vector.Grow.Unboxed.Test+    Data.Vector.Grow.Storable.Test+    Data.Vector.Grow.Test+    Data.Vector.Grow.Unboxed.Test   ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N   build-depends:       base
+ src/Data/Vector/Grow.hs view
@@ -0,0 +1,230 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+-- |+-- Module      : Data.Vector.Grow+-- Copyright   : (c) 2020 Gushcha Anton+-- License     : MIT+-- Maintainer  : ncrashed@protonmail.com+-- Stability   : unstable+-- Portability : non-portable+--+-- Module defines mutable vector that can grow in size automatically when an user+-- adds new elements at the end of vector.+--+-- We reallocate vector with 1.5x length to get amortized append.+module Data.Vector.Grow(+    GrowVector(..)+  , IOGrowVector+  -- * Quering info about vector+  , length+  , null+  , capacity+  -- * Creation+  , new+  , newSized+  -- * Quering subvectors+  , slice+  -- * Converting to immutable+  , thaw+  , freeze+  -- * Capacity maninuplation+  , ensure+  , ensureAppend+  -- * Accessing individual elements+  , read+  , write+  , unsafeRead+  , unsafeWrite+  -- * Appending to vector+  , pushBack+  , unsafePushBack+  ) where++import Control.Monad+import Control.Monad.Primitive+import Data.Primitive.MutVar+import Data.Vector.Mutable (MVector)+import GHC.Generics+import Prelude hiding (length, null, read)++import qualified Data.Vector as U+import qualified Data.Vector.Mutable as M++-- | Grow vector that is wrap around mutable vector. We allocate partially filled+-- vector and grow it when there is no more space for new element.+data GrowVector s a = GrowVector {+  growVector         :: !(MutVar s (MVector s a))+, growVectorLength   :: !(MutVar s Int)+} deriving (Generic)++-- | Synonim for 'GrowVector' in 'IO' monad+type IOGrowVector a = GrowVector RealWorld a++-- | Return current capacity of the vector (amount of elements that it can fit without realloc)+capacity :: (PrimMonad m) => GrowVector (PrimState m) a -> m Int+capacity v = do+  mv <- readMutVar $ growVector v+  pure $ M.length mv+{-# INLINE capacity #-}++-- | Return current amount of elements in the vector+length :: (PrimMonad m) => GrowVector (PrimState m) a -> m Int+length v = readMutVar $ growVectorLength v+{-# INLINE length #-}++-- | Return 'True' if there is no elements inside the vector+null :: (PrimMonad m) => GrowVector (PrimState m) a -> m Bool+null v = fmap (== 0) $ length v+{-# INLINE null #-}++-- | Allocation of new growable vector with given capacity.+new :: (PrimMonad m) => Int -> m (GrowVector (PrimState m) a)+new = newSized 0+{-# INLINE new #-}++-- | Allocation of new growable vector with given filled size and capacity.+-- Elements is not initialized. Capacity must be greater than filled size.+newSized :: (PrimMonad m) => Int -> Int -> m (GrowVector (PrimState m) a)+newSized n cap = GrowVector <$> (newMutVar =<< M.new cap) <*> newMutVar n+{-# INLINABLE newSized #-}++-- | Yield a part of mutable vector without copying it. The vector must contain at least i+n elements.+slice :: (PrimMonad m)+  => Int -- ^ i starting index+  -> Int -- ^ n number of elements+  -> GrowVector (PrimState m) a+  -> m (GrowVector (PrimState m) a)+slice i n v = do+  newSize <- newMutVar n+  mv <- readMutVar $ growVector v+  newVec <- newMutVar $! M.slice i n mv+  pure $! GrowVector newVec newSize+{-# INLINABLE slice #-}++-- | Convert immutable vector to grow mutable version. Doesn't allocate additonal memory for appending,+-- use 'ensure' to add capacity to the vector.+thaw :: (PrimMonad m)+  => U.Vector a+  -> m (GrowVector (PrimState m) a)+thaw u = do+  mv <- newMutVar =<< U.thaw u+  lv <- newMutVar (U.length u)+  pure $ GrowVector mv lv+{-# INLINABLE thaw #-}++-- | Freezing growable vector. It will contain only actual elements of the vector not including capacity+-- space, but you should call 'U.force' on resulting vector to not hold the allocated capacity of original+-- vector in memory.++freeze :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> m (U.Vector a)+freeze v = do+  n <- length v+  mv <- readMutVar $ growVector v+  U.freeze $ M.take n mv+{-# INLINABLE freeze #-}++-- | Ensure that grow vector has at least given capacity possibly with reallocation.+ensure :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int+  -> m ()+ensure v n = do+  c <- capacity v+  unless (c >= n) $ do+    mv <- readMutVar $ growVector v+    writeMutVar (growVector v) =<< M.grow mv (n - c)+{-# INLINABLE ensure #-}++-- | Ensure that grow vector has enough space for additonal n elements.+-- We grow vector by 1.5 factor or by required elements count * 1.5.+ensureAppend :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Additional n elements+  -> m ()+ensureAppend v i = do+  n <- readMutVar $ growVectorLength v+  mv <- readMutVar $ growVector v+  let c = M.length mv+  unless (c >= n + i) $ do+    let growFactor = 1.5+        newCap = ceiling $ max (growFactor * fromIntegral c) (fromIntegral c + growFactor * fromIntegral (n + i - c))+    writeMutVar (growVector v) =<< M.grow mv (newCap - c)+{-# INLINABLE ensureAppend #-}++-- | Read element from vector at given index.+read :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> m a+read v i = do+  n <- readMutVar $ growVectorLength v+#ifndef LIQUID+  when (i < 0 || i >= n) $ error $ "GrowVector.read: index " <> show i <> " is out bounds " <> show n+#endif+  mv <- readMutVar $ growVector v+  M.unsafeRead mv i+{-# INLINABLE read #-}++-- | Read element from vector at given index.+unsafeRead :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> m a+unsafeRead v i = do+  mv <- readMutVar $ growVector v+  M.unsafeRead mv i+{-# INLINABLE unsafeRead #-}++-- | Write down element in the vector at given index.+write :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> a+  -> m ()+write v i a = do+  n <- readMutVar $ growVectorLength v+#ifndef LIQUID+  when (i < 0 || i >= n) $ error $ "GrowVector.write: index " <> show i <> " is out bounds " <> show n+#endif+  mv <- readMutVar $ growVector v+  M.unsafeWrite mv i a+{-# INLINABLE write #-}++-- | Write down element in the vector at given index.+unsafeWrite :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> a+  -> m ()+unsafeWrite v i a = do+  mv <- readMutVar $ growVector v+  M.unsafeWrite mv i a+{-# INLINABLE unsafeWrite #-}++-- | O(1) amortized appending to vector+pushBack :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> a+  -> m ()+pushBack v a = do+  ensureAppend v 1+  unsafePushBack v a+{-# INLINABLE pushBack #-}++-- | O(1) amortized appending to vector. Doesn't reallocate vector, so+-- there must by capacity - length >= 1.+unsafePushBack :: (PrimMonad m)+  => GrowVector (PrimState m) a+  -> a+  -> m ()+unsafePushBack v a = do+  n <- readMutVar $ growVectorLength v+  mv <- readMutVar $ growVector v+  M.write mv n a+  writeMutVar (growVectorLength v) (n+1)+{-# INLINABLE unsafePushBack #-}
+ src/Data/Vector/Grow/Storable.hs view
@@ -0,0 +1,230 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+-- |+-- Module      : Data.Vector.Grow.Storable+-- Copyright   : (c) 2020 Gushcha Anton+-- License     : MIT+-- Maintainer  : ncrashed@protonmail.com+-- Stability   : unstable+-- Portability : non-portable+--+-- Module defines mutable vector that can grow in size automatically when an user+-- adds new elements at the end of vector.+--+-- We reallocate vector with 1.5x length to get amortized append.+module Data.Vector.Grow.Storable(+    GrowVector(..)+  , IOGrowVector+  -- * Quering info about vector+  , length+  , null+  , capacity+  -- * Creation+  , new+  , newSized+  -- * Quering subvectors+  , slice+  -- * Converting to immutable+  , thaw+  , freeze+  -- * Capacity maninuplation+  , ensure+  , ensureAppend+  -- * Accessing individual elements+  , read+  , write+  , unsafeRead+  , unsafeWrite+  -- * Appending to vector+  , pushBack+  , unsafePushBack+  ) where++import Control.Monad+import Control.Monad.Primitive+import Data.Primitive.MutVar+import Data.Vector.Storable.Mutable (MVector, Storable)+import GHC.Generics+import Prelude hiding (length, null, read)++import qualified Data.Vector.Storable as V+import qualified Data.Vector.Storable.Mutable as M++-- | Grow vector that is wrap around mutable vector. We allocate partially filled+-- vector and grow it when there is no more space for new element.+data GrowVector s a = GrowVector {+  growVector         :: !(MutVar s (MVector s a))+, growVectorLength   :: !(MutVar s Int)+} deriving (Generic)++-- | Synonim for 'GrowVector' in 'IO' monad+type IOGrowVector a = GrowVector RealWorld a++-- | Return current capacity of the vector (amount of elements that it can fit without realloc)+capacity :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Int+capacity v = do+  mv <- readMutVar $ growVector v+  pure $ M.length mv+{-# INLINE capacity #-}++-- | Return current amount of elements in the vector+length :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Int+length v = readMutVar $ growVectorLength v+{-# INLINE length #-}++-- | Return 'True' if there is no elements inside the vector+null :: (Storable a, PrimMonad m) => GrowVector (PrimState m) a -> m Bool+null v = fmap (== 0) $ length v+{-# INLINE null #-}++-- | Allocation of new growable vector with given capacity.+new :: (Storable a, PrimMonad m) => Int -> m (GrowVector (PrimState m) a)+new = newSized 0+{-# INLINE new #-}++-- | Allocation of new growable vector with given filled size and capacity.+-- Elements is not initialized. Capacity must be greater than filled size.+newSized :: (Storable a, PrimMonad m) => Int -> Int -> m (GrowVector (PrimState m) a)+newSized n cap = GrowVector <$> (newMutVar =<< M.new cap) <*> newMutVar n+{-# INLINABLE newSized #-}++-- | Yield a part of mutable vector without copying it. The vector must contain at least i+n elements.+slice :: (Storable a, PrimMonad m)+  => Int -- ^ i starting index+  -> Int -- ^ n number of elements+  -> GrowVector (PrimState m) a+  -> m (GrowVector (PrimState m) a)+slice i n v = do+  newSize <- newMutVar n+  mv <- readMutVar $ growVector v+  newVec <- newMutVar $! M.slice i n mv+  pure $! GrowVector newVec newSize+{-# INLINABLE slice #-}++-- | Convert immutable vector to grow mutable version. Doesn't allocate additonal memory for appending,+-- use 'ensure' to add capacity to the vector.+thaw :: (Storable a, PrimMonad m)+  => V.Vector a+  -> m (GrowVector (PrimState m) a)+thaw u = do+  mv <- newMutVar =<< V.thaw u+  lv <- newMutVar (V.length u)+  pure $ GrowVector mv lv+{-# INLINABLE thaw #-}++-- | Freezing growable vector. It will contain only actual elements of the vector not including capacity+-- space, but you should call 'V.force' on resulting vector to not hold the allocated capacity of original+-- vector in memory.++freeze :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> m (V.Vector a)+freeze v = do+  n <- length v+  mv <- readMutVar $ growVector v+  V.freeze $ M.take n mv+{-# INLINABLE freeze #-}++-- | Ensure that grow vector has at least given capacity possibly with reallocation.+ensure :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int+  -> m ()+ensure v n = do+  c <- capacity v+  unless (c >= n) $ do+    mv <- readMutVar $ growVector v+    writeMutVar (growVector v) =<< M.grow mv (n - c)+{-# INLINABLE ensure #-}++-- | Ensure that grow vector has enough space for additonal n elements.+-- We grow vector by 1.5 factor or by required elements count * 1.5.+ensureAppend :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Additional n elements+  -> m ()+ensureAppend v i = do+  n <- readMutVar $ growVectorLength v+  mv <- readMutVar $ growVector v+  let c = M.length mv+  unless (c >= n + i) $ do+    let growFactor = 1.5+        newCap = ceiling $ max (growFactor * fromIntegral c) (fromIntegral c + growFactor * fromIntegral (n + i - c))+    writeMutVar (growVector v) =<< M.grow mv (newCap - c)+{-# INLINABLE ensureAppend #-}++-- | Read element from vector at given index.+read :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> m a+read v i = do+  n <- readMutVar $ growVectorLength v+#ifndef LIQUID+  when (i < 0 || i >= n) $ error $ "GrowVector.read: index " <> show i <> " is out bounds " <> show n+#endif+  mv <- readMutVar $ growVector v+  M.unsafeRead mv i+{-# INLINABLE read #-}++-- | Read element from vector at given index.+unsafeRead :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> m a+unsafeRead v i = do+  mv <- readMutVar $ growVector v+  M.unsafeRead mv i+{-# INLINABLE unsafeRead #-}++-- | Write down element in the vector at given index.+write :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> a+  -> m ()+write v i a = do+  n <- readMutVar $ growVectorLength v+#ifndef LIQUID+  when (i < 0 || i >= n) $ error $ "GrowVector.write: index " <> show i <> " is out bounds " <> show n+#endif+  mv <- readMutVar $ growVector v+  M.unsafeWrite mv i a+{-# INLINABLE write #-}++-- | Write down element in the vector at given index.+unsafeWrite :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> Int -- ^ Index of element. Must be in [0 .. length) range+  -> a+  -> m ()+unsafeWrite v i a = do+  mv <- readMutVar $ growVector v+  M.unsafeWrite mv i a+{-# INLINABLE unsafeWrite #-}++-- | O(1) amortized appending to vector+pushBack :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> a+  -> m ()+pushBack v a = do+  ensureAppend v 1+  unsafePushBack v a+{-# INLINABLE pushBack #-}++-- | O(1) amortized appending to vector. Doesn't reallocate vector, so+-- there must by capacity - length >= 1.+unsafePushBack :: (Storable a, PrimMonad m)+  => GrowVector (PrimState m) a+  -> a+  -> m ()+unsafePushBack v a = do+  n <- readMutVar $ growVectorLength v+  mv <- readMutVar $ growVector v+  M.write mv n a+  writeMutVar (growVectorLength v) (n+1)+{-# INLINABLE unsafePushBack #-}
+ test/Data/Vector/Grow/Storable/Test.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedLists #-}+module Data.Vector.Grow.Storable.Test where++import Control.Monad.Primitive (RealWorld)+import Data.Vector.Grow.Storable (GrowVector)+import qualified Data.Vector.Grow.Storable as V++import Test.Tasty.Hspec++spec_creation :: Spec+spec_creation = describe "vector creation" $ do+  it "initialized with right size" $ do+    v :: GrowVector RealWorld Int <- V.new 42+    l <- V.length v+    l `shouldBe` 0+    c <- V.capacity v+    c `shouldBe` 42+    r <- V.null v+    r `shouldBe` True+  it "preallocated initialized with right size" $ do+    v :: GrowVector RealWorld Int <- V.newSized 23 42+    l <- V.length v+    l `shouldBe` 23+    c <- V.capacity v+    c `shouldBe` 42+    r <- V.null v+    r `shouldBe` False++spec_slicing :: Spec+spec_slicing = describe "vector slicing" $ do+  it "simple slice" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    v' <- V.slice 1 2 v+    vf <- V.freeze v'+    vf `shouldBe` [2, 3]+  it "empty slice" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    v' <- V.slice 1 0 v+    vf <- V.freeze v'+    vf `shouldBe` []+  it "begin slice" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    v' <- V.slice 0 1 v+    vf <- V.freeze v'+    vf `shouldBe` [1]+  it "end slice" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    v' <- V.slice 4 1 v+    vf <- V.freeze v'+    vf `shouldBe` [5]+  it "mutating parent slice" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    v' <- V.slice 1 2 v+    vf1 <- V.freeze v'+    vf1 `shouldBe` [2, 3]+    V.write v 2 4+    vf2 <- V.freeze v'+    vf2 `shouldBe` [2, 4]++spec_readWrite :: Spec+spec_readWrite = describe "basic read write" $ do+  it "read elements" $ do+    v :: GrowVector RealWorld Int <- V.thaw [1, 2, 3, 4, 5]+    a1 <- V.read v 0+    a1 `shouldBe` 1+    a2 <- V.read v 1+    a2 `shouldBe` 2+    a3 <- V.read v 2+    a3 `shouldBe` 3+    a4 <- V.read v 4+    a4 `shouldBe` 5+  it "writes elements" $ do+    v :: GrowVector RealWorld Int <- V.newSized 2 2+    V.write v 0 1+    V.write v 1 2+    v' <- V.freeze v+    v' `shouldBe` [1, 2]+  it "write-read indemponent" $ do+    v :: GrowVector RealWorld Int <- V.newSized 1 1+    V.write v 0 424242+    a <- V.read v 0+    a `shouldBe` 424242++spec_ensure :: Spec+spec_ensure = describe "capacity realloc" $ do+  it "ensure reallocates properly" $ do+    v :: GrowVector RealWorld Int <- V.new 5+    V.ensure v 1+    c1 <- V.capacity v+    c1 `shouldBe` 5+    V.ensure v 6+    c2 <- V.capacity v+    c2 `shouldBe` 6+  it "ensureAppend reallocates properly" $ do+    v :: GrowVector RealWorld Int <- V.new 5+    V.ensureAppend v 1+    c1 <- V.capacity v+    c1 `shouldBe` 5+    V.ensureAppend v 6+    c2 <- V.capacity v+    c2 `shouldBe` 8+    V.ensureAppend v 14+    c3 <- V.capacity v+    c3 `shouldBe` 17++spec_pushBack :: Spec+spec_pushBack = describe "push back operations" $ do+  it "push simple" $ do+    v :: GrowVector RealWorld Int <- V.new 1+    V.pushBack v 1+    l1 <- V.length v+    c1 <- V.capacity v+    l1 `shouldBe` 1+    c1 `shouldBe` 1+    V.pushBack v 2+    l2 <- V.length v+    c2 <- V.capacity v+    l2 `shouldBe` 2+    c2 `shouldBe` 3+    V.pushBack v 3+    l3 <- V.length v+    c3 <- V.capacity v+    l3 `shouldBe` 3+    c3 `shouldBe` 3+    V.pushBack v 4+    l4 <- V.length v+    c4 <- V.capacity v+    l4 `shouldBe` 4+    c4 `shouldBe` 5+    v' <- V.freeze v+    v' `shouldBe` [1, 2, 3, 4]+  it "push unsafe" $ do+    v :: GrowVector RealWorld Int <- V.new 1+    V.unsafePushBack v 1+    l1 <- V.length v+    c1 <- V.capacity v+    l1 `shouldBe` 1+    c1 `shouldBe` 1+    V.ensureAppend v 1+    V.unsafePushBack v 2+    l2 <- V.length v+    c2 <- V.capacity v+    l2 `shouldBe` 2+    c2 `shouldBe` 3+    V.unsafePushBack v 3+    l3 <- V.length v+    c3 <- V.capacity v+    l3 `shouldBe` 3+    c3 `shouldBe` 3+    V.ensureAppend v 1+    V.unsafePushBack v 4+    l4 <- V.length v+    c4 <- V.capacity v+    l4 `shouldBe` 4+    c4 `shouldBe` 5+    v' <- V.freeze v+    v' `shouldBe` [1, 2, 3, 4]
+ test/Data/Vector/Grow/Test.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedLists #-}+module Data.Vector.Grow.Test where++import Control.Monad.Primitive (RealWorld)+import Data.Vector.Grow (GrowVector)+import qualified Data.Vector.Grow as G++import Test.Tasty.Hspec++spec_creation :: Spec+spec_creation = describe "vector creation" $ do+  it "initialized with right size" $ do+    v :: GrowVector RealWorld Int <- G.new 42+    l <- G.length v+    l `shouldBe` 0+    c <- G.capacity v+    c `shouldBe` 42+    r <- G.null v+    r `shouldBe` True+  it "preallocated initialized with right size" $ do+    v :: GrowVector RealWorld Int <- G.newSized 23 42+    l <- G.length v+    l `shouldBe` 23+    c <- G.capacity v+    c `shouldBe` 42+    r <- G.null v+    r `shouldBe` False++spec_slicing :: Spec+spec_slicing = describe "vector slicing" $ do+  it "simple slice" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    v' <- G.slice 1 2 v+    vf <- G.freeze v'+    vf `shouldBe` [2, 3]+  it "empty slice" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    v' <- G.slice 1 0 v+    vf <- G.freeze v'+    vf `shouldBe` []+  it "begin slice" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    v' <- G.slice 0 1 v+    vf <- G.freeze v'+    vf `shouldBe` [1]+  it "end slice" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    v' <- G.slice 4 1 v+    vf <- G.freeze v'+    vf `shouldBe` [5]+  it "mutating parent slice" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    v' <- G.slice 1 2 v+    vf1 <- G.freeze v'+    vf1 `shouldBe` [2, 3]+    G.write v 2 4+    vf2 <- G.freeze v'+    vf2 `shouldBe` [2, 4]++spec_readWrite :: Spec+spec_readWrite = describe "basic read write" $ do+  it "read elements" $ do+    v :: GrowVector RealWorld Int <- G.thaw [1, 2, 3, 4, 5]+    a1 <- G.read v 0+    a1 `shouldBe` 1+    a2 <- G.read v 1+    a2 `shouldBe` 2+    a3 <- G.read v 2+    a3 `shouldBe` 3+    a4 <- G.read v 4+    a4 `shouldBe` 5+  it "writes elements" $ do+    v :: GrowVector RealWorld Int <- G.newSized 2 2+    G.write v 0 1+    G.write v 1 2+    v' <- G.freeze v+    v' `shouldBe` [1, 2]+  it "write-read indemponent" $ do+    v :: GrowVector RealWorld Int <- G.newSized 1 1+    G.write v 0 424242+    a <- G.read v 0+    a `shouldBe` 424242++spec_ensure :: Spec+spec_ensure = describe "capacity realloc" $ do+  it "ensure reallocates properly" $ do+    v :: GrowVector RealWorld Int <- G.new 5+    G.ensure v 1+    c1 <- G.capacity v+    c1 `shouldBe` 5+    G.ensure v 6+    c2 <- G.capacity v+    c2 `shouldBe` 6+  it "ensureAppend reallocates properly" $ do+    v :: GrowVector RealWorld Int <- G.new 5+    G.ensureAppend v 1+    c1 <- G.capacity v+    c1 `shouldBe` 5+    G.ensureAppend v 6+    c2 <- G.capacity v+    c2 `shouldBe` 8+    G.ensureAppend v 14+    c3 <- G.capacity v+    c3 `shouldBe` 17++spec_pushBack :: Spec+spec_pushBack = describe "push back operations" $ do+  it "push simple" $ do+    v :: GrowVector RealWorld Int <- G.new 1+    G.pushBack v 1+    l1 <- G.length v+    c1 <- G.capacity v+    l1 `shouldBe` 1+    c1 `shouldBe` 1+    G.pushBack v 2+    l2 <- G.length v+    c2 <- G.capacity v+    l2 `shouldBe` 2+    c2 `shouldBe` 3+    G.pushBack v 3+    l3 <- G.length v+    c3 <- G.capacity v+    l3 `shouldBe` 3+    c3 `shouldBe` 3+    G.pushBack v 4+    l4 <- G.length v+    c4 <- G.capacity v+    l4 `shouldBe` 4+    c4 `shouldBe` 5+    v' <- G.freeze v+    v' `shouldBe` [1, 2, 3, 4]+  it "push unsafe" $ do+    v :: GrowVector RealWorld Int <- G.new 1+    G.unsafePushBack v 1+    l1 <- G.length v+    c1 <- G.capacity v+    l1 `shouldBe` 1+    c1 `shouldBe` 1+    G.ensureAppend v 1+    G.unsafePushBack v 2+    l2 <- G.length v+    c2 <- G.capacity v+    l2 `shouldBe` 2+    c2 `shouldBe` 3+    G.unsafePushBack v 3+    l3 <- G.length v+    c3 <- G.capacity v+    l3 `shouldBe` 3+    c3 `shouldBe` 3+    G.ensureAppend v 1+    G.unsafePushBack v 4+    l4 <- G.length v+    c4 <- G.capacity v+    l4 `shouldBe` 4+    c4 `shouldBe` 5+    v' <- G.freeze v+    v' `shouldBe` [1, 2, 3, 4]