{-# OPTIONS_GHC -Wno-incomplete-patterns #-} {-# LANGUAGE DerivingStrategies, ViewPatterns #-} {-| Module : Parsley.Internal.Common.Queue.Impl Description : Implementation of a queue. License : BSD-3-Clause Maintainer : Jamie Willis Stability : experimental Implementation of a FIFO queue structure, with amortized operations. @since 1.5.0.0 -} module Parsley.Internal.Common.Queue.Impl ( module Parsley.Internal.Common.Queue.Impl ) where import Prelude hiding (null, foldr) import Data.List (foldl') import qualified Prelude (foldr) {-| Concrete FIFO Queue, with amortized constant operations. @since 1.5.0.0 -} data Queue a = Queue { outsz :: Int, outs :: [a], insz :: Int, ins :: [a] } deriving stock Eq {-| Construct an empty queue. @since 1.5.0.0 -} empty :: Queue a empty = Queue 0 [] 0 [] {-| Adds an element onto the end of the queue. @since 1.5.0.0 -} enqueue :: a -> Queue a -> Queue a enqueue x q = q {insz = insz q + 1, ins = x : ins q} {-| Adds each of the elements onto the queue, from left-to-right. @since 1.5.0.0 -} enqueueAll :: [a] -> Queue a -> Queue a enqueueAll xs q = q { insz = insz q + length xs, ins = foldl' (flip (:)) (ins q) xs } {-| Removes an element from the front of the queue. @since 1.5.0.0 -} dequeue :: Queue a -> (a, Queue a) dequeue q@(outs -> (x:outs')) = (x, q {outsz = outsz q - 1, outs = outs'}) dequeue q@(outs -> []) | insz q /= 0 = dequeue (Queue (insz q) (reverse (ins q)) 0 []) | otherwise = error "dequeue of empty queue" {-| Is the queue empty? @since 1.5.0.0 -} null :: Queue a -> Bool null (Queue 0 [] 0 []) = True null _ = False {-| Returns how many elements are in the queue. @since 1.5.0.0 -} size :: Queue a -> Int size q = insz q + outsz q {-| Folds the values in the queue. @since 1.5.0.0 -} foldr :: (a -> b -> b) -> b -> Queue a -> b foldr f k = Prelude.foldr f k . toList instance Show a => Show (Queue a) where show = show . toList {-| Converts this queue into a list. @since 1.5.0.0 -} toList :: Queue a -> [a] toList q = outs q ++ reverse (ins q)