@@ -38,6 +38,7 @@ module Control.Concurrent.STM.TQueue (
3838 newTQueue ,
3939 newTQueueIO ,
4040 readTQueue ,
41+ readTQueueN ,
4142 tryReadTQueue ,
4243 flushTQueue ,
4344 peekTQueue ,
@@ -103,6 +104,64 @@ readTQueue (TQueue read write) = do
103104 writeTVar read zs
104105 return z
105106
107+
108+ -- +-----------+--------------- +-----------------+
109+ -- | write = 0 | write < N-read | write >= N-read |
110+ -- +--------------+-----------+--------------- +-----------------+
111+ -- | read == 0 | retry | case 2 | case 3 |
112+ -- | 0 < read < N | retry | retry | case 4 |
113+ -- +--------------+-----------+--------------- +-----------------+
114+ -- | read >= N | . . . . . . . case 1 . . . . . . . . . |
115+ -- +----=--------------------------------------------------------+
116+
117+ -- case 1a: More than N: splitAt N read -> put suffix in read and return prefix
118+ -- case 1b: Exactly N: Reverse write into read, and return all of the old read
119+ -- case 2: Move reverse write to read, retry
120+ -- case 3: Reverse write -> splitAt N, put suffix in read and return prefix
121+ -- case 4: Like case 3 but prepend read onto return value
122+
123+ -- | Reads N values, blocking until enough are available
124+ readTQueueN :: Int -> TQueue a -> STM [a ]
125+ readTQueueN n (TQueue read write) = do
126+ xs <- readTVar read
127+ let xl = length xs
128+ if xl > n then do -- case 1a
129+ let (as,bs) = splitAt n xs
130+ writeTVar read bs
131+ pure as
132+ else if xl == n then do -- case 1b
133+ ys <- readTVar write
134+ case ys of
135+ [] -> do
136+ writeTVar read []
137+ retry
138+ _ -> do
139+ let zs = reverse ys
140+ writeTVar write []
141+ writeTVar read zs
142+ pure xs
143+ else do
144+ ys <- readTVar write
145+ let yl = length ys
146+ if yl == 0 then
147+ retry
148+ else if yl < n - xl then
149+ if xl == 0 then do -- case 2
150+ let zs = reverse ys
151+ writeTVar write []
152+ writeTVar read zs
153+ retry
154+ else
155+ retry
156+ else do -- cases 3 and 4
157+ let (as,bs) = splitAt (n- xl) (reverse ys)
158+ writeTVar read bs
159+ pure $ xs <> as
160+
161+
162+
163+
164+
106165-- | A version of 'readTQueue' which does not retry. Instead it
107166-- returns @Nothing@ if no value is available.
108167tryReadTQueue :: TQueue a -> STM (Maybe a )
0 commit comments