git-annex/Utility/TList.hs

104 lines
2.5 KiB
Haskell
Raw Normal View History

2013-04-24 20:01:01 +00:00
{- Transactional lists
-
- Based on DLists, a transactional list can quickly and efficiently
- have items inserted at either end, or a whole list appended to it.
-
2014-01-07 21:33:38 +00:00
- Unlike a TQueue, the entire contents of a TList can be efficiently
- read without modifying it.
-
- Copyright 2013-2020 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
2013-04-24 20:01:01 +00:00
-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
2013-04-24 20:01:01 +00:00
module Utility.TList (
TList,
newTList,
getTList,
setTList,
takeTList,
readTList,
consTList,
snocTList,
appendTList,
headTList,
) where
2013-04-24 20:01:01 +00:00
import Common
import Control.Concurrent.STM
import qualified Data.DList as D
type TList a = TMVar (D.DList a)
newTList :: STM (TList a)
newTList = newEmptyTMVar
2020-07-10 16:59:41 +00:00
{- Takes the head of the TList, leaving the rest.
- Blocks when empty.
-
- O(n) due to use of D.tail
-}
headTList :: TList a -> STM a
headTList tlist = do
dl <- takeTMVar tlist
#if MIN_VERSION_dlist(1,0,0)
let !dl' = D.fromList $ D.tail dl
#else
2020-07-10 16:59:41 +00:00
let !dl' = D.tail dl
#endif
2020-07-10 16:59:41 +00:00
unless (emptyDList dl') $
putTMVar tlist dl'
return (D.head dl)
2013-04-24 20:01:01 +00:00
{- Gets the contents of the TList. Blocks when empty.
- TList is left empty. -}
getTList :: TList a -> STM [a]
getTList tlist = D.toList <$> getTDList tlist
getTDList :: TList a -> STM (D.DList a)
getTDList = takeTMVar
{- Replaces the contents of the TList. -}
setTList :: TList a -> [a] -> STM ()
setTList tlist = setTDList tlist . D.fromList
setTDList :: TList a -> D.DList a -> STM ()
setTDList tlist = modifyTList tlist . const
2013-04-24 20:01:01 +00:00
{- Takes anything currently in the TList, without blocking.
2013-04-24 20:01:01 +00:00
- TList is left empty. -}
takeTList :: TList a -> STM [a]
takeTList tlist = maybe [] D.toList <$> tryTakeTMVar tlist
{- Reads anything in the list, without modifying it, or blocking. -}
2013-04-24 20:01:01 +00:00
readTList :: TList a -> STM [a]
readTList tlist = maybe [] D.toList <$> tryReadTMVar tlist
2013-04-24 20:01:01 +00:00
2020-07-10 16:59:41 +00:00
{- Mutates a TList.
-
- O(n) due to the use of emptyDList -}
2013-04-24 20:01:01 +00:00
modifyTList :: TList a -> (D.DList a -> D.DList a) -> STM ()
modifyTList tlist a = do
dl <- fromMaybe D.empty <$> tryTakeTMVar tlist
let !dl' = a dl
{- The TMVar is left empty when the list is empty.
- Thus attempts to read it automatically block. -}
unless (emptyDList dl') $
putTMVar tlist dl'
2020-07-10 16:59:41 +00:00
emptyDList :: D.DList a -> Bool
emptyDList = null . D.toList
2013-04-24 20:01:01 +00:00
consTList :: TList a -> a -> STM ()
consTList tlist v = modifyTList tlist $ \dl -> D.cons v dl
snocTList :: TList a -> a -> STM ()
snocTList tlist v = modifyTList tlist $ \dl -> D.snoc dl v
appendTList :: TList a -> [a] -> STM ()
appendTList tlist l = modifyTList tlist $ \dl -> D.append dl (D.fromList l)