packages feed

pec-0.2.0: lib/Data/Deque.pec

module Data.Deque

exports
  Deque
  any
  del_back
  deque
  empty
  filter
  find
  find_idx
  fold
  foreach
  foreach_idx
  is_empty
  is_full
  map
  pop_back
  pop_front
  push_back
  push_front
  put

imports
  Prelude
  Data.Array as A

where

type Deque cnt a =
  { back :: Idx #cnt
  , height :: W32
  , data :: Array #cnt a
  }

filter :: (a -> Bool) -> Ptr (Deque #cnt a) -> ()
filter f p => do
  h = @p.height
  empty p
  unsafe_foreach_idx (back p) h (filter_elem f p)

filter_elem :: (a -> Bool) -> Ptr (Deque #cnt a) -> Idx #cnt -> ()
filter_elem f p i => do
  a = @p.data[i]
  when (f a) (assert (push_front a p))

any :: { Load p } => (a -> Bool) -> Pointer p (Deque #cnt a) -> Bool
any f p => case new (find_idx f p) of
  Nothing -> False
  Just _ -> True

find :: { Load p } =>
  (a -> Bool) -> Pointer p (Deque #cnt a) -> Maybe (Pointer p a)
find f p => case new (find_idx f p) of
  Nothing -> Nothing
  Just i -> Just p.data[@i]

find_idx :: { Load p } =>
  (a -> Bool) -> Pointer p (Deque #cnt a) -> Maybe (Idx #cnt)
find_idx f p => unsafe_find_idx (back p) @p.height f p.data

unsafe_find_idx :: { Load p } =>
  Idx #cnt -> W32 -> (a -> Bool) -> Pointer p (Array #cnt a) ->
  Maybe (Idx #cnt)
unsafe_find_idx b j f p => do
  i = new (0 :: W32)
  while ((@i < j) && (not (f @p[wrap_add b @i]))) (inc i)
  branch
    @i == j -> Nothing
    | Just (unsafe_to_idx @i)

map :: (a -> b) -> Ptr (Deque #cnt a) -> Deque #cnt b
map f p => do
  q = unsafe_alloca
  foreach_idx (A.map_idx f p.data q.data) p
  q.height <- @p.height
  q.back <- @p.back
  load q

foreach :: { Load p } =>
  (Pointer p a -> ()) -> Pointer p (Deque #cnt a) -> ()
foreach f p => foreach_idx (A.apply_at_idx f p.data) p

foreach_idx :: { Load p } =>
  (Idx #cnt -> ()) -> Pointer p (Deque #cnt a) -> ()
foreach_idx f p => unsafe_foreach_idx (back p) @p.height f

unsafe_foreach_idx :: Idx #cnt -> W32 -> (Idx #cnt -> ()) -> ()
unsafe_foreach_idx b h f => times h (\i -> f (wrap_add b i))

deque :: #cnt -> Deque #cnt a
deque _ => do
  p = unsafe_alloca
  p.back <- 0
  empty p
  load p

empty :: Ptr (Deque #cnt a) -> ()
empty p => p.height <- 0

push_front :: a -> Ptr (Deque #cnt a) -> Bool
push_front a p => branch
  is_full p -> False
  | do
      p.data[front p] <- a
      inc p.height
      True

pop_front :: Ptr (Deque #cnt a) -> Maybe a
pop_front p => branch
  is_empty p -> Nothing
  | do
      dec p.height
      Just @p.data[front p]

push_back :: a -> Ptr (Deque #cnt a) -> Bool
push_back a p => branch
  is_full p -> False
  | do
      p.data[@p.back] <- a
      p.back <- wrap_dec @p.back
      inc p.height
      True

pop_back :: Ptr (Deque #cnt a) -> Maybe a
pop_back p => branch
  del_back p -> Just @p.data[@p.back]
  | Nothing

del_back :: Ptr (Deque #cnt a) -> Bool
del_back p => branch
  is_empty p -> False
  | do
      p.back <- wrap_add @p.back 1
      dec p.height
      True

is_empty :: { Load p } => Pointer p (Deque #cnt a) -> Bool
is_empty p => @p.height == 0

is_full :: { Load p } => Pointer p (Deque #cnt a) -> Bool
is_full p => @p.height == count p.data

front :: { Load p } => Pointer p (Deque #cnt a) -> Idx #cnt
front p => wrap_add (back p) @p.height

back :: { Load p } => Pointer p (Deque #cnt a) -> Idx #cnt
back p => wrap_add @p.back 1

wrap_op :: (W32 -> W32) -> Idx #cnt -> Idx #cnt
wrap_op f a => unsafe_to_idx ((f (from_idx a)) % (count_idx a))

wrap_add :: Idx #cnt -> W32 -> Idx #cnt
wrap_add a b => wrap_op (add b) a

wrap_dec :: Idx #cnt -> Idx #cnt
wrap_dec a => wrap_add a (count_idx a - 1)

put :: { Load p } =>
  (a -> ()) -> Pointer p (Deque #cnt a) -> ()
put f p => putBrackets (foreach (putElem f) p)

fold :: { Load p } => (b -> a -> b) -> b -> Pointer p (Deque #cnt a) -> b
fold f b deq => do
  pb = new b
  foreach (fold_ptr f pb) deq
  @pb