-
Notifications
You must be signed in to change notification settings - Fork 1
/
016-count_distinct_characters.dfy
41 lines (39 loc) · 1.22 KB
/
016-count_distinct_characters.dfy
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
function contains_char(s: string, c: char): bool
decreases |s|
requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' || 'A' <= s[i] <= 'Z'
requires 'a' <= c <= 'z'
{
if |s| == 0 then false else s[0] == c || s[0] == upper_char(c) || contains_char(s[1..], c)
}
function upper_char(c: char) : (C: char)
requires 'a' <= c <= 'z'
ensures 'A' <= C <= 'Z'
{ c - 'a' + 'A' }
method count_distinct_characters(s: string) returns (count: int)
// pre-conditions-start
requires forall i :: 0 <= i < |s| ==> 'a' <= s[i] <= 'z' || 'A' <= s[i] <= 'Z'
// pre-conditions-end
// post-conditions-start
ensures count == |set c | 'a' <= c <= 'z' && contains_char(s, c)|
// post-conditions-end
{
// impl-start
count := 0;
ghost var contained: set<char> := {};
var i := 'a';
while i <= 'z'
// invariants-start
invariant 'a' <= i <= ('z' as int + 1) as char
invariant count == |contained|
invariant contained == set c | 'a' <= c < i && contains_char(s, c)
// invariants-end
{
if contains_char(s, i) {
count := count + 1;
contained := contained + {i};
}
i := (i as int + 1) as char;
}
assert contained == set c | 'a' <= c <= 'z' && contains_char(s, c); // assert-line
// impl-end
}