packages feed

compact-mutable-vector (empty) → 0.0.0.1

raw patch · 6 files changed

+233/−0 lines, 6 filesdep +basedep +compactdep +compact-mutable-vectorsetup-changed

Dependencies added: base, compact, compact-mutable-vector, ghc-prim, hspec, primitive, vector

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Copyright 2019 rightfold++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the documentation+   and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ compact-mutable-vector.cabal view
@@ -0,0 +1,66 @@+build-type: Simple+cabal-version: >= 1.8++name: compact-mutable-vector+version: 0.0.0.1++category: Data+license: BSD3+license-file: LICENSE+author: rightfold+maintainer: rightfold <rightfold@gmail.com>+bug-reports: https://github.com/rightfold/compact-mutable-vector/issues++synopsis: Mutable vector with different GC characteristics+description:+  Library for avoiding excessive mutable array traversals by the garbage+  collector when you use compact regions for your elements.+  .+  See Haddock for more information.++source-repository head+  type: git+  location: https://github.com/rightfold/compact-mutable-vector.git++library+  build-depends:+    base          >= 4.12 && < 5,+    compact,+    ghc-prim,+    primitive     >= 0.5.0.1 && < 0.8,+    vector        >= 0.12 && < 0.13++  exposed-modules:+    Data.Vector.Mutable.Compact++  ghc-options:+    -Wall+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns++  hs-source-dirs:+    src++test-suite test+  build-depends:+    base,+    compact,+    compact-mutable-vector,+    hspec++  ghc-options:+    -Wall+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns++  hs-source-dirs:+    test++  main-is:+    Main.hs++  other-modules:+    Data.Vector.Mutable.CompactSpec++  type:+    exitcode-stdio-1.0
+ src/Data/Vector/Mutable/Compact.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}++-- |+-- When you use normal mutable vectors, the garbage collector will traverse+-- them on every garbage collection, because they may point to data that is+-- newer than them. If you want to store your elements on a compact region+-- anyway, but also need to point to them from a mutable vector, you can+-- exploit the stability of the elements' addresses after adding them to the+-- compact region, to avoid these expensive traversals when collecting garbage.+--+-- This library offers a data type for mutable vectors where all elements are+-- stored in a compact region, using an unspeakable pointer casting hack.+module Data.Vector.Mutable.Compact+  ( -- * Basic operations+    CVector+  , replicate+  , read+  , write++    -- * Shape querying+  , length+  , null+  ) where++import Prelude hiding (length, null, read, replicate)++import Data.Primitive.Addr (Addr (..))+import Data.Compact (Compact)+import Data.Vector.Primitive.Mutable (MVector)+import GHC.IO (IO (..))+import GHC.Prim (RealWorld)++import qualified Data.Compact as Compact+import qualified Data.Vector.Primitive.Mutable as MVector+import qualified GHC.Prim as Prim++--------------------------------------------------------------------------------+-- Basic operations++-- |+-- Store the elements of the vector in a compact region, and use an unboxed+-- vector of pointers to the elements. Values in a compact region will not be+-- moved by the garbage collector, so their addresses are stable, and can hence+-- be stored in a mutable byte array. This avoids garbage collection overhead+-- if you store your elements in a compact region anyway, because the garbage+-- collector will not traverse byte arrays.+--+-- The elements must be able to be stored in a compact region. See+-- "Data.Compact" for a list of restrictions. The vector itself cannot itself+-- be stored in a compact region, because it is mutable.+--+-- Elements can never be bottom, because they are added to a compact region.+data CVector a =+  CVector+    !(Compact ())+    {-# UNPACK #-} !(MVector RealWorld Addr)++-- |+-- Create a new mutable vector of the given length, with each element set to+-- the given value. The given compact region will be used for all future+-- elements inserted into this vector.+replicate :: Compact () -> Int -> b -> IO (CVector b)+replicate c n x = do+  -- TODO: Should we add the element with sharing?+  xC <- Compact.getCompact <$> Compact.compactAdd c x+  xA <- IO $ \s -> let !(# s', xA #) = Prim.anyToAddr# xC s in+                   (# s', Addr xA #)+  v  <- MVector.replicate n xA+  pure $ CVector c v++-- |+-- Read the element at the given zero-based position. If the position is out of+-- bounds, crash.+read :: CVector a -> Int -> IO a+read (CVector _ v) i = do+  Addr xA <- MVector.read v i+  let (# xC #) = Prim.addrToAny# xA+  pure xC++-- |+-- Write an element at the given zero-based position. If the position is out of+-- bounds, crash.+--+-- The element will be added to the compact region.+write :: CVector a -> Int -> a -> IO ()+write (CVector c v) i x = do+  -- TODO: Should we add the element with sharing?+  xC <- Compact.getCompact <$> Compact.compactAdd c x+  xA <- IO $ \s -> let !(# s', xA #) = Prim.anyToAddr# xC s in+                   (# s', Addr xA #)+  MVector.write v i xA++--------------------------------------------------------------------------------+-- Shape querying++-- |+-- How many elements are in the vector?+{-# INLINE length #-}+length :: CVector a -> Int+length (CVector _ v) = MVector.length v++-- |+-- Is the vector empty?+{-# INLINE null #-}+null :: CVector a -> Bool+null (CVector _ v) = MVector.null v
+ test/Data/Vector/Mutable/CompactSpec.hs view
@@ -0,0 +1,29 @@+module Data.Vector.Mutable.CompactSpec+  ( spec+  ) where++import Data.Foldable (for_)+import Test.Hspec (Spec, it, shouldBe)+import System.Mem (performGC)++import qualified Data.Compact as Compact+import qualified Data.Vector.Mutable.Compact as CVector++spec :: Spec+spec =+  for_ [0 .. 63] $ \n ->+    it (show n) $ do+      c <- Compact.compact ()+      v <- CVector.replicate c n "ABC"+      for_ [0 .. n - 1] $ \i -> do++        performGC++        abc <- CVector.read v i+        abc `shouldBe` "ABC"++        performGC++        CVector.write v i (show i)+        def <- CVector.read v i+        def `shouldBe` (show i)
+ test/Main.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}