This PR adjusts the experimental module system to make `private` the default visibility modifier in `module`s, introducing `public` as a new modifier instead. `public section` can be used to revert the default for an entire section, though this is more intended to ease gradual adoption of the new semantics such as in `Init` (and soon `Std`) where they should be replaced by a future decl-by-decl re-review of visibilities.
81 lines
2.5 KiB
Text
81 lines
2.5 KiB
Text
/-
|
||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Daniel Selsam
|
||
|
||
Simple queue implemented using two lists.
|
||
Note: this is only a temporary placeholder.
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Init.Data.List.Control
|
||
|
||
public section
|
||
|
||
namespace Std
|
||
|
||
/--
|
||
A functional queue data structure, using two back-to-back lists.
|
||
If we think of the queue as having elements pushed on the front and
|
||
popped from the back, then the queue itself is effectively `eList ++ dList.reverse`.
|
||
-/
|
||
structure Queue (α : Type u) where
|
||
/-- The enqueue list, which stores elements that have just been pushed
|
||
(with the most recently enqueued elements at the head). -/
|
||
eList : List α := []
|
||
/-- The dequeue list, which buffers elements ready to be dequeued
|
||
(with the head being the next item to be yielded by `dequeue?`). -/
|
||
dList : List α := []
|
||
|
||
namespace Queue
|
||
|
||
variable {α : Type u}
|
||
|
||
/-- `O(1)`. The empty queue. -/
|
||
def empty : Queue α := {}
|
||
|
||
instance : EmptyCollection (Queue α) := ⟨.empty⟩
|
||
instance : Inhabited (Queue α) := ⟨∅⟩
|
||
|
||
/-- `O(1)`. Is the queue empty? -/
|
||
def isEmpty (q : Queue α) : Bool :=
|
||
q.dList.isEmpty && q.eList.isEmpty
|
||
|
||
/-- `O(1)`. Push an element on the front of the queue. -/
|
||
def enqueue (v : α) (q : Queue α) : Queue α :=
|
||
{ q with eList := v::q.eList }
|
||
|
||
/-- `O(|vs|)`. Push a list of elements `vs` on the front of the queue. -/
|
||
def enqueueAll (vs : List α) (q : Queue α) : Queue α :=
|
||
{ q with eList := vs ++ q.eList }
|
||
|
||
/--
|
||
`O(1)` amortized, `O(n)` worst case. Pop an element from the back of the queue,
|
||
returning the element and the new queue.
|
||
-/
|
||
def dequeue? (q : Queue α) : Option (α × Queue α) :=
|
||
match q.dList with
|
||
| d::ds => some (d, { q with dList := ds })
|
||
| [] =>
|
||
match q.eList.reverse with
|
||
| [] => none
|
||
| d::ds => some (d, { eList := [], dList := ds })
|
||
|
||
def toArray (q : Queue α) : Array α :=
|
||
q.dList.toArray ++ q.eList.toArray.reverse
|
||
|
||
/--
|
||
`O(n)`. Applies the monadic predicate `p` to every element in the queue, and returns the queue
|
||
of elements for which `p` returns `true`. Note that there are currently no guarantees for the order
|
||
that `p` is applied in.
|
||
-/
|
||
@[specialize]
|
||
def filterM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (q : Queue α) :
|
||
m (Queue α) := do
|
||
let dList ← q.dList.filterM p
|
||
let eList ← q.eList.filterM p
|
||
if dList.isEmpty then
|
||
return { dList := eList.reverse, eList := [] }
|
||
else
|
||
return { dList, eList }
|