packages feed

stm-supply (empty) → 0.1.0.0

raw patch · 5 files changed

+182/−0 lines, 5 filesdep +QuickCheckdep +Uniquedep +asyncsetup-changed

Dependencies added: QuickCheck, Unique, async, base, concurrent-supply, random, stm-supply

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Joe Canero (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Joe Canero nor the names of other+      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+OWNER 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
+ src/Control/Concurrent/STMSupply.hs view
@@ -0,0 +1,33 @@+module Control.Concurrent.STMSupply+(+  STMSupply+, newSTMSupplyIO+, freshId+, splitSupply+) where++import qualified Control.Concurrent.Supply as S+import GHC.Conc++-- | newtype wrapper around a TVar Supply.+newtype STMSupply = Supply {+    unSupply :: TVar S.Supply+  }++-- | Construct a new @STMSupply@ in the IO Monad.+newSTMSupplyIO :: IO STMSupply+newSTMSupplyIO = Supply <$> (newTVarIO =<< S.newSupply)++-- | Using an @STMSupply@, atomically get a fresh ID.+freshId :: STMSupply -> STM Int+freshId Supply{unSupply = s} = do+  (i, s') <- S.freshId <$> readTVar s+  writeTVar s s' >> return i++-- | Using an @STMSupply@, atomically split the underlying @Supply@ into two.+--  Stores one of the new supplies in the STMSupply that was the first+--  argument, and returns the second Supply.+splitSupply :: STMSupply -> STM STMSupply+splitSupply Supply{unSupply = s} = do+  (s1, s2) <- S.splitSupply <$> readTVar s+  writeTVar s s1 >> (Supply <$> newTVar s2)
+ stm-supply.cabal view
@@ -0,0 +1,38 @@+name:                stm-supply+version:             0.1.0.0+synopsis:            STM wrapper around Control.Concurrent.Supply.+description:         Please see README.md+homepage:            https://github.com/caneroj1/stm-supply#readme+license:             BSD3+license-file:        LICENSE+author:              Joe Canero+maintainer:          jmc41493@gmail.com+copyright:           Copyright: (c) 2016 Joe Canero+category:            Control+build-type:          Simple+-- extra-source-files:+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Control.Concurrent.STMSupply+  build-depends:       base >= 4.7 && < 5+                     , concurrent-supply+  default-language:    Haskell2010++test-suite stm-supply-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:       base+                     , stm-supply+                     , async+                     , random+                     , QuickCheck+                     , Unique+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/caneroj1/stm-supply
+ test/Spec.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE TemplateHaskell #-}++module Main where++import Control.Concurrent.Async+import Control.Concurrent.STMSupply+import Control.Monad+import Data.List+import Data.List.Unique+import GHC.Conc+import System.Random+import Test.QuickCheck+import Test.QuickCheck.Monadic++-- Each split supply should generate distinct sequences of integers.+prop_idSplitSupply :: Positive Int -> Property+prop_idSplitSupply n = monadicIO $ do+  s   <- run newSTMSupplyIO+  s'  <- run . atomically $ splitSupply s+  ls1 <- run $ testImpl_idSequenceN n s+  ls2 <- run $ testImpl_idSequenceN n s'+  assert (satisfy n ls1 &&+          satisfy n ls2 &&+          ls1 /= ls2)++-- Spawn multiple async actions and have them each get a fresh ID.+-- The sorted IDs should all be distinct and sequential.+prop_idSequenceN :: Positive Int -> Property+prop_idSequenceN n = monadicIO $ do+  supply <- run newSTMSupplyIO+  ls     <- run $ testImpl_idSequenceN n supply+  assert $ satisfy n ls++-- Spawn multiple async actions and have them each get some fresh IDs+-- and split the supply. We want every ID retrieved to be unique.+-- We will spawn N async actions that each split the supply and then+-- take N IDs. We expect NxN unique integers.+prop_idSequenceSplitsN :: Positive Int -> Property+prop_idSequenceSplitsN p@(Positive n) = monadicIO $ do+  s  <- run newSTMSupplyIO+  ls <- run $ sortUniq . concat <$>+        (mapM wait =<< mapM (\_ -> async (asyncAction s)) [0..(n-1)])+  assert (length ls == (n * n))+  where+    asyncAction s = do+      threadDelay <$> randomDelay+      newSupply <- atomically $ splitSupply s+      atomically $ replicateM n (freshId newSupply)++-- testImpl_idSequence accepts an Int N and an STMSupply+-- and creates N async workers that will each atomically get a+-- freshID. We should produce a sorted list of integers L such that+-- L contains N distinct, sequential integers+testImpl_idSequenceN :: Positive Int -> STMSupply -> IO [Int]+testImpl_idSequenceN (Positive n) supply =+  sort <$> (mapM wait =<< mapM (\_ -> async asyncAction) [0..(n-1)])+  where+    asyncAction = do+      threadDelay <$> randomDelay+      atomically $ freshId supply++-- random delay of 350 - 700ms+randomDelay :: IO Int+randomDelay = (fst . randomR (350000, 700000)) <$> newStdGen++-- a list of integers satisfies the test condition if there+-- are N distinct integers and they are sequential.+satisfy :: Positive Int -> [Int] -> Bool+satisfy (Positive n) ls = length ls == n && isSequence ls+  where+    isSequence []       = True+    isSequence [x]      = True+    isSequence l@(x:xs) = all (==1) $ zipWith (-) xs l++return []+runTests = $quickCheckAll++main :: IO ()+main = void runTests