|  | 
|  | 1 | +{-# LANGUAGE BangPatterns #-} | 
|  | 2 | +{-# LANGUAGE LinearTypes #-} | 
|  | 3 | +{-# LANGUAGE LambdaCase #-} | 
|  | 4 | +{-# LANGUAGE GADTs #-} | 
|  | 5 | +{-# LANGUAGE GeneralizedNewtypeDeriving #-} | 
|  | 6 | +{-# LANGUAGE NoImplicitPrelude #-} | 
|  | 7 | + | 
|  | 8 | +-- | Mutable Linear Deque | 
|  | 9 | +-- | 
|  | 10 | +-- This module provides a pure interface to a mutable deque. | 
|  | 11 | +-- | 
|  | 12 | +-- It is designed to be imported qualfied: | 
|  | 13 | +-- | 
|  | 14 | +-- > import qualfied Data.Deque.Mutable.Linear as Deque | 
|  | 15 | +module Data.Deque.Mutable.Linear | 
|  | 16 | +  ( | 
|  | 17 | +  -- * Allocation | 
|  | 18 | +    Deque | 
|  | 19 | +  , alloc | 
|  | 20 | +  , fromList | 
|  | 21 | +  -- * Querying | 
|  | 22 | +  , size | 
|  | 23 | +  , length | 
|  | 24 | +  , isFull | 
|  | 25 | +  , peekFront | 
|  | 26 | +  , peekBack | 
|  | 27 | +  -- * Modification | 
|  | 28 | +  , pushFront | 
|  | 29 | +  , pushBack | 
|  | 30 | +  , popFront | 
|  | 31 | +  , popBack | 
|  | 32 | +  , map | 
|  | 33 | +  -- * Consumption | 
|  | 34 | +  , toList | 
|  | 35 | +  ) | 
|  | 36 | +where | 
|  | 37 | + | 
|  | 38 | +import qualified Data.Array.Mutable.Linear as Array | 
|  | 39 | +import Data.Unrestricted.Linear | 
|  | 40 | +import Prelude.Linear hiding (length, map) | 
|  | 41 | +import qualified Prelude | 
|  | 42 | +import GHC.Stack | 
|  | 43 | + | 
|  | 44 | + | 
|  | 45 | +-- # Types | 
|  | 46 | +------------------------------------------------------------------------------- | 
|  | 47 | + | 
|  | 48 | +data Deque a where | 
|  | 49 | +  Deque :: !Int -> !Ptr -> !(Array.Array a) %1-> Deque a | 
|  | 50 | +  -- This is: Deque length ptr array | 
|  | 51 | +  -- | 
|  | 52 | +  -- The length is the number of elements stored. | 
|  | 53 | +  -- The ptr is the starting pointer to the front end, and the deque | 
|  | 54 | +  -- continues forward, wrapping the end if needed. Example: | 
|  | 55 | +  -- | 
|  | 56 | +  -- [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | 
|  | 57 | +  --  ....^                 ^.......... | 
|  | 58 | +  --      |                 | | 
|  | 59 | +  --   ptr+len             ptr | 
|  | 60 | +  -- | 
|  | 61 | +  -- | 
|  | 62 | +  -- So the deque is: 7--8--9--10--0--1 | 
|  | 63 | + | 
|  | 64 | +newtype Ptr = Ptr Int deriving Prelude.Num | 
|  | 65 | + | 
|  | 66 | +-- | The two faces of a deque | 
|  | 67 | +data Face = Front | Back | 
|  | 68 | + | 
|  | 69 | + | 
|  | 70 | +-- # Internal Helpers | 
|  | 71 | +------------------------------------------------------------------------------- | 
|  | 72 | + | 
|  | 73 | +-- @backPtr offset len size ptr = ptr'@ where @ptr'@ is the pointer | 
|  | 74 | +-- to the back of the deque + the offset | 
|  | 75 | +-- Must have: len >= 1 | 
|  | 76 | +backPtr :: Int -> Int -> Int -> Ptr -> Int | 
|  | 77 | +backPtr off len sz (Ptr p) = (off + p + len - 1) `mod` sz | 
|  | 78 | + | 
|  | 79 | +-- @prevPtr size ptr@ will be the previous pointer | 
|  | 80 | +prevPtr :: Int -> Ptr -> Int | 
|  | 81 | +prevPtr sz (Ptr p) = (p - 1 + sz) `mod` sz | 
|  | 82 | + | 
|  | 83 | +-- @nextPtr size ptr@ will be the next pointer | 
|  | 84 | +nextPtr :: Int -> Ptr -> Int | 
|  | 85 | +nextPtr sz (Ptr p) = (p + 1) `mod` sz | 
|  | 86 | + | 
|  | 87 | + | 
|  | 88 | +-- # Allocation | 
|  | 89 | +------------------------------------------------------------------------------- | 
|  | 90 | + | 
|  | 91 | +-- | Run a computation of an empty Deque with a given size | 
|  | 92 | +alloc :: HasCallStack => Int -> (Deque a %1-> Ur b) %1-> Ur b | 
|  | 93 | +alloc k f = Array.alloc k err $ \arr -> f (Deque 0 0 arr) where | 
|  | 94 | +  err = Prelude.error "Accessing error element of a collection!" | 
|  | 95 | + | 
|  | 96 | +-- | Run a computation on a Deque that is deterimined by the given the list | 
|  | 97 | +-- where we treat the start and end of the list as the left and right pointers, | 
|  | 98 | +-- with the total capacity as the length of the list. | 
|  | 99 | +fromList :: HasCallStack => [a] -> (Deque a %1-> Ur b) %1-> Ur b | 
|  | 100 | +fromList xs f = | 
|  | 101 | +  Array.fromList xs $ \arr -> f (Deque (Prelude.length xs) 0 arr) | 
|  | 102 | + | 
|  | 103 | + | 
|  | 104 | +-- # Querying | 
|  | 105 | +------------------------------------------------------------------------------- | 
|  | 106 | + | 
|  | 107 | +-- | The total capacity of the Deque | 
|  | 108 | +size :: Deque a %1-> (Ur Int, Deque a) | 
|  | 109 | +size (Deque len ptr arr) = Array.size arr & | 
|  | 110 | +  \(sz, arr0) -> (sz, Deque len ptr arr0) | 
|  | 111 | + | 
|  | 112 | +-- | The number of elements currently stored | 
|  | 113 | +length :: Deque a %1-> (Ur Int, Deque a) | 
|  | 114 | +length (Deque len ptr arr) = (Ur len, Deque len ptr arr) | 
|  | 115 | + | 
|  | 116 | +-- | We are full if the length equals the size | 
|  | 117 | +isFull :: Deque a %1-> (Ur Bool, Deque a) | 
|  | 118 | +isFull d = | 
|  | 119 | +  size d & \(Ur sz, Deque len ptr arr) -> (Ur (len == sz), Deque len ptr arr) | 
|  | 120 | + | 
|  | 121 | +peek :: HasCallStack => Face -> Deque a %1-> (Ur a, Deque a) | 
|  | 122 | +peek _ (Deque 0 _ arr) = error "Peeking a zero-length deque." $ arr | 
|  | 123 | +peek face (Deque len ptr@(Ptr p) arr) = case face of | 
|  | 124 | +  Front -> Array.read arr p & \(val, arr0) -> (val, Deque len ptr arr0) | 
|  | 125 | +  Back -> Array.size arr & \(Ur sz, arr0) -> | 
|  | 126 | +    Array.read arr0 (backPtr 0 len sz ptr) & \(val, arr1) -> | 
|  | 127 | +      (val, Deque len ptr arr1) | 
|  | 128 | + | 
|  | 129 | +-- | View the top of the left queue | 
|  | 130 | +peekFront :: HasCallStack => Deque a %1-> (Ur a, Deque a) | 
|  | 131 | +peekFront = peek Front | 
|  | 132 | + | 
|  | 133 | +-- | View the top of the right queue | 
|  | 134 | +peekBack :: HasCallStack => Deque a %1-> (Ur a, Deque a) | 
|  | 135 | +peekBack = peek Back | 
|  | 136 | + | 
|  | 137 | + | 
|  | 138 | +-- # Modification | 
|  | 139 | +------------------------------------------------------------------------------- | 
|  | 140 | + | 
|  | 141 | +push :: HasCallStack => Face -> a -> Deque a %1-> Deque a | 
|  | 142 | +push face x deq = isFull deq & \case | 
|  | 143 | +  (Ur True, deq0) -> error "Pushing to full deque" $ deq0 | 
|  | 144 | +  (Ur False, Deque 0 _ arr) -> Array.write arr 0 x & \arr0 -> Deque 1 0 arr0 | 
|  | 145 | +  (Ur False, Deque len (Ptr p) arr) -> case face of | 
|  | 146 | +    Front -> Array.size arr & \(Ur sz, arr0) -> | 
|  | 147 | +      Array.write arr0 (prevPtr sz (Ptr p)) x & \arr1 -> | 
|  | 148 | +        Deque (len+1) (Ptr $ prevPtr sz (Ptr p)) arr1 | 
|  | 149 | +    Back -> Array.size arr & \(Ur sz, arr0) -> | 
|  | 150 | +      Array.write arr0 (backPtr 1 len sz (Ptr p)) x & \arr1 -> | 
|  | 151 | +        Deque (len+1) (Ptr p) arr1 | 
|  | 152 | + | 
|  | 153 | +-- | Push to the front end | 
|  | 154 | +pushFront :: HasCallStack => a -> Deque a %1-> Deque a | 
|  | 155 | +pushFront = push Front | 
|  | 156 | + | 
|  | 157 | +-- | Push to the back end | 
|  | 158 | +pushBack :: HasCallStack => a -> Deque a %1-> Deque a | 
|  | 159 | +pushBack = push Back | 
|  | 160 | + | 
|  | 161 | +pop :: HasCallStack => Face -> Deque a %1-> (Ur a, Deque a) | 
|  | 162 | +pop _ (Deque 0 _ arr) = error "Popping from an empty deque" $ arr | 
|  | 163 | +pop face (Deque len ptr@(Ptr p) arr) = case face of | 
|  | 164 | +  Front -> Array.size arr & \(Ur sz, arr0) -> | 
|  | 165 | +    Array.read arr0 p & \(val, arr1) -> | 
|  | 166 | +      (val, Deque (len-1) (Ptr $ nextPtr sz ptr) arr1) | 
|  | 167 | +  Back -> Array.size arr & \(Ur sz, arr0) -> | 
|  | 168 | +    Array.read arr0 (backPtr 0 len sz ptr) & \(val, arr1) -> | 
|  | 169 | +      (val, Deque (len-1) ptr arr1) | 
|  | 170 | + | 
|  | 171 | +-- | Remove the last added element from the left queue | 
|  | 172 | +popFront :: HasCallStack => Deque a %1-> (Ur a, Deque a) | 
|  | 173 | +popFront = pop Front | 
|  | 174 | + | 
|  | 175 | +-- | Remove the last added element from the right queue | 
|  | 176 | +popBack :: HasCallStack => Deque a %1-> (Ur a, Deque a) | 
|  | 177 | +popBack = pop Back | 
|  | 178 | + | 
|  | 179 | +-- Note: We can't use a Prelude.Functor nor a Data.Functor | 
|  | 180 | +-- because the mapped function need not be linear but we must | 
|  | 181 | +-- consume the Deque linearly. The types don't align. | 
|  | 182 | +map :: (a -> b) -> Deque a %1-> Deque b | 
|  | 183 | +map f (Deque len p arr) = Deque len p (Array.map f arr) | 
|  | 184 | + | 
|  | 185 | + | 
|  | 186 | +-- # Consumption | 
|  | 187 | +------------------------------------------------------------------------------- | 
|  | 188 | + | 
|  | 189 | +-- | Convert the Deque to a list where the first element is the left | 
|  | 190 | +-- top and the last element is the right top | 
|  | 191 | +toList :: Deque a %1-> Ur [a] | 
|  | 192 | +toList (Deque len (Ptr p) arr) = Array.size arr & \(Ur sz, arr0) -> | 
|  | 193 | +  loop len (backPtr 0 len sz (Ptr p)) [] arr0 | 
|  | 194 | +  where | 
|  | 195 | +    loop :: Int -> Int -> [a] -> Array.Array a %1-> Ur [a] | 
|  | 196 | +    loop 0 _ xs arr' = lseq arr' (Ur xs) | 
|  | 197 | +    loop l ptr xs arr' = Array.read arr' ptr & \(Ur a, arr0) -> | 
|  | 198 | +      Array.size arr0 & \(Ur sz, arr1) -> | 
|  | 199 | +        loop (l-1) (prevPtr sz (Ptr ptr)) (a:xs) arr1 | 
|  | 200 | + | 
|  | 201 | +instance Consumable (Deque a) where | 
|  | 202 | +  consume (Deque _ _ arr) = consume arr | 
|  | 203 | + | 
0 commit comments