Table
include collections
module hash_table(key,value,shard) = {
¤
Interface
Set the value of a key
action set(k:key.t, v:value)
action get(k:key.t) returns (v:value)
action extract_(lo:key.t,hi:key.t) returns(res:shard.t)
action incorporate(s:shard.t)
¤
Specification
function hash(X:key.t) : value
init hash(X) = 0
object spec = {
before set {
hash(k) := v
}
after get {
assert v = hash(k)
}
after extract_ {
assert shard.lo(res) = lo;
assert (lo <= hi -> lo <= shard.hi(res)) & shard.hi(res) <= hi;
assert (shard.lo(res) <= X & X <= shard.hi(res)) -> shard.value(res,X) = hash(X)
}
before incorporate(s:shard.t) {
assert shard.valid(s);
hash(K) := shard.value(s,K) if (shard.lo(s) <= K & K <= shard.hi(s)) else hash(K)
}
}
¤
Implementation
object impl = {
instance tab : ordered_map(key,value)
implement set {
call tab.set(k,v)
}
implement get {
v := tab.get(k)
}
implement extract_ {
shard.second(res,X) := 0;
local idx : key.iter.t, pos : shard.iter.t, lim: key.iter.t {
idx := tab.begin(lo);
lim := key.iter.begin(hi);
pos := shard.iter.begin(0);
while ~shard.iter.iter_end(pos) & idx <= lim
invariant ~shard.iter.done(X,pos) -> shard.second(res,X) = 0
invariant lo <= X & key.iter.done(X,idx) -> shard.value(res,X) = hash(X)
invariant ~key.iter.iter_end(idx) -> lo <= key.iter.iter_val(idx)
invariant shard.iter.iter_end(pos) -> key.iter.done(lo,idx)
invariant ~key.iter.done(X,idx) -> ~shard.at(res,X,Y)
invariant shard.at(res,X,Y) & shard.at(res,X,Z) -> Y = Z
{
shard.first(res,shard.iter.val(pos)) := key.iter.val(idx);
shard.second(res,shard.iter.val(pos)) := tab.get(key.iter.val(idx));
idx := tab.next(idx);
pos := shard.iter.next(pos)
};
shard.lo(res) := lo;
if key.iter.done(hi,idx) {
shard.hi(res) := hi
} else {
shard.hi(res) := key.iter.val(key.iter.prev(idx))
}
}
}
implement incorporate(s:shard.t) {
local lo:key.t, hi:key.t {
lo := shard.lo(s);
hi := shard.hi(s);
call tab.erase(lo,hi);
local idx : key.iter.t, pos : shard.iter.t {
pos := shard.iter.begin(0);
while ~shard.iter.iter_end(pos)
invariant lo <= X & X <= hi & shard.value(s,X) = 0 -> ~tab.s(X)
invariant lo <= X & X <= hi & shard.iter.done(Y,pos) & shard.at(s,X,Y) -> tab.s(X) & tab.r(X,shard.value(s,X))
invariant ~(lo <= X & X <= hi) -> spec.tab_invar(X,Y)
invariant tab.r(X,Y) & tab.r(X,Z) -> Y = Z
{
local r : shard.range {
r := shard.iter.val(pos);
if lo <= shard.first(s,r) & shard.first(s,r) <= hi & shard.second(s,r) ~= 0 {
call tab.set(shard.first(s,r),shard.second(s,r))
}
};
pos := shard.iter.next(pos)
}
}
}
}
object spec = {
derived tab_invar(X,Y) =
(tab.s(X) & tab.r(X,Y) -> hash(X) = Y)
& (~tab.s(X) -> hash(X) = 0)
& (tab.s(X) -> tab.r(X,hash(X)))
}
conjecture shard.value(S,X)=Z -> spec.tab_invar(X,Y)
}
}