/* CS:5810 Formal Methods in Software Engineering Fall 2020 The University of Iowa Instructor: Cesare Tinelli */ // Parametric FIFO queue // Implementation uses an array to store the queue elements // in order of arrival class Queue { // Abtract representation of the queue's elements ghost var Content: seq; // Concrete implementation of the queue // container for the queue's elements var a: array; // size of the queue var n: nat; predicate Valid() reads this, a; { // Concrete class invariant n <= a.Length && 0 < a.Length && // Connection between abstract and concrete state Content == a[0..n] } constructor (d: T) ensures Valid(); ensures fresh(a); ensures Content == []; { a := new T[5](_ => d); // initializes every array element to d n := 0; // ghost code Content := []; } method front() returns (e: T) requires Valid(); requires Content != []; ensures Valid(); ensures Content == old(Content); ensures e == Content[0]; { e := a[0]; } method enqueue(e: T) modifies this, a; requires Valid(); ensures Valid(); ensures old(n) < old(a.Length) ==> a == old(a); ensures old(n) == old(a.Length) ==> fresh(a); ensures Content == old(Content) + [e]; { if (n == a.Length) { var b := new T[2 * a.Length](_ => e); forall i:int | 0 <= i < n { b[i] := a[i]; } a := b; } a[n] := e; n := n + 1; // ghost code Content := a[0..n]; } method dequeue() returns (e: T) modifies this, a; requires Content != []; requires Valid(); ensures Valid(); ensures a == old(a); ensures Content == old(Content[1..]); ensures [e] + Content == old(Content); { e := a[0]; n := n - 1; forall i:int | 0 <= i < n { a[i] := a[i + 1]; } // ghost code Content := a[0..n]; } } method test () { var q := new Queue(0); assert q.Content == []; q.enqueue(1); assert q.Content == [1]; q.enqueue(2); assert q.Content == [1,2]; q.enqueue(3); assert q.Content == [1,2,3]; q.enqueue(2); assert q.Content == [1,2,3,2]; q.enqueue(4); assert q.Content == [1,2,3,2,4]; var f := q.front(); assert f == 1 && q.Content == [1,2,3,2,4]; f := q.dequeue(); assert q.Content == [2,3,2,4]; q.enqueue(5); assert q.Content == [2,3,2,4,5]; }