packages feed

impure-containers 0.4.0 → 0.4.1

raw patch · 10 files changed

+216/−68 lines, 10 filesdep +criteriondep ~basedep ~containersdep ~hashablePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: criterion

Dependency ranges changed: base, containers, hashable, primitive, vector

API changes (from Hackage documentation)

- Data.Graph.Immutable: dijkstraMonoidal :: (Ord s, Monoid s) => (v -> v -> s -> e -> s) -> s -> Vertex g -> Vertex g -> Graph g e v -> s
- Data.Graph.Immutable: dijkstraMonoidalCover :: (Ord s, Monoid s, Foldable t) => (v -> v -> s -> e -> s) -> s -> t (Vertex g) -> Graph g e v -> Vertices g s
+ Data.Graph.Immutable: atVertex :: Vertex g -> Graph g e v -> v
+ Data.Graph.Immutable: dijkstraDistance :: (Num e, Ord e) => Vertex g -> Vertex g -> Graph g e v -> Maybe e
+ Data.Graph.Immutable: dijkstraFoldM :: (Ord s, Monoid s, Foldable t, PrimMonad m) => (v -> v -> s -> e -> s) -> (v -> s -> x -> m x) -> s -> x -> t (Vertex g) -> Graph g e v -> m x
+ Data.Graph.Immutable: verticesTraverse :: Applicative m => (Vertex g -> v -> m a) -> Vertices g v -> m (Vertices g a)
+ Data.Maybe.Unsafe: data UnsafeMaybe a
+ Data.Maybe.Unsafe: fromMaybe :: Maybe a -> UnsafeMaybe a
+ Data.Maybe.Unsafe: instance GHC.Base.Applicative Data.Maybe.Unsafe.UnsafeMaybe
+ Data.Maybe.Unsafe: instance GHC.Base.Functor Data.Maybe.Unsafe.UnsafeMaybe
+ Data.Maybe.Unsafe: instance GHC.Base.Monad Data.Maybe.Unsafe.UnsafeMaybe
+ Data.Maybe.Unsafe: just :: a -> UnsafeMaybe a
+ Data.Maybe.Unsafe: maybe :: b -> (a -> b) -> UnsafeMaybe a -> b
+ Data.Maybe.Unsafe: nothing :: UnsafeMaybe a
+ Data.Maybe.Unsafe: toMaybe :: UnsafeMaybe a -> Maybe a
- Data.Graph.Immutable: dijkstra :: (Num e, Ord e) => Vertex g -> Vertex g -> Graph g e v -> Maybe e
+ Data.Graph.Immutable: dijkstra :: (Ord s, Monoid s, Foldable t) => (v -> v -> s -> e -> s) -> s -> t (Vertex g) -> Graph g e v -> Graph g e s
- Data.Graph.Immutable: setVertices :: Vertices g v -> Graph g e v -> Graph g e v
+ Data.Graph.Immutable: setVertices :: Vertices g v -> Graph g e w -> Graph g e v
- Data.Trie.Immutable.Bits: Trie :: !(Maybe v) -> !(Maybe (Trie k v)) -> !(Maybe (Trie k v)) -> Trie k v
+ Data.Trie.Immutable.Bits: Trie :: !(UnsafeMaybe v) -> !(UnsafeMaybe (Trie k v)) -> !(UnsafeMaybe (Trie k v)) -> Trie k v
- Data.Trie.Immutable.Bits: [trieLeft] :: Trie k v -> !(Maybe (Trie k v))
+ Data.Trie.Immutable.Bits: [trieLeft] :: Trie k v -> !(UnsafeMaybe (Trie k v))
- Data.Trie.Immutable.Bits: [trieRight] :: Trie k v -> !(Maybe (Trie k v))
+ Data.Trie.Immutable.Bits: [trieRight] :: Trie k v -> !(UnsafeMaybe (Trie k v))
- Data.Trie.Immutable.Bits: [trieValue] :: Trie k v -> !(Maybe v)
+ Data.Trie.Immutable.Bits: [trieValue] :: Trie k v -> !(UnsafeMaybe v)

