packages feed

impure-containers 0.3 → 0.3.1

raw patch · 8 files changed

+395/−11 lines, 8 filesdep +transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

API changes (from Hackage documentation)

+ Data.Primitive.Array.Maybe: data MutableMaybeArray s a
+ Data.Primitive.Array.Maybe: newMaybeArray :: PrimMonad m => Int -> Maybe a -> m (MutableMaybeArray (PrimState m) a)
+ Data.Primitive.Array.Maybe: readMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> m (Maybe a)
+ Data.Primitive.Array.Maybe: writeMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> Maybe a -> m ()
+ Data.Primitive.Bool: BoolByte :: Bool -> BoolByte
+ Data.Primitive.Bool: [getBoolByte] :: BoolByte -> Bool
+ Data.Primitive.Bool: instance Data.Primitive.Types.Prim Data.Primitive.Bool.BoolByte
+ Data.Primitive.Bool: newtype BoolByte
+ Data.Primitive.MutVar.Maybe: data MutMaybeVar s a
+ Data.Primitive.MutVar.Maybe: newMutMaybeVar :: PrimMonad m => Maybe a -> m (MutMaybeVar (PrimState m) a)
+ Data.Primitive.MutVar.Maybe: readMutMaybeVar :: PrimMonad m => MutMaybeVar (PrimState m) a -> m (Maybe a)
+ Data.Primitive.MutVar.Maybe: writeMutMaybeVar :: PrimMonad m => MutMaybeVar (PrimState m) a -> Maybe a -> m ()
+ Data.Primitive.PrimArray: MutablePrimArray :: (MutableByteArray s) -> MutablePrimArray s a
+ Data.Primitive.PrimArray: newPrimArray :: (PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)
+ Data.Primitive.PrimArray: newtype MutablePrimArray s a
+ Data.Primitive.PrimArray: readPrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> m a
+ Data.Primitive.PrimArray: setPrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> Int -> a -> m ()
+ Data.Primitive.PrimArray: sizeofMutablePrimArray :: Prim a => MutablePrimArray s a -> Int
+ Data.Primitive.PrimArray: writePrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> a -> m ()
+ Data.Trie.Mutable.Bits: MTrie :: !(MutMaybeVar s v) -> !(MutMaybeVar s (MTrie s k v)) -> !(MutMaybeVar s (MTrie s k v)) -> MTrie s k v
+ Data.Trie.Mutable.Bits: [trieLeft] :: MTrie s k v -> !(MutMaybeVar s (MTrie s k v))
+ Data.Trie.Mutable.Bits: [trieRight] :: MTrie s k v -> !(MutMaybeVar s (MTrie s k v))
+ Data.Trie.Mutable.Bits: [trieValue] :: MTrie s k v -> !(MutMaybeVar s v)
+ Data.Trie.Mutable.Bits: data MTrie s k v
+ Data.Trie.Mutable.Bits: insert :: (FiniteBits k, PrimMonad m) => MTrie (PrimState m) k v -> k -> v -> m ()
+ Data.Trie.Mutable.Bits: insertPrefix :: (FiniteBits k, PrimMonad m) => MTrie (PrimState m) k v -> Int -> k -> v -> m ()
+ Data.Trie.Mutable.Bits: lookup :: (FiniteBits k, PrimMonad m) => MTrie (PrimState m) k v -> k -> m (Maybe v)
+ Data.Trie.Mutable.Bits: new :: PrimMonad m => m (MTrie (PrimState m) k v)

Files

