Skip to content

Commit 0bf070c

Browse files
committed
Adding Deques
1 parent ca6aeee commit 0bf070c

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed

linear-base.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ library
4040
Data.Bifunctor.Linear.Internal.Bifunctor
4141
Data.Bifunctor.Linear.Internal.SymmetricMonoidal
4242
Data.Bool.Linear
43+
Data.Deque.Mutable.Linear
4344
Data.Either.Linear
4445
Data.Functor.Linear
4546
Data.Functor.Linear.Internal.Functor

src/Data/Deque/Mutable/Linear.hs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
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+

src/Data/Unrestricted/Internal/Instances.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ instance Dupable (Ur a) where
196196
instance Movable (Ur a) where
197197
move (Ur a) = Ur (Ur a)
198198

199+
deriving instance Prelude.Show a => Prelude.Show (Ur a)
200+
199201
instance Prelude.Functor Ur where
200202
fmap f (Ur a) = Ur (f a)
201203

0 commit comments

Comments
 (0)