module Data.RoundRobin ( RoundRobin , newRoundRobin , select , set ) where import Data.IORef import Data.List.NonEmpty (NonEmpty(..)) -- | A simple round-robin table -- useful for selecting resource using round-robin fashion. newtype RoundRobin a = RoundRobin (IORef [a]) deriving Eq -- | create a round-robin table from list. -- -- If list is empty, an error will be raised. -- will use 'NonEmpty' in future(ghc 8 are widely used). newRoundRobin :: NonEmpty a -> IO (RoundRobin a) newRoundRobin (x :| xs) = newIORef (cycle (x:xs)) >>= return . RoundRobin -- | select an item from round-robin table. select :: RoundRobin a -> IO a select (RoundRobin ref) = atomicModifyIORef' ref (\ (a:as) -> (as, a)) -- | set a new round-robin table. set :: RoundRobin a -> NonEmpty a -> IO () set (RoundRobin ref) (x :| xs) = atomicModifyIORef' ref (const (cycle (x:xs) , ()))