module Data.Registry.Class where

import Control.Monad
import Control.Monad.IO.Class
import Data.Maybe (isJust)
import qualified Data.Text as T
import qualified Data.Vector.Mutable as VM

-- | @IRegistry@ typeclass presents a registry interface.
-- The complexity /O(1)/ in the operations can be "amortized" complexity.
class IRegistry reg where
  -- | /O(1)/ Checking if the specified key exists
  has :: MonadIO m => reg v -> T.Text -> m Bool
  has reg :: reg v
reg k :: Text
k = (Maybe v -> Bool) -> m (Maybe v) -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe v -> Bool
forall a. Maybe a -> Bool
isJust (m (Maybe v) -> m Bool) -> m (Maybe v) -> m Bool
forall a b. (a -> b) -> a -> b
$ reg v
reg reg v -> Text -> m (Maybe v)
forall (reg :: * -> *) (m :: * -> *) v.
(IRegistry reg, MonadIO m) =>
reg v -> Text -> m (Maybe v)
!? Text
k

  -- | /O(1)/ Indexing
  (!) :: MonadIO m => reg v -> T.Text -> m v
  reg :: reg v
reg ! k :: Text
k = (Maybe v -> v) -> m (Maybe v) -> m v
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(Just a :: v
a) -> v
a) (m (Maybe v) -> m v) -> m (Maybe v) -> m v
forall a b. (a -> b) -> a -> b
$ reg v
reg reg v -> Text -> m (Maybe v)
forall (reg :: * -> *) (m :: * -> *) v.
(IRegistry reg, MonadIO m) =>
reg v -> Text -> m (Maybe v)
!? Text
k

  -- | /O(1)/ Safe indexing
  (!?) :: MonadIO m => reg v -> T.Text -> m (Maybe v)

  -- | /O(1)/ Update, raise an exception if the key does not exist.
  update :: MonadIO m => reg v -> T.Text -> (v -> m v) -> m ()
  update reg :: reg v
reg k :: Text
k f :: v -> m v
f = reg v
reg reg v -> Text -> m v
forall (reg :: * -> *) (m :: * -> *) v.
(IRegistry reg, MonadIO m) =>
reg v -> Text -> m v
! Text
k m v -> (v -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \v :: v
v -> v -> m v
f v
v m v -> (v -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \v' :: v
v' -> reg v -> Text -> v -> m ()
forall (reg :: * -> *) (m :: * -> *) v.
(IRegistry reg, MonadIO m) =>
reg v -> Text -> v -> m ()
write reg v
reg Text
k v
v'

  -- | /O(1)/ Write, raise an exception if the key does not exist.
  write :: MonadIO m => reg v -> T.Text -> v -> m ()

  -- | /O(1)/ Adding a new value to the last position
  register :: MonadIO m => reg v -> T.Text -> v -> m ()

  -- | /O(n)/ Inserting a new value to the specified position (in the underlying vector)
  insert :: MonadIO m => reg v -> Int -> T.Text -> v -> m ()

  -- | /O(n)/ Deleting the specified value (this is a slow operation).
  delete :: MonadIO m => reg v -> T.Text -> m ()

  -- | /O(1)/ Get the underlying vector. Be careful: modifying the vector might cause a problem.
  asVec :: reg v -> VM.IOVector v

infixl 9 !
infixl 9 !?

-- | For-loop over the registry, ignoring the key order.
forV_ :: (MonadIO m, IRegistry reg) => reg v -> (v -> m ()) -> m ()
forV_ :: reg v -> (v -> m ()) -> m ()
forV_ reg :: reg v
reg iter :: v -> m ()
iter =
  let vec :: IOVector v
vec = reg v -> IOVector v
forall (reg :: * -> *) v. IRegistry reg => reg v -> IOVector v
asVec reg v
reg
  in  [Int] -> (Int -> m ()) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [0 .. IOVector v -> Int
forall s a. MVector s a -> Int
VM.length IOVector v
vec Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1] ((Int -> m ()) -> m ()) -> (Int -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \i :: Int
i -> IO v -> m v
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (MVector (PrimState IO) v -> Int -> IO v
forall (m :: * -> *) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
VM.read IOVector v
MVector (PrimState IO) v
vec Int
i) m v -> (v -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= v -> m ()
iter

-- | For-loop over the registry with the index, ignoring the key order.
iforV_ :: (MonadIO m, IRegistry reg) => reg v -> (Int -> v -> m ()) -> m ()
iforV_ :: reg v -> (Int -> v -> m ()) -> m ()
iforV_ reg :: reg v
reg iter :: Int -> v -> m ()
iter =
  let vec :: IOVector v
vec = reg v -> IOVector v
forall (reg :: * -> *) v. IRegistry reg => reg v -> IOVector v
asVec reg v
reg
  in  [Int] -> (Int -> m ()) -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [0 .. IOVector v -> Int
forall s a. MVector s a -> Int
VM.length IOVector v
vec Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1] ((Int -> m ()) -> m ()) -> (Int -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \i :: Int
i -> IO v -> m v
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (MVector (PrimState IO) v -> Int -> IO v
forall (m :: * -> *) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
VM.read IOVector v
MVector (PrimState IO) v
vec Int
i) m v -> (v -> m ()) -> m ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> v -> m ()
iter Int
i

-- | Modifying the item one by one, ignoring the key order.
modifyV_ :: (MonadIO m, IRegistry reg) => reg v -> (v -> m v) -> m ()
modifyV_ :: reg v -> (v -> m v) -> m ()
modifyV_ reg :: reg v
reg iter :: v -> m v
iter = reg v -> (Int -> v -> m ()) -> m ()
forall (m :: * -> *) (reg :: * -> *) v.
(MonadIO m, IRegistry reg) =>
reg v -> (Int -> v -> m ()) -> m ()
iforV_ reg v
reg ((Int -> v -> m ()) -> m ()) -> (Int -> v -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \i :: Int
i v :: v
v -> do
  v
v' <- v -> m v
iter v
v
  IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVector (PrimState IO) v -> Int -> v -> IO ()
forall (m :: * -> *) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> a -> m ()
VM.write (reg v -> IOVector v
forall (reg :: * -> *) v. IRegistry reg => reg v -> IOVector v
asVec reg v
reg) Int
i v
v'