1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
module ResizableArraySpec
use int.Int
use map.Map
use map.Const
type rarray 'a = private {
ghost mutable length: int;
ghost mutable data: map int 'a
}
function ([]) (r: rarray 'a) (i: int) : 'a = Map.get r.data i
val function ([<-]) (r: rarray 'a) (i: int) (v: 'a) : rarray 'a
ensures { result.length = r.length }
ensures { result.data = Map.set r.data i v }
val make (len: int) (dummy: 'a) : rarray 'a
requires { 0 <= len }
ensures { result.length = len }
ensures { result.data = Const.const dummy }
(* ensures { forall i: int. 0 <= i < len -> result[i] = dummy } *)
val ([]) (r: rarray 'a) (i: int) : 'a
requires { 0 <= i < r.length } ensures { result = r[i] }
val ([]<-) (r: rarray 'a) (i: int) (v: 'a) : unit writes {r}
requires { 0 <= i < r.length } ensures { r = (old r)[i <- v] }
val resize (r: rarray 'a) (len: int) : unit writes {r}
requires { 0 <= len }
ensures { r.length = len }
ensures { forall i: int.
0 <= i < old r.length -> i < len -> r[i] = (old r)[i] }
val append (r1: rarray 'a) (r2: rarray 'a) : unit writes {r1}
ensures { r1.length = (old r1.length) + r2.length }
ensures { forall i: int. 0 <= i < r1.length ->
(i < old r1.length -> r1[i] = (old r1)[i]) /\
(old r1.length <= i -> r1[i] = r2[i - old r1.length]) }
end
module ResizableArrayImplem (* : ResizableArraySpec *)
use int.Int
use int.MinMax
use array.Array as A
type rarray 'a =
{ dummy: 'a; mutable length: int; mutable data: A.array 'a }
invariant { 0 <= length <= A.length data }
invariant { forall i: int. length <= i < A.length data ->
A.([]) data i = dummy }
by { dummy = any 'a; length = 0; data = A.make 0 (any 'a) }
function ([]) (r: rarray 'a) (i: int) : 'a = A.([]) r.data i
(*
function make (len: int) (dummy: 'a) : rarray 'a =
{ dummy = dummy; length = len; data = A.make len dummy }
*)
let make (len: int) (dummy: 'a) : rarray 'a
requires { 0 <= len }
ensures { result.dummy = dummy }
ensures { result.length = len }
ensures { forall i:int. 0 <= i < len -> A.([]) result.data i = dummy }
=
{ dummy = dummy; length = len; data = A.make len dummy }
let ([]) (r: rarray 'a) (i: int) : 'a
requires { 0 <= i < r.length }
=
A.([]) r.data i
let ([]<-) (r: rarray 'a) (i: int) (v: 'a) : unit
requires { 0 <= i < r.length }
ensures { r.data.A.elts = A.Map.([<-]) (old r).data.A.elts i v }
=
A.([]<-) r.data i v
let resize (r: rarray 'a) (len: int) : unit
requires { 0 <= len }
ensures { r.length = len }
ensures { forall i: int.
0 <= i < old r.length -> i < len -> r[i] = (old r)[i] }
=
let n = A.length r.data in
if len > n then begin
let a = A.make (max len (2 * n)) r.dummy in
A.blit r.data 0 a 0 n;
r.data <- a
end else begin
A.fill r.data len (n - len) r.dummy
end;
r.length <- len
let append (r1: rarray 'a) (r2: rarray 'a) : unit
ensures { r1.length = old r1.length + r2.length }
ensures { forall i: int. 0 <= i < r1.length ->
(i < old r1.length -> r1[i] = (old r1)[i]) /\
(old r1.length <= i -> r1[i] = r2[i - old r1.length]) }
=
let n1 = length r1 in
resize r1 (length r1 + length r2);
A.blit r2.data 0 r1.data n1 (length r2)
(* sanity checks for WhyML typing system *)
(*
let test_reset1 (r: rarray) =
let a = A.make 10 dummy in
r.data <- a;
A.([]) a 0 (* <-- we cannot access array a anymore *)
let test_reset2 (r: rarray) =
let b = r.data in
r.data <- A.make 10 dummy;
let x = A.([]) r.data 0 in (* <-- this is accepted *)
let y = A.([]) b 0 in (* <-- but we cannot access array b anymore *)
()
(* the same, using resize *)
let test_reset3 (r: rarray) =
let c = r.data in
resize r 10;
let x = A.([]) r.data 0 in (* <-- this is accepted *)
let y = A.([]) c 0 in (* <-- but we cannot access array c anymore *)
()
*)
end
module Test
use int.Int
use ResizableArrayImplem
let test1 () =
let r = make 10 0 in
assert { r.length = 10 };
r[0] <- 17;
resize r 7;
assert { r[0] = 17 };
assert { r.length = 7 }
let test2 () =
let r1 = make 10 0 in
r1[0] <- 17;
let r2 = make 10 0 in
r2[0] <- 42;
append r1 r2;
assert { r1.length = 20 };
assert { r1[0] = 17 };
let x = r1[10] in
assert { x = 42 };
let y = r2[0] in
assert { y = 42 };
()
end
|