grapesy-1.0.0: kvstore/KVStore/Util/RandomAccessSet.hs
-- | A set which supports random access.
--
-- Intended for qualified import.
--
-- > import KVStore.Util.RandomAccessSet (RandomAccessSet)
-- > import KVStore.Util.RandomAccessSet qualified as RandomAccessSet
module KVStore.Util.RandomAccessSet (
RandomAccessSet -- opaque
-- * API
, new
, isEmpty
, getRandomKey
, add
, remove
) where
import Control.Concurrent
import Data.Set (Set)
import Data.Set qualified as Set
import KVStore.Util.RandomGen qualified as Random
{-------------------------------------------------------------------------------
Definition
-------------------------------------------------------------------------------}
newtype RandomAccessSet a = Wrap {
unwrap :: MVar (Set a)
}
{-------------------------------------------------------------------------------
API
-------------------------------------------------------------------------------}
new :: IO (RandomAccessSet a)
new = Wrap <$> newMVar Set.empty
isEmpty :: RandomAccessSet a -> IO Bool
isEmpty ras = withRAS ras $ Set.null
getRandomKey :: RandomAccessSet a -> IO a
getRandomKey ras = do
gen <- Random.new
withRASIO ras $ \s -> do
n <- Random.nextInt gen (Set.size s)
return $ Set.elemAt n s
add :: Ord a => RandomAccessSet a -> a -> IO Bool
add ras value =
modifyRAS ras $ \set ->
if value `Set.member` set
then (set, False)
else (Set.insert value set, True)
remove :: Ord a => RandomAccessSet a -> a -> IO ()
remove ras value = modifyRAS_ ras $ Set.delete value
{-------------------------------------------------------------------------------
Internal: wrap pure operations
-------------------------------------------------------------------------------}
withRAS :: RandomAccessSet a -> (Set a -> b) -> IO b
withRAS ras f = withMVar (unwrap ras) $ return . f
modifyRAS :: RandomAccessSet a -> (Set a -> (Set a, b)) -> IO b
modifyRAS ras f = modifyMVar (unwrap ras) $ return . f
modifyRAS_ :: RandomAccessSet a -> (Set a -> Set a) -> IO ()
modifyRAS_ ras f = modifyMVar_ (unwrap ras) $ return . f
{-------------------------------------------------------------------------------
Internal: wrap IO operations
-------------------------------------------------------------------------------}
withRASIO :: RandomAccessSet a -> (Set a -> IO b) -> IO b
withRASIO ras = withMVar (unwrap ras)