impure-containers.cabal view
@@ -1,5 +1,5 @@ name:                impure-containers-version:             0.3+version:             0.3.1 synopsis:            Mutable containers in haskell description:         Please see README.md homepage:            https://github.com/andrewthad/impure-containers#readme@@ -28,8 +28,14 @@     -- Data.Vector.Unique     Data.Graph.Immutable     Data.Graph.Mutable+    Data.Trie.Mutable.Bits     Data.ArrayList.Generic     Data.Graph.Types+    Data.Primitive.PrimArray+    Data.Primitive.Array.Maybe+    Data.Primitive.MutVar.Maybe+    Data.Primitive.Bool+    -- Data.Containers.Impure.Internal   other-modules:     Data.HashMap.Mutable.Internal.Array     Data.HashMap.Mutable.Internal.CacheLine@@ -73,11 +79,11 @@    -- ghc-prof-options: -prof -auto-all -  if impl(ghc >= 6.12.0)-    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2-                 -fno-warn-unused-do-bind-  else-    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2+  ghc-options:+    -Wall -fwarn-tabs -funbox-strict-fields+    -fno-warn-unused-do-bind+    -- Turn this one back on later+    -- -O2  Flag unsafe-tricks   Description: turn on unsafe GHC tricks@@ -114,6 +120,7 @@     , HUnit     , test-framework-hunit     , vector+    , transformers   ghc-options:         -threaded -rtsopts -with-rtsopts=-N   default-language:    Haskell2010 
src/Data/Graph/Immutable.hs view
@@ -23,9 +23,6 @@ import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU --- mapVertices :: (v -> w) -> Graph g e v -> Graph g e w--- mapVertices = fmap- dijkstra :: (Ord s, Monoid s)   => (v -> v -> s -> e -> s)   -> s -- ^ Weight to assign start vertex
+ src/Data/Primitive/Array/Maybe.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE MagicHash #-}++-- | This uses some unsafe hackery.+module Data.Primitive.Array.Maybe +  ( MutableMaybeArray+  , newMaybeArray+  , readMaybeArray+  , writeMaybeArray+  ) where++import Control.Monad.Primitive+import Data.Primitive.Array+import GHC.Prim (reallyUnsafePtrEquality#,Any)+import Unsafe.Coerce (unsafeCoerce)++newtype MutableMaybeArray s a = MutableMaybeArray (MutableArray s Any)++unsafeToMaybe :: Any -> Maybe a+unsafeToMaybe a = +  case reallyUnsafePtrEquality# a nothingSurrogate of+    0# -> Just (unsafeCoerce a)+    _  -> Nothing+{-# INLINE unsafeToMaybe #-}++nothingSurrogate :: Any+nothingSurrogate = error "nothingSurrogate: This value should not be forced!"+{-# NOINLINE nothingSurrogate #-}++newMaybeArray :: PrimMonad m => Int -> Maybe a -> m (MutableMaybeArray (PrimState m) a)+newMaybeArray i ma = case ma of+  Just a -> do+    x <- newArray i (unsafeCoerce a)+    return (MutableMaybeArray x)+  Nothing -> do +    x <- newArray i nothingSurrogate+    return (MutableMaybeArray x)++readMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> m (Maybe a)+readMaybeArray (MutableMaybeArray m) ix = do+  a <- readArray m ix+  return (unsafeToMaybe a)++writeMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> Maybe a -> m ()+writeMaybeArray (MutableMaybeArray marr) ix ma = case ma of+  Just a -> writeArray marr ix (unsafeCoerce a)+  Nothing -> writeArray marr ix nothingSurrogate++
+ src/Data/Primitive/Bool.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}++module Data.Primitive.Bool +  ( BoolByte(..)+  ) where++import Data.Primitive.Types+import qualified Data.Primitive.Types as P+import Data.Word+import GHC.Prim +import GHC.Types (Int(..))++{-@ data BoolByte = BoolByte { getBoolByte :: Bool } @-}+newtype BoolByte = BoolByte { getBoolByte :: Bool }++toBool :: Word8 -> BoolByte+toBool w = case w of+  0 -> BoolByte False+  _ -> BoolByte True+{-# INLINE toBool #-}++toBool# :: Word# -> BoolByte+toBool# w# = case eqWord# w# 0## of+  0# -> BoolByte False+  _  -> BoolByte True+{-# INLINE toBool# #-}++fromBool# :: BoolByte -> Word#+fromBool# (BoolByte b) = case b of+  True -> 1##+  False -> 0##+{-# INLINE fromBool# #-}++fromBool :: BoolByte -> Word8+fromBool (BoolByte b) = case b of+  True -> 1+  False -> 0++instance Prim BoolByte where+  sizeOf# _ = 1#+  alignment# _ = 1#+  indexByteArray# arr# i# = toBool# (indexWord8Array# arr# i#)               +  readByteArray# arr# i# s# = +    case readWord8Array# arr# i# s# of        +      { (# s1#, x# #) -> (# s1#, toBool# x# #) }  +  writeByteArray# arr# i# b s# = +    writeWord8Array# arr# i# (fromBool# b) s#    +  setByteArray# arr# i# n# b s# = P.setByteArray# arr# i# n# (fromBool b) s#+  indexOffAddr# addr# i# = toBool (indexOffAddr# addr# i#)+  readOffAddr#  addr# i# s# = +    case readOffAddr# addr# i# s# of+      (# s1#, w #) -> (# s1#, toBool w #)+  writeOffAddr# addr# i# b s# = writeOffAddr# addr# i# (fromBool b) s#+  setOffAddr# addr# i# n# b s# = +    setOffAddr# addr# i# n# (fromBool b) s#+  {-# INLINE sizeOf# #-}                                        +  {-# INLINE alignment# #-}                                     +  {-# INLINE indexByteArray# #-}                                +  {-# INLINE readByteArray# #-}                                 +  {-# INLINE writeByteArray# #-}                                +  {-# INLINE setByteArray# #-}                                  +  {-# INLINE indexOffAddr# #-}                                  +  {-# INLINE readOffAddr# #-}                                   +  {-# INLINE writeOffAddr# #-}                                  +  {-# INLINE setOffAddr# #-}                                    +
+ src/Data/Primitive/MutVar/Maybe.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE MagicHash    #-} +{-# LANGUAGE BangPatterns #-}++module Data.Primitive.MutVar.Maybe +  ( MutMaybeVar+  , newMutMaybeVar+  , readMutMaybeVar+  , writeMutMaybeVar+  ) where++import Data.Primitive.MutVar+import Control.Monad.Primitive++import Unsafe.Coerce+import GHC.Prim++import Data.Maybe++newtype MutMaybeVar s a = MutMaybeVar (MutVar s Any)++-- | nothingSurrogate stands in for the value Nothing; we distinguish it by pointer+nothingSurrogate :: Any+nothingSurrogate = error "Data.Primitive.MutVar.Maybe.nothingSurrogate evaluated"+{-# NOINLINE nothingSurrogate #-}++newMutMaybeVar :: PrimMonad m => Maybe a -> m (MutMaybeVar (PrimState m) a)+newMutMaybeVar ma = case ma of+  Just a -> do+    x <- newMutVar (unsafeCoerce a)+    return (MutMaybeVar x)+  Nothing -> do+    x <- newMutVar nothingSurrogate+    return (MutMaybeVar x)+{-# INLINE newMutMaybeVar #-}++readMutMaybeVar :: PrimMonad m => MutMaybeVar (PrimState m) a -> m (Maybe a)+readMutMaybeVar (MutMaybeVar r) = do+  x <- readMutVar r+  return $ toMaybe x+{-# INLINE readMutMaybeVar #-}++toMaybe :: Any -> Maybe a+toMaybe x = case reallyUnsafePtrEquality# x nothingSurrogate of+  0# -> Just $ unsafeCoerce x+  _ -> Nothing+{-# INLINE toMaybe #-}++writeMutMaybeVar :: PrimMonad m => MutMaybeVar (PrimState m) a -> Maybe a -> m ()+writeMutMaybeVar (MutMaybeVar r) ma = case ma of+  Just a -> writeMutVar r $ unsafeCoerce a+  Nothing -> writeMutVar r nothingSurrogate+{-# INLINE writeMutMaybeVar #-}+
+ src/Data/Primitive/PrimArray.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}++module Data.Primitive.PrimArray +  ( MutablePrimArray(..)+  , newPrimArray+  , readPrimArray+  , writePrimArray+  , sizeofMutablePrimArray+  , setPrimArray+  ) where++import Control.Monad.Primitive+import Data.Primitive.ByteArray+import Data.Primitive.Types+import GHC.Prim (newByteArray#,quotInt#,sizeofMutableByteArray#,(*#))+import GHC.Types (Int(..))++newtype MutablePrimArray s a = MutablePrimArray (MutableByteArray s)++newPrimArray :: (PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)+newPrimArray (I# n#) = result+  where+  result = primitive (\s# -> case newByteArray# (n# *# (sizeOf# (toUndefined1 result))) s# of+      (# s'#, arr# #) -> (# s'#, MutablePrimArray (MutableByteArray arr#) #)+    )++readPrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> m a+readPrimArray (MutablePrimArray m) = readByteArray m+{-# INLINE readPrimArray #-}++writePrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> a -> m ()+writePrimArray (MutablePrimArray m) = writeByteArray m+{-# INLINE writePrimArray #-}++sizeofMutablePrimArray :: Prim a => MutablePrimArray s a -> Int+sizeofMutablePrimArray p@(MutablePrimArray (MutableByteArray arr#)) =+  I# (quotInt# (sizeofMutableByteArray# arr#) (sizeOf# (toUndefined2 p)))+{-# INLINE sizeofMutablePrimArray #-}++setPrimArray+  :: (Prim a, PrimMonad m) +  => MutablePrimArray (PrimState m) a -- ^ array to fill+  -> Int -- ^ offset into array+  -> Int -- ^ number of values to fill+  -> a   -- ^ value to fill with+  -> m ()+setPrimArray (MutablePrimArray m) = setByteArray m++-- A hack to avoid adding forall statements to+-- other type signatures.+toUndefined1 :: m (MutablePrimArray (PrimState m) a) -> a+toUndefined1 _ = undefined++toUndefined2 :: MutablePrimArray s a -> a+toUndefined2 _ = undefined++
+ src/Data/Trie/Mutable/Bits.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE BangPatterns #-}++module Data.Trie.Mutable.Bits where++import Control.Monad.Primitive+import Data.Bits+import Data.Primitive.ByteArray+import Data.Primitive.Array+import Data.Primitive.MutVar.Maybe+import Data.Word+import GHC.TypeLits+import Data.Primitive.PrimArray+import Data.Primitive.Bool (BoolByte(..))++data MTrie s k v = MTrie+  { trieValue :: !(MutMaybeVar s v)+  , trieLeft  :: !(MutMaybeVar s (MTrie s k v))+  , trieRight :: !(MutMaybeVar s (MTrie s k v))+  }++new :: PrimMonad m => m (MTrie (PrimState m) k v)+new = MTrie+  <$> newMutMaybeVar Nothing+  <*> newMutMaybeVar Nothing+  <*> newMutMaybeVar Nothing++-- | This gives the best match, that is, the+--   value stored at the longest prefix that+--   matched this key.+lookup :: (FiniteBits k, PrimMonad m)+  => MTrie (PrimState m) k v+  -> k+  -> m (Maybe v)+lookup theTrie theKey = go Nothing theTrie theKey where+  totalBits :: Int+  totalBits = finiteBitSize theKey+  -- mask :: k+  mask = bit (totalBits - 1)+  -- zero :: k+  zero = zeroBits+  go !mres (MTrie valRef leftRef rightRef) key = do+    mval <- readMutMaybeVar valRef+    let mresNext = case mval of+          Nothing -> mres+          Just res -> Just res+        chosenRef = if (mask .&. key) == zero+          then leftRef+          else rightRef+    chosen <- readMutMaybeVar chosenRef+    case chosen of+      Nothing -> return mresNext+      Just nextTrie -> go mresNext nextTrie (unsafeShiftL key 1)++insert :: (FiniteBits k, PrimMonad m)+  => MTrie (PrimState m) k v+  -> k -- ^ prefix key+  -> v -- ^ value+  -> m ()+insert trie key = insertPrefix trie (finiteBitSize key) key++insertPrefix :: (FiniteBits k, PrimMonad m)+  => MTrie (PrimState m) k v+  -> Int -- ^ significant bits from key+  -> k -- ^ prefix key+  -> v -- ^ value+  -> m ()+insertPrefix theTrie theSig theKey value =+  if theSig > totalBits+    then return ()+    else go theSig theKey theTrie+  where+  totalBits :: Int+  totalBits = finiteBitSize theKey+  -- mask :: k+  mask = bit (totalBits - 1)+  -- zero :: k+  zero = zeroBits+  go !significant !key (MTrie valRef leftRef rightRef) = if significant > 0+    then do+      let chosenRef = if (mask .&. key) == zero+            then leftRef+            else rightRef+      chosen <- readMutMaybeVar chosenRef+      nextTrie <- case chosen of+        Nothing -> do+          nextTrie <- new+          writeMutMaybeVar chosenRef (Just nextTrie)+          return nextTrie+        Just nextTrie -> return nextTrie+      go (significant - 1) (unsafeShiftL key 1) nextTrie+    else writeMutMaybeVar valRef (Just value)++
test/Spec.hs view
@@ -10,8 +10,10 @@ import Test.HUnit                           (Assertion,(@?=)) import Data.Monoid                          (All(..)) import Data.Traversable+import Data.Foldable import Control.Applicative import Data.Coerce+import Data.Functor.Compose  import Data.Word import Data.Function (on)@@ -23,11 +25,14 @@ import qualified Data.Map.Strict as Map import Debug.Trace +import Data.Primitive.Array.Maybe+ import qualified Data.Vector as V import qualified Data.ArrayList.Generic as ArrayList import qualified Data.Heap.Mutable.ModelD as HeapD import qualified Data.Graph.Mutable as MGraph import qualified Data.Graph.Immutable as Graph+import qualified Data.Trie.Mutable.Bits as BitTrie  main :: IO () main = defaultMain tests@@ -46,6 +51,13 @@     [ testProperty "Building only from vertices" graphBuildingVertices     , testProperty "Trivial case for Dijkstras Algorithm" dijkstraEasyDistance     ]+  , testGroup "MaybeArray"+    [ testCase "Values are as expected" maybeArrayWorks+    ]+  , testGroup "Bit Trie"+    [ testProperty "Basic Insert and Lookup" bitTrieBasic+    , testProperty "Prefixes" bitTriePrefix+    ]   ]  testElements :: Int@@ -140,8 +152,6 @@                    for vlist $ \vb ->                      Const (All $ Graph.lookupEdge va vb g == Just onlyEdge) -data Thing = Thing- -- Every node is connected to at most two other nodes. The end -- nodes only have one neighbor. Go from one end node to the other. dijkstraEasyDistance :: [Word32] -> Bool@@ -163,3 +173,54 @@           let expected = Min (sum xs)            in expected == Graph.dijkstra (\_ _ (Min x) distance -> Min (x + distance)) (Min 0) start end g +data Thing = Foo | Bar Int | Baz Bool+  deriving (Eq,Show)++maybeArrayWorks :: IO ()+maybeArrayWorks = do+  arr <- newMaybeArray 17 Nothing+  writeMaybeArray arr 0 (Just Foo)+  writeMaybeArray arr 9 (Just (Bar 62))+  writeMaybeArray arr 16 (Just (Baz True))+  a <- readMaybeArray arr 0+  b <- readMaybeArray arr 9+  c <- readMaybeArray arr 16+  d <- readMaybeArray arr 12+  arr2 <- newMaybeArray 17 (Just (Baz True))+  writeMaybeArray arr 2 Nothing+  writeMaybeArray arr 7 (Just (Bar 15))+  e <- readMaybeArray arr 2+  f <- readMaybeArray arr 7+  (a,b,c,d,e,f) @?=+    ( Just Foo, Just $ Bar 62+    , Just $ Baz True, Nothing+    , Nothing, Just (Bar 15)+    )++bitTrieBasic :: [Word8] -> Bool+bitTrieBasic xs =+  let res = runST $ do+        trie <- BitTrie.new+        for_ xs $ \x -> BitTrie.insert trie x x+        Const (All res) <- getCompose $ for_ xs $ \x -> Compose $ do+          m <- BitTrie.lookup trie x+          return $ Const $ case m of+            Nothing -> All False+            Just y -> All (x == y)+        return res+   in res == True++bitTriePrefix :: Word8 -> Bool+bitTriePrefix x = do+  let res = runST $ do+        trie <- BitTrie.new+        BitTrie.insertPrefix trie 4 0xF0 'B'+        BitTrie.insertPrefix trie 1 0x80 'A'+        BitTrie.insertPrefix trie 4 0x00 'C'+        m <- BitTrie.lookup trie x+        return $ case () of+          () | x <  0x10 -> m == Just 'C'+             | x >= 0xF0 -> m == Just 'B'+             | x >= 0x80 -> m == Just 'A'+             | otherwise -> m == Nothing+   in res == True