packages feed

concurrent-supply (empty) → 0.1

raw patch · 4 files changed

+192/−0 lines, 4 filesdep +basedep +ghc-primdep +hashablesetup-changed

Dependencies added: base, ghc-prim, hashable

Files

+ Control/Concurrent/Supply.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE MagicHash, UnboxedTuples, Trustworthy #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Control.Concurrent.Supply+-- Copyright   :  (C) 2011 Edward Kmett,+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>+-- Stability   :  provisional+-- Portability :  portable+--+-- A globally unique fresh identifier supply with local pooling and replay+-- support.+----------------------------------------------------------------------------+module Control.Concurrent.Supply+  ( Supply+  -- * Variables+  , newSupply+  , freshId+  , splitSupply+  -- * Unboxed API+  , freshId#+  , splitSupply#+  ) where++import Data.Hashable+import Data.IORef+import Data.Functor ((<$>))+import Data.Monoid+import GHC.IO (unsafeDupablePerformIO)+import GHC.Types (Int(..))+import GHC.Prim (Int#)++infixr 5 :-+data Stream a = a :- Stream a++instance Functor Stream where+  fmap f (a :- as) = f a :- fmap f as++extract :: Stream a -> a+extract (a :- _) = a++units :: Stream ()+units = () :- units++data Block = Block Int !(Stream Block)++instance Eq Block where+  Block a (Block b _ :- _) == Block c (Block d _ :- _) = a == c && b == d++instance Ord Block where+  Block a (Block b _ :- _) `compare` Block c (Block d _ :- _) = compare a c `mappend` compare b d++instance Show Block where+  showsPrec d (Block a (Block b _ :- _)) = showParen (d >= 10) $+    showString "Block " . showsPrec 10 a . showString " (Block " . showsPrec 10 b . showString " ... :- ...)"++instance Hashable Block where+  hashWithSalt s (Block a (Block b _ :- _)) = s `hashWithSalt` a `hashWithSalt` b++blockSize :: Int+blockSize = 1024+{-# INLINE blockSize #-}++-- Minimum size to be worth splitting a supply rather than just CAS'ing twice to avoid multiple subsequent biased splits+minSplitSupplySize :: Int+minSplitSupplySize = 32 -- based on sqrt blockSize+{-# INLINE minSplitSupplySize #-}++blockCounter :: IORef Int+blockCounter = unsafeDupablePerformIO $ newIORef 0++gen :: () -> Block+gen _ = Block (unsafeDupablePerformIO $ atomicModifyIORef blockCounter $ \ i -> let i' = i + blockSize in (i', i))+              (gen <$> units)+{-# NOINLINE gen #-}++newBlock :: IO Block+newBlock = return $ gen ()+{-# NOINLINE newBlock #-}++splitBlock# :: Block -> (# Block, Block #)+splitBlock# (Block i (x :- xs)) = (# x, Block i xs #)+{-# INLINE splitBlock# #-}++-- | A user managed globally unique variable supply.+data Supply = Supply {-# UNPACK #-} !Int {-# UNPACK #-} !Int Block+  deriving (Eq,Ord,Show)++instance Hashable Supply where+  hashWithSalt s (Supply i j b) = s `hashWithSalt` i `hashWithSalt` j `hashWithSalt` b++blockSupply :: Block -> Supply+blockSupply (Block i bs) = Supply i (i + blockSize - 1) (extract bs)++-- | Grab a new supply. Any two supplies obtained with newSupply are guaranteed to return+-- disjoint sets of identifiers. Replaying the same sequence of operations on the same+-- Supply will yield the same results.+newSupply :: IO Supply+newSupply = blockSupply <$> newBlock++-- | Obtain a fresh Id from a Supply.+freshId :: Supply -> (Int, Supply)+freshId s = case freshId# s of+  (# i, s' #) -> (I# i, s')++-- | Split a supply into two supplies that will return disjoint identifiers+splitSupply :: Supply -> (Supply, Supply)+splitSupply s = case splitSupply# s of+  (# l, r #) -> (l, r)++-- | An unboxed version of freshId+freshId# :: Supply -> (# Int#, Supply #)+freshId# (Supply i@(I# i#) j b)+  | i /= j = (# i#, Supply (i + 1) j b #)+  | otherwise = case b of+    Block k b' -> (# i#, Supply k (k + blockSize - 1) (extract b') #)+{-# INLINE freshId# #-}++-- | An unboxed version of splitSupply+splitSupply# :: Supply -> (# Supply, Supply #)+splitSupply# (Supply i k b) = case splitBlock# b of+    (# bl, br #)+      | k - i >= minSplitSupplySize+      , j <- i + div (k - i) 2 ->+        (# Supply i j bl, Supply (j + 1) k br #)+      | Block x (l :- r :- _) <- bl+      , y <- x + div blockSize 2+      , z <- x + blockSize - 1 ->+        (# Supply x (y - 1) l, Supply y z r #)+{-# INLINE splitSupply# #-}
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright 2011 Edward Kmett++All rights reserved.++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 author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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
+ concurrent-supply.cabal view
@@ -0,0 +1,29 @@+name:          concurrent-supply+category:      Concurrency, Parallelism+version:       0.1+license:       BSD3+cabal-version: >= 1.10+license-file:  LICENSE+author:        Edward A. Kmett+maintainer:    Edward A. Kmett <ekmett@gmail.com>+stability:     experimental+homepage:      http://github.com/ekmett/concurrent-supply/+copyright:     Copyright (C) 2011 Edward A. Kmett+synopsis:      A fast current unique identifier supply with a pure API+description:   A fast current unique identifier supply with a pure API+build-type:    Simple++source-repository head+  type: git+  location: git://github.com/ekmett/concurrent-supply.git++library+  default-language: Haskell2010+  other-extensions: MagicHash, UnboxedTuples+  exposed-modules:+    Control.Concurrent.Supply+  ghc-options: -Wall+  build-depends:+    base     >= 4 && < 5,+    hashable >= 1.1 && < 1.2,+    ghc-prim >= 0.2 && < 0.4