module Utilities (
IndexedMVar()
, newIndexedMVar, putMVarIx, readMVarIx
, nextHighestPowerOfTwo
) where
import Control.Concurrent.MVar
import Control.Exception
import Control.Applicative
import Data.Bits
import Data.Word
import Data.Atomics
import Data.IORef
newtype IndexedMVar a = IndexedMVar (IORef [(Int, MVar a)])
newIndexedMVar :: IO (IndexedMVar a)
newIndexedMVar = IndexedMVar <$> newIORef []
readMVarIx :: IndexedMVar a -> Int -> IO a
readMVarIx mvIx i = do
readMVar =<< getMVarIx mvIx i
putMVarIx :: IndexedMVar a -> Int -> a -> IO ()
putMVarIx mvIx i a = do
flip putMVar a =<< getMVarIx mvIx i
getMVarIx :: IndexedMVar a -> Int -> IO (MVar a)
getMVarIx (IndexedMVar v) i = do
mv <- newEmptyMVar
tk0 <- readForCAS v
let go tk = do
let !xs = peekTicket tk
case findInsert i mv xs of
Left alreadyPresentMVar -> return alreadyPresentMVar
Right xs' -> do
(success,newTk) <- casIORef v tk xs'
if success
then return mv
else go newTk
go tk0
findInsert :: Int -> mvar -> [(Int,mvar)] -> Either mvar [(Int,mvar)]
findInsert i mv = ins where
ins [] = Right [(i,mv)]
ins xss@((i',x):xs) =
case compare i i' of
GT -> Right $ (i,mv):xss
EQ -> Left x
LT -> fmap ((i',x):) $ ins xs
nextHighestPowerOfTwo :: Int -> Int
nextHighestPowerOfTwo 0 = 1
nextHighestPowerOfTwo n =
let !nhp2 = 2 ^ (ceiling (logBase 2 $ fromIntegral $ abs n :: Float) :: Int)
in assert (nhp2 > 0 && popCount (fromIntegral nhp2 :: Word) == 1)
nhp2