{-# language DeriveTraversable #-}
{-# language ScopedTypeVariables #-}
{-# language BangPatterns #-}
{-# language MagicHash #-}
{-# language UnboxedTuples #-}
{-# language PatternSynonyms #-}
{-# language ViewPatterns #-}
{-# language Trustworthy #-}
{-# language TypeFamilies #-}
{-# language FlexibleContexts #-}
module Data.CompactSequence.Queue.Simple.Internal
( Queue (.., Empty, (:<))
, (|>)
, empty
, snoc
, uncons
, take
, fromList
, fromListN
, fromListNIncremental
) where
import qualified Data.CompactSequence.Queue.Internal as Q
import Data.CompactSequence.Internal.Size (Size, Twice)
import qualified Data.CompactSequence.Internal.Size as Sz
import qualified Data.CompactSequence.Internal.Array as A
import qualified Data.CompactSequence.Internal.Numbers as N
import qualified Data.Foldable as F
import qualified GHC.Exts as Exts
import Control.Monad.State.Strict
import qualified Control.Monad.State.Lazy as LS
import qualified Prelude as P
import Prelude hiding (take)
newtype Queue a = Queue (Q.Queue Sz.Sz1 a)
deriving (Functor, Traversable, Eq, Ord)
empty :: Queue a
empty = Queue Q.empty
snoc :: Queue a -> a -> Queue a
snoc (Queue q) a = Queue $ Q.snocA Sz.one q (A.singleton a)
(|>) :: Queue a -> a -> Queue a
(|>) = snoc
uncons :: Queue a -> Maybe (a, Queue a)
uncons (Queue q) = case Q.viewA Sz.one q of
Q.EmptyA -> Nothing
Q.ConsA sa q'
| (# a #) <- A.getSingleton# sa
-> Just (a, Queue q')
infixr 5 :<
infixl 4 `snoc`, |>
pattern (:<) :: a -> Queue a -> Queue a
pattern x :< xs <- (uncons -> Just (x, xs))
pattern Empty :: Queue a
pattern Empty = Queue Q.Empty
{-# COMPLETE (:<), Empty #-}
instance Foldable Queue where
foldMap f (Queue q) = foldMap f q
foldr c n (Queue q) = foldr c n q
foldr' c n (Queue q) = F.foldr' c n q
foldl f b (Queue q) = foldl f b q
foldl' f b (Queue q) = F.foldl' f b q
null (Queue Q.Empty) = True
null _ = False
length (Queue q) = go 0 Sz.one q
where
go :: Int -> Size m -> Q.Queue m a -> Int
go !acc !_s Q.Empty = acc
go !acc !s (Q.Node pr m sf) = go (acc + lpr + lsf) (Sz.twice s) m
where
lpr = case pr of
Q.FD1{} -> Sz.getSize s
Q.FD2{} -> 2*Sz.getSize s
Q.FD3{} -> 3*Sz.getSize s
lsf = case sf of
Q.RD0 -> 0
Q.RD1{} -> Sz.getSize s
Q.RD2{} -> 2*Sz.getSize s
instance Show a => Show (Queue a) where
showsPrec p xs = showParen (p > 10) $
showString "fromList " . shows (F.toList xs)
instance Exts.IsList (Queue a) where
type Item (Queue a) = a
toList = F.toList
fromList = fromList
fromListN = fromListN
instance Semigroup (Queue a) where
Empty <> q = q
q <> Empty = q
q <> r = fromListN (length q + length r) (F.toList q ++ F.toList r)
instance Monoid (Queue a) where
mempty = empty
take :: Int -> Queue a -> Queue a
take n s
| n <= 0 = Empty
| compareLength n s == LT
= fromListN n (P.take n (F.toList s))
| otherwise = s
compareLength :: Int -> Queue a -> Ordering
compareLength n0 (Queue que0) = go Sz.one n0 que0
where
go :: Size n -> Int -> Q.Queue n a -> Ordering
go !_sz n Q.Empty = compare n 0
go _sz n _ | n <= 0 = LT
go sz n (Q.Node pr m sf)
= go (Sz.twice sz) (n - frontLen sz pr - rearLen sz sf) m
frontLen :: Size n -> Q.FD n a -> Int
frontLen s Q.FD1{} = Sz.getSize s
frontLen s Q.FD2{} = 2 * Sz.getSize s
frontLen s Q.FD3{} = 3 * Sz.getSize s
rearLen :: Size n -> Q.RD n a -> Int
rearLen s Q.RD0{} = 0
rearLen s Q.RD1{} = Sz.getSize s
rearLen s Q.RD2{} = 2 * Sz.getSize s
fromList :: [a] -> Queue a
fromList = F.foldl' snoc empty
fromListN :: Int -> [a] -> Queue a
fromListN n xs
= Queue $ evalState (fromListQN Sz.one (N.toBin23 n)) xs
fromListNIncremental :: Int -> [a] -> Queue a
fromListNIncremental n xs
= Queue $ LS.evalState (fromListQN Sz.one (N.toBin23 n)) xs
{-# SPECIALIZE
fromListQN :: Size n -> N.Bin23 -> State [a] (Q.Queue n a)
#-}
{-# SPECIALIZE
fromListQN :: Size n -> N.Bin23 -> LS.State [a] (Q.Queue n a)
#-}
fromListQN :: MonadState [a] m => Size n -> N.Bin23 -> m (Q.Queue n a)
fromListQN !_ N.End23 = do
remains <- get
if null remains
then pure Q.empty
else error "Data.CompactSequence.Queue.Simple.fromListQN: List too long"
fromListQN !sz N.OneEnd23 = do
sa <- state (A.arraySplitListN sz)
remains <- get
if null remains
then pure $! Q.Node (Q.FD1 sa) Q.Empty Q.RD0
else error "Data.CompactSequence.Queue.Simple.fromListQN: List too long"
fromListQN !sz (N.Two23 mn) = do
sa1 <- state (A.arraySplitListN sz)
sa2 <- state (A.arraySplitListN sz)
m <- fromListQN (Sz.twice sz) mn
pure $! Q.Node (Q.FD2 sa1 sa2) m Q.RD0
fromListQN !sz (N.Three23 mn) = do
sa1 <- state (A.arraySplitListN sz)
sa2 <- state (A.arraySplitListN sz)
sa3 <- state (A.arraySplitListN sz)
m <- fromListQN (Sz.twice sz) mn
pure $! Q.Node (Q.FD3 sa1 sa2 sa3) m Q.RD0