content: module Network.Neks.DataStore (
          DataStore, createStore, dump, load, insert, get, delete
  ) where
  
  import qualified Data.Map.Strict as Map (Map, empty, insert, lookup, delete)
  import Control.Concurrent.STM (STM)
  import Control.Concurrent.STM.TMVar (TMVar, newTMVar, takeTMVar, putTMVar, readTMVar)
  import Data.Hashable (Hashable, hash)
  import Data.Vector as Vector (Vector, fromList, toList, mapM, (!))
  import Data.Bits ((.&.))
  
  newtype DataStore k v = DataStore {mapsOf :: Vector (TMVar (Map.Map k v))}
  
  createStore :: STM (DataStore k v)
  createStore = load [Map.empty | _ <- [0..4096]]
  
  insert :: (Hashable k, Ord k) => k -> v -> DataStore k v -> STM ()
  insert k v (DataStore maps) = do
          let atomicMap = maps ! (hash k .&. 0xFFF)
          map <- takeTMVar atomicMap
          putTMVar atomicMap $! Map.insert k v map
  
  get :: (Hashable k, Ord k) => k -> DataStore k v -> STM (Maybe v)
  get k (DataStore maps) = do
          let atomicMap = maps ! (hash k .&. 0xFFF)
          map <- readTMVar atomicMap
          return (Map.lookup k map)
  
  delete :: (Hashable k, Ord k) => k -> DataStore k v -> STM ()
  delete k (DataStore maps) = do
          let atomicMap = maps ! (hash k .&. 0xFFF)
          map <- takeTMVar atomicMap
          putTMVar atomicMap $! Map.delete k map
  
  dump :: DataStore k v -> STM [Map.Map k v]
  dump = Prelude.mapM readTMVar . toList . mapsOf
  
  load :: [Map.Map k v] -> STM (DataStore k v)
  load = fmap DataStore . Vector.mapM newTMVar . fromList