packages feed

pec-0.2.0: lib/Data/Stack.pec

module Data.Stack

// explicit export list

exports
  Stack
  any
  empty
  filter
  find
  find_idx
  fold
  foreach
  foreach_idx
  is_empty
  is_full
  map
  pop
  push
  put
  stack

imports
  Prelude
  Data.Array as A

where

// BAL: some Ptr's can be changed to Load Pointers

type Stack cnt a =
  { height :: W32
  , data :: Array #cnt a
  }
// stacks are polymorphic in their size and what they contain

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

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

find :: (a -> Bool) -> Ptr (Stack #cnt a) -> Maybe (Ptr a)
find f p => case new (find_idx f p) of
  Nothing -> Nothing
  Just i -> Just p.data[@i]

find_idx :: (a -> Bool) -> Ptr (Stack #cnt a) -> Maybe (Idx #cnt)
find_idx f p => A.unsafe_find_idx @p.height f p.data

any :: (a -> Bool) -> Ptr (Stack #cnt a) -> Bool
any f p => case new (find_idx f p) of
  Nothing -> False
  Just _ -> True

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

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

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

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

stack :: #cnt -> Stack #cnt a
stack _ => do
  p = unsafe_alloca
  empty p
  load p

push :: a -> Ptr (Stack #cnt a) -> Bool
push a p => branch
  is_full p -> False
  | do
      p.data[unsafe_to_idx @p.height] <- a
      inc p.height
      True

pop :: Ptr (Stack #cnt a) -> Maybe a
pop p => branch
  del p -> Just @p.data[unsafe_to_idx @p.height]
  | Nothing

del :: Ptr (Stack #cnt a) -> Bool
del p => branch
  is_empty p -> False
  | do
      dec p.height
      True

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

is_full :: { Load p } => Pointer p (Stack #cnt a) -> Bool
is_full p => @p.height > unsafe_cast (A.max_idx p.data)

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

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