-
Notifications
You must be signed in to change notification settings - Fork 0
/
set.cairo
119 lines (100 loc) · 3.56 KB
/
set.cairo
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
%lang starknet
from starkware.cairo.common.bool import TRUE, FALSE
from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize
from starkware.cairo.common.dict import dict_write, dict_read, dict_update
from starkware.cairo.common.dict_access import DictAccess
from src.utils.constants import SET_SIZE, UNDEFINED
from src.utils.comparator import is_ge
func new_set{range_check_ptr}() -> DictAccess* {
alloc_locals;
let (local set) = default_dict_new(default_value=UNDEFINED);
// Persist the set size in the same dict so user dont has to worry about it
dict_write{dict_ptr=set}(key=SET_SIZE, new_value=0);
default_dict_finalize(dict_accesses_start=set, dict_accesses_end=set, default_value=UNDEFINED);
return set;
}
func add{range_check_ptr, set: DictAccess*}(value: felt) {
alloc_locals;
let set_size = size();
let (contains_value, _) = contains(value);
if (contains_value == FALSE) {
dict_write{dict_ptr=set}(key=set_size, new_value=value);
// update set size
dict_update{dict_ptr=set}(key=SET_SIZE, prev_value=set_size, new_value=set_size + 1);
} else {
return ();
}
return ();
}
func get{range_check_ptr, set: DictAccess*}(idx: felt) -> felt {
let set_size = size();
if (set_size == 0) {
return UNDEFINED;
}
tempvar idx_out_of_bounds = is_ge(idx, set_size);
if (idx_out_of_bounds == TRUE) {
return UNDEFINED;
}
let (value) = dict_read{dict_ptr=set}(key=idx);
return value;
}
func remove{range_check_ptr, set: DictAccess*}(idx: felt) -> felt {
alloc_locals;
let value = get(idx);
if (value != UNDEFINED) {
let set_size = size();
// update set size and build a set without that value
_update_set(idx, set_size);
dict_update{dict_ptr=set}(key=SET_SIZE, prev_value=set_size, new_value=set_size - 1);
return value;
} else {
return value;
}
}
func replace{range_check_ptr, set: DictAccess*}(idx: felt, value: felt) {
alloc_locals;
let set_size = size();
tempvar idx_out_of_bounds = is_ge(idx, set_size);
if (idx_out_of_bounds == TRUE) {
return ();
}
let (contains_value, idx_value) = contains(value);
if (contains_value == TRUE) {
remove(idx_value);
tempvar range_check_ptr=range_check_ptr;
tempvar set=set;
} else {
tempvar range_check_ptr=range_check_ptr;
tempvar set=set;
}
dict_write{dict_ptr=set}(key=idx, new_value=value);
return ();
}
func contains{range_check_ptr, set: DictAccess*}(value: felt) -> (contains: felt, idx: felt) {
let set_size = size();
return _contains(value, 0, set_size);
}
func size{range_check_ptr, set: DictAccess*}() -> felt {
let (set_size) = dict_read{dict_ptr=set}(key=SET_SIZE);
return set_size;
}
// Aux methods
func _contains{range_check_ptr, set: DictAccess*}(value: felt, idx: felt, set_size: felt) -> (contains: felt, idx: felt) {
if (idx == set_size) {
return (FALSE, UNDEFINED);
}
let (set_value) = dict_read{dict_ptr=set}(key=idx);
if (set_value == value) {
return (TRUE, idx);
}
return _contains(value, idx + 1, set_size);
}
func _update_set{range_check_ptr, set: DictAccess*}(idx: felt, set_size: felt) {
if (idx == set_size - 1) {
return ();
}
// update every set value with the next one
let (next_value) = dict_read{dict_ptr=set}(key=idx + 1);
dict_write{dict_ptr=set}(key=idx, new_value=next_value);
return _update_set(idx + 1, set_size);
}