-- Copyright (c) 2016, Emil Axelsson, Peter Jonsson, Anders Persson and -- Josef Svenningsson -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- -- * Redistributions of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- * Neither the name of the ERICSSON AB nor the names of its contributors -- may be used to endorse or promote products derived from this software -- without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- | Indexable FIFO queues module Feldspar.Data.Queue ( Queue (..) , initQueueFromBuffer , initQueue , newQueue , initQueueFromBuffer2 , initQueue2 , newQueue2 ) where import Prelude () import Feldspar import Feldspar.Data.Vector -- | Indexable FIFO queue data Queue a = Queue { indexQ :: forall m . MonadComp m => Data Index -> m a , putQ :: forall m . MonadComp m => a -> m () , withQ :: forall m b . (Syntax b, MonadComp m) => (Pull a -> m b) -> m b } -- Another option would be to represent a queue as its state (the counter and -- the array), but the above representation leaves room for other -- implementations. -- | Create a new cyclic queue using an existing array as buffer. The length of -- the array determines the queue size. initQueueFromBuffer :: forall m a . (Syntax a, MonadComp m) => Arr a -> m (Queue a) initQueueFromBuffer buf = do ir <- initRef 0 let indexQ :: forall m2 . MonadComp m2 => Data Index -> m2 a indexQ j = do i <- unsafeFreezeRef ir getArr buf $ calcIndex i j putQ :: forall m2 . MonadComp m2 => a -> m2 () putQ a = do i <- unsafeFreezeRef ir setArr buf i a setRef ir ((i+1) `mod` len) withQ :: forall m2 b . (Syntax b, MonadComp m2) => (Pull a -> m2 b) -> m2 b withQ f = do i <- unsafeFreezeRef ir vec <- unsafeFreezeArr buf f $ backPermute (\_ -> calcIndex i) vec return Queue {..} where len = length buf calcIndex i j = (len+i-j-1) `mod` len -- | Create a new cyclic queue initialized by the given vector (which also -- determines the size) initQueue :: (Manifestable m vec a, Finite vec, Syntax a, MonadComp m) => vec -- ^ Initial content (also determines the queue size) -> m (Queue a) initQueue init = do buf <- newArr $ length init manifestStore buf init initQueueFromBuffer buf -- | Create a new cyclic queue of the given length without initialization newQueue :: (Syntax a, MonadComp m) => Data Length -> m (Queue a) newQueue l = newArr l >>= initQueueFromBuffer initQueueFromBuffer2 :: forall m a . (Syntax a, MonadComp m) => Data Length -- ^ Queue size, must be <= half the buffer size -> Arr a -- ^ Buffer -> m (Queue a) initQueueFromBuffer2 len buf = do ir <- initRef 0 let indexQ :: forall m2 . MonadComp m2 => Data Index -> m2 a indexQ j = do i <- unsafeFreezeRef ir getArr buf (len+i-j-1) putQ :: forall m2 . MonadComp m2 => a -> m2 () putQ a = do i <- unsafeFreezeRef ir setArr buf i a setArr buf (i+len) a setRef ir ((i+1) `mod` len) withQ :: forall m2 b . (Syntax b, MonadComp m2) => (Pull a -> m2 b) -> m2 b withQ f = do i <- unsafeFreezeRef ir vec <- unsafeFreezeArr buf f $ reverse $ take len $ drop i vec return Queue {..} -- | Create a new cyclic queue. This implementation uses a buffer twice as long -- as the queue size to avoid modulus operations when accessing the elements. initQueue2 :: (Pushy m vec a, Finite vec, Syntax a, MonadComp m) => vec -- ^ Initial content (also determines the queue size) -> m (Queue a) initQueue2 init = do buf <- newArr (2*len) manifestStore buf (init++init) initQueueFromBuffer2 len buf where len = length init -- | Create a new cyclic queue. This implementation uses a buffer twice as long -- as the queue size to avoid modulus operations when accessing the elements. newQueue2 :: (Syntax a, MonadComp m) => Data Length -- ^ Queue size -> m (Queue a) newQueue2 l = do buf <- newArr (2*l) initQueueFromBuffer2 l buf