Files

+ bench/Main.hs view
@@ -0,0 +1,4 @@+module Main (main) where++main :: IO ()+main = return ()
impure-containers.cabal view
@@ -1,5 +1,5 @@ name:                impure-containers-version:             0.4.0+version:             0.4.1 synopsis:            Mutable containers in haskell description:         Please see README.md homepage:            https://github.com/andrewthad/impure-containers#readme@@ -25,7 +25,6 @@     -- Data.Heap.Mutable.ModelB     Data.Heap.Mutable.ModelC     Data.Heap.Mutable.ModelD-    -- Data.Vector.Unique     Data.Graph.Immutable     Data.Graph.Mutable     Data.Trie.Mutable.Bits@@ -37,6 +36,7 @@     Data.Primitive.Array.Maybe     Data.Primitive.MutVar.Maybe     Data.Primitive.Bool+    Data.Maybe.Unsafe     -- Data.Containers.Impure.Internal   other-modules:     Data.HashMap.Mutable.Internal.Array@@ -47,11 +47,11 @@     Data.HashMap.Mutable.Internal.UnsafeTricks     Data.HashMap.Mutable.Internal.Utils   build-depends:-      base >= 4.7 && < 5-    , hashable-    , primitive-    , vector-    , containers+      base >= 4.8 && < 5+    , hashable >= 1.2 && < 1.3+    , primitive >= 0.6 && < 0.7+    , vector >= 0.11 && < 0.13+    , containers > 0.5 && < 0.6     , ghc-prim   default-language:    Haskell2010 @@ -124,6 +124,17 @@     , vector     , transformers   ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++benchmark impure-containers-bench+  type:                exitcode-stdio-1.0+  hs-source-dirs:      bench+  main-is:             Main.hs+  build-depends:+      base+    , impure-containers+    , criterion+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -O2   default-language:    Haskell2010  source-repository head
src/Data/Graph/Immutable.hs view
@@ -14,6 +14,7 @@   ( -- * Graph Operations     lookupVertex   , lookupEdge+  , atVertex   , mapVertices   , traverseVertices_   , traverseEdges_@@ -26,14 +27,15 @@   , with     -- * Algorithms   , dijkstra-  , dijkstraMonoidal-  , dijkstraMonoidalCover+  , dijkstraDistance+  , dijkstraFoldM     -- * Size and Vertex   , sizeInt   , vertexInt     -- * Vertices   , verticesRead   , verticesLength+  , verticesTraverse   , verticesTraverse_   , verticesToVertexList   , verticesToVector@@ -71,6 +73,9 @@     Nothing -> Nothing     Just ix -> Just (V.unsafeIndex (V.unsafeIndex edges x) ix) +atVertex :: Vertex g -> Graph g e v -> v+atVertex v g = verticesRead (vertices g) v+ -- | Not the same as 'fmap' because the function also takes the vertex id. mapVertices :: (Vertex g -> a -> b) -> Graph g e a -> Graph g e b mapVertices f (Graph sg) = Graph sg@@ -93,7 +98,6 @@         ) allVertices  -- | Traverse the neighbors of a specific vertex.---   Change this to use unsafeRead some time soon. traverseNeighbors_ :: Applicative m   => (Vertex g -> v -> e -> m a)   -> Vertex g@@ -101,13 +105,13 @@   -> m () traverseNeighbors_ f (Vertex x) (Graph g) =   let allVertices  = graphVertices g-      theVertices  = graphOutboundNeighborVertices g V.! x-      edges        = graphOutboundNeighborEdges g V.! x+      theVertices  = V.unsafeIndex (graphOutboundNeighborVertices g) x+      edges        = V.unsafeIndex (graphOutboundNeighborEdges g) x       numNeighbors = U.length theVertices       go !i = if i < numNeighbors-        then let vertexNum = theVertices U.! i-                 vertexVal = allVertices V.! vertexNum-                 edgeVal = edges V.! i+        then let vertexNum = U.unsafeIndex theVertices i+                 vertexVal = V.unsafeIndex allVertices vertexNum+                 edgeVal = V.unsafeIndex edges i               in f (Vertex vertexNum) vertexVal edgeVal *> go (i + 1)         else pure ()    in go 0@@ -118,7 +122,7 @@ vertices (Graph (SomeGraph v _ _)) = Vertices v  -- | Set the vertices of a graph.-setVertices :: Vertices g v -> Graph g e v -> Graph g e v+setVertices :: Vertices g v -> Graph g e w -> Graph g e v setVertices (Vertices x) (Graph (SomeGraph _ a b)) = Graph (SomeGraph x a b)  -- | Get the number of vertices in a graph.@@ -207,16 +211,17 @@ --   The source code of this function provides an example of how to use --   the generalized variants of Dijkstra\'s algorithm provided by this --   module.-dijkstra :: (Num e, Ord e)+dijkstraDistance :: (Num e, Ord e)   => Vertex g -- ^ Start vertex   -> Vertex g -- ^ End vertex   -> Graph g e v -- ^ Graph   -> Maybe e-dijkstra start end g = getMinDistance-  ( dijkstraMonoidal+dijkstraDistance start end g = +  getMinDistance $ atVertex end+  ( dijkstra     (\_ _ mdist e -> addMinDistance mdist e)     (MinDistance (Just 0))-    start end g+    (Identity start) g   )   where addMinDistance (MinDistance m) e = MinDistance (fmap (+ e) m) @@ -238,17 +243,6 @@   mempty = MinDistance Nothing   mappend ma mb = min ma mb --- | A generalized version of Dijkstra\'s algorithm.-dijkstraMonoidal :: (Ord s, Monoid s)-  => (v -> v -> s -> e -> s) -- Weight combining function-  -> s           -- ^ Weight to assign start vertex-  -> Vertex g    -- ^ Start vertex-  -> Vertex g    -- ^ End vertex-  -> Graph g e v -- ^ Graph-  -> s-dijkstraMonoidal f s start end g =-  verticesRead (dijkstraMonoidalCover f s (Identity start) g) end- -- | This is a generalization of Dijkstra\'s algorithm. Like the original, --   it takes a start 'Vertex' but unlike the original, it does not take --   an end. It will continue traversing the 'Graph' until it has touched@@ -298,14 +292,41 @@ -- --   This function could be written without unsafely pattern matching --   on 'Vertex', but doing so allows us to use a faster heap implementation.-dijkstraMonoidalCover ::+dijkstra ::      (Ord s, Monoid s, Foldable t)   => (v -> v -> s -> e -> s) -- ^ Weight function-  -> s                 -- ^ Weight to assign start vertex-  -> t (Vertex g)      -- ^ Start vertices-  -> Graph g e v       -- ^ Graph-  -> Vertices g s-dijkstraMonoidalCover f s0 v0 g = runST $ do+  -> s -- ^ Weight to assign start vertex+  -> t (Vertex g) -- ^ Start vertices+  -> Graph g e v -- ^ Graph+  -> Graph g e s+dijkstra f s0 v0 g = +  fst $ runST $ dijkstraGeneral f (\_ _ _ -> return ()) s0 () v0 g++-- Traverse every vertex in the graph and monadically fold+-- their values.+dijkstraFoldM :: +     (Ord s, Monoid s, Foldable t, PrimMonad m)+  => (v -> v -> s -> e -> s) -- ^ Weight function+  -> (v -> s -> x -> m x) -- ^ Monadic fold function+  -> s -- ^ Weight to assign start vertex+  -> x -- ^ Initial accumulator+  -> t (Vertex g) -- ^ Start vertices+  -> Graph g e v -- ^ Graph+  -> m x+dijkstraFoldM f mf s0 acc v0 g = +  fmap snd $ dijkstraGeneral f mf s0 acc v0 g++-- | This is not exported+dijkstraGeneral ::+     (Ord s, Monoid s, Foldable t, PrimMonad m)+  => (v -> v -> s -> e -> s) -- ^ Weight function+  -> (v -> s -> x -> m x) -- ^ Monadic fold+  -> s -- ^ Weight to assign start vertex+  -> x -- ^ Initial fold value+  -> t (Vertex g) -- ^ Start vertices+  -> Graph g e v -- ^ Graph+  -> m (Graph g e s, x)+dijkstraGeneral f step s0 x0 v0 g = do   let theSize = size g       oldVertices = vertices g   newVertices <- Mutable.verticesReplicate theSize mempty@@ -318,10 +339,10 @@     -- We know it's ok in this case because the min heap does not     -- create Ints that we did not push onto it.     Heap.unsafePush s0 (getVertexInternal v) heap-  let go = do+  let go x = do         m <- Heap.pop heap         case m of-          Nothing -> return True+          Nothing -> return (BoolWith True x)           Just (s,unwrappedVertexIx) -> do             -- Unsafe cast from Int to Vertex             let vertex = Vertex unwrappedVertexIx@@ -336,13 +357,16 @@                   (getVertexInternal neighborVertex)                   heap               ) vertex g-            return False-      runMe = do-        isDone <- go-        if isDone then return () else runMe-  runMe+            xNext <- step value s x+            return (BoolWith False xNext)+      runMe x = do+        BoolWith isDone xNext <- go x+        if isDone then return xNext else runMe xNext+  xFinal <- runMe x0   newVerticesFrozen <- verticesFreeze newVertices-  return newVerticesFrozen+  return (setVertices newVerticesFrozen g, xFinal)++data BoolWith a = BoolWith Bool !a  -- mutableIForM_ :: PrimMonad m => MVector (PrimState m) a -> (Int -> a -> m b) -> m () -- mutableIForM_ m f = forM_ (take (MV.length m) (enumFrom 0)) $ \i -> do
src/Data/Graph/Mutable.hs view
@@ -23,10 +23,11 @@ import Data.Hashable (Hashable) import qualified Data.HashMap.Mutable.Basic as HashTable --- | $mutgraph--- Operations that mutate a 'MGraph'. Vertices and edges can both be added,--- and edges can be deleted, but vertices cannot be deleted. Providing such--- an operation would undermine the safety that this library provides.+{- $mutgraph+   Operations that mutate a 'MGraph'. Vertices and edges can both be added,+   and edges can be deleted, but vertices cannot be deleted. Providing such+   an operation would undermine the safety that this library provides.+-}  -- | This does two things: --@@ -60,16 +61,17 @@     Nothing -> HashTable.insert edges (IntPair a b) e     Just eOld -> HashTable.insert edges (IntPair a b) (combine eOld e) --- | $mutvertices--- Operations that mutate a 'MVertices' or a 'MUVertices'. These functions have nothing--- to do with 'MGraph' and are not usually needed by end users of this library. They--- are useful for users writing algorithms that need to mark vertices in a graph as--- it is traversed.------ All of these operations are--- wrappers around operations from @Data.Vector.Mutable@ and @Data.Vector.Unbox.Mutable@.--- As long as you do not import @Data.Graph.Types.Internal@, this library guarentees that--- these operations will not fail at runtime.+{- $mutvertices+   Operations that mutate a 'MVertices' or a 'MUVertices'. These functions have nothing+   to do with 'MGraph' and are not usually needed by end users of this library. They+   are useful for users writing algorithms that need to mark vertices in a graph as+   it is traversed.++   All of these operations are+   wrappers around operations from @Data.Vector.Mutable@ and @Data.Vector.Unbox.Mutable@.+   As long as you do not import @Data.Graph.Types.Internal@, this library guarentees that+   these operations will not fail at runtime.+-}  verticesReplicate :: PrimMonad m => Size g -> v -> m (MVertices (PrimState m) g v) verticesReplicate (Size i) v = fmap MVertices (MV.replicate i v)
src/Data/HashMap/Mutable/Internal/UnsafeTricks.hs view
@@ -21,6 +21,7 @@ import qualified Data.Vector.Mutable as M #ifdef UNSAFETRICKS import           GHC.Exts+import           GHC.Types import           Unsafe.Coerce  #if __GLASGOW_HASKELL__ >= 707
+ src/Data/Maybe/Unsafe.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE MagicHash, BangPatterns #-}+module Data.Maybe.Unsafe (UnsafeMaybe+                         ,just+                         ,nothing+                         ,fromMaybe+                         ,maybe+                         ,toMaybe) where++import Unsafe.Coerce+import System.IO.Unsafe+import System.Mem.StableName+import GHC.Prim+import GHC.Types+import Prelude hiding (maybe)++thunk :: Int -> Int+thunk x = error "bang"+{-# NOINLINE thunk #-}++thunkStableName :: StableName (Int -> Int)+thunkStableName = unsafePerformIO (makeStableName thunk)++-- | nothingSurrogate stands in for the value Nothing; we distinguish it by pointer+nothingSurrogate :: Any+nothingSurrogate = unsafeCoerce thunk+{-# NOINLINE nothingSurrogate #-}++nothingStableName :: StableName Any+nothingStableName = unsafePerformIO (makeStableName nothingSurrogate)++newtype UnsafeMaybe a = UnsafeMaybe Any++instance Functor UnsafeMaybe where+  fmap f = maybe nothing (just . f)++instance Applicative UnsafeMaybe where+  pure = just+  {-# INLINE pure #-}+  -- (UnsafeMaybe f) <*> (UnsafeMaybe x) = case reallyUnsafePtrEquality# f nothingSurrogate of+  --   0# -> case reallyUnsafePtrEquality# x nothingSurrogate of+  --     0# -> just ((unsafeCoerce f) (unsafeCoerce x))+  --     _  -> nothing+  --   _  -> nothing+  mf <*> mx = maybe nothing (\f -> maybe nothing (just . f) mx) mf+  {-# INLINE (<*>) #-}++instance Monad UnsafeMaybe where+  return = just+  -- (UnsafeMaybe x) >>= f = case reallyUnsafePtrEquality# x nothingSurrogate of+  --   0# -> f (unsafeCoerce x)+  --   _  -> nothing+  mx >>= f = maybe nothing f mx+++just :: a -> UnsafeMaybe a+just a = UnsafeMaybe (unsafeCoerce a)++nothing :: UnsafeMaybe a+nothing = UnsafeMaybe nothingSurrogate++fromMaybe :: Maybe a -> UnsafeMaybe a+fromMaybe (Just a) = just a+fromMaybe Nothing  = nothing+{-# INLINE fromMaybe #-}++maybe :: b -> (a -> b) -> UnsafeMaybe a -> b+maybe !def transform (UnsafeMaybe !a) = case eqStableName thunkStableName named ||+                                            eqStableName nothingStableName named of+  False -> transform (unsafeCoerce a)+  True  -> def+  where named = unsafePerformIO (makeStableName a)+{-# INLINE maybe #-}++-- toMaybe :: UnsafeMaybe a -> Maybe a+-- toMaybe (UnsafeMaybe a) = case reallyUnsafePtrEquality# a nothingSurrogate of+--   0# -> Just (unsafeCoerce a)+--   _  -> Nothing+-- {-# INLINE toMaybe #-}++toMaybe :: UnsafeMaybe a -> Maybe a+toMaybe = maybe Nothing Just
src/Data/Primitive/Array/Maybe.hs view
@@ -10,7 +10,8 @@  import Control.Monad.Primitive import Data.Primitive.Array-import GHC.Prim (reallyUnsafePtrEquality#,Any)+import GHC.Prim (reallyUnsafePtrEquality#)+import GHC.Exts (Any) import Unsafe.Coerce (unsafeCoerce)  newtype MutableMaybeArray s a = MutableMaybeArray (MutableArray s Any)
src/Data/Primitive/MutVar/Maybe.hs view
@@ -13,6 +13,7 @@  import Unsafe.Coerce import GHC.Prim+import GHC.Types  import Data.Maybe 
src/Data/Trie/Immutable/Bits.hs view
@@ -13,15 +13,16 @@ import Data.Primitive.ByteArray import Data.Primitive.MutVar.Maybe import Data.Trie.Mutable.Bits (MTrie(..))+import Data.Maybe.Unsafe  data Trie k v = Trie-  { trieValue :: !(Maybe v)-  , trieLeft  :: !(Maybe (Trie k v))-  , trieRight :: !(Maybe (Trie k v))+  { trieValue :: !(UnsafeMaybe v)+  , trieLeft  :: !(UnsafeMaybe (Trie k v))+  , trieRight :: !(UnsafeMaybe (Trie k v))   }  empty :: Trie k v-empty = Trie Nothing Nothing Nothing+empty = Trie nothing nothing nothing  -- | This gives the best match, that is, the --   value stored at the longest prefix that@@ -30,7 +31,7 @@   => Trie k v   -> k   -> Maybe v-lookup theTrie theKey = go Nothing theTrie theKey where+lookup theTrie theKey = toMaybe (go nothing theTrie theKey) where   totalBits :: Int   totalBits = finiteBitSize theKey   -- mask :: k@@ -39,7 +40,7 @@   zero = zeroBits   go !mres (Trie mval mleft mright) key =     let chosen = if (mask .&. key) == zero then mleft else mright-     in case chosen of+     in case toMaybe chosen of           Nothing -> mval           Just nextTrie -> go mval nextTrie (unsafeShiftL key 1) @@ -55,5 +56,5 @@     immutableRight <- case mright of       Just right -> fmap Just $ go right       Nothing -> return Nothing-    return (Trie mval immutableLeft immutableRight)+    return undefined --(Trie mval immutableLeft immutableRight) 
test/Spec.hs view
@@ -16,6 +16,7 @@ import Data.Functor.Compose  import Data.Word+import Data.Functor.Identity import Data.Function (on) import Data.List (groupBy) import Control.Monad@@ -33,6 +34,8 @@ import qualified Data.Graph.Mutable as MGraph import qualified Data.Graph.Immutable as Graph import qualified Data.Trie.Mutable.Bits as BitTrie+import qualified Data.Maybe.Unsafe as UMaybe+import           Data.Maybe.Unsafe hiding (maybe)  main :: IO () main = defaultMain tests@@ -58,6 +61,10 @@     [ testProperty "Basic Insert and Lookup" bitTrieBasic     , testProperty "Prefixes" bitTriePrefix     ]+  , testGroup "Unsafe Maybe"+    [ testCase "Unsafe Maybe functions" unsafeMaybeWorks+    -- , testProperty "Unsafe Maybe Quickcheck props" unsafeMaybeProp+    ]   ]  testElements :: Int@@ -170,7 +177,11 @@         (Just _,Nothing)  -> False         (Just start, Just end) ->           let expected = Min (sum xs)-           in expected == Graph.dijkstraMonoidal (\_ _ (Min x) distance -> Min (x + distance)) (Min 0) start end g+           in expected == Graph.atVertex end +                (Graph.dijkstra +                  (\_ _ (Min x) distance -> Min (x + distance)) +                  (Min 0) (Identity start) g+                )  data Thing = Foo | Bar Int | Baz Bool   deriving (Eq,Show)@@ -195,6 +206,17 @@     , Just $ Baz True, Nothing     , Nothing, Just (Bar 15)     )++unsafeMaybeWorks :: IO ()+unsafeMaybeWorks = (a,b,c,d,e,f,g,h) @?= (Nothing,Just 0,1,Nothing,Just 3,Nothing,Just 4,Nothing)+  where a = toMaybe $ nothing :: Maybe Int+        b = toMaybe $ just (0 :: Int)+        c = UMaybe.maybe (0 :: Int) (+1) (just 0)+        d = toMaybe $ nothing :: Maybe Int+        e = toMaybe $ fmap (+1) (just 2)+        f = toMaybe $ fmap (+1) nothing+        g = toMaybe $ just (just 4) >>= id+        h = toMaybe $ UMaybe.maybe nothing (const nothing) nothing :: Maybe Int  bitTrieBasic :: [Word8] -> Bool bitTrieBasic xs =