-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathmodule.ae
More file actions
153 lines (137 loc) · 4.88 KB
/
Copy pathmodule.ae
File metadata and controls
153 lines (137 loc) · 4.88 KB
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
// std.set - unordered set of unique strings
//
// Backed by the same hash table as std.map, so lookups are O(1) on
// average and items are copied on insert (the caller's string lifetime
// does not matter).
//
// import std.set
//
// main() {
// seen = set.new()
// set.add(seen, "alpha")
// set.add(seen, "alpha") // already present, set stays size 1
// if set.contains(seen, "alpha") {
// println("size=${set.size(seen)}")
// }
// set.free(seen)
// }
//
// API shape:
// - Raw externs mirror the C entry points and use the C-style int
// returns. They are the escape hatch for advanced callers.
// - Aether-native wrappers (below) return bools and Go-style
// `(value, err)` tuples.
exports(
aether_set_new, aether_set_add, aether_set_has, aether_set_remove, aether_set_size, aether_set_clear, aether_set_free,
aether_set_items_raw, aether_set_items_free,
map_keys_size_raw, map_keys_get_raw,
new, add, try_add, contains, remove, size, clear, free, items, items_free,
items_size, items_get
)
// ---- raw externs (std/collections/aether_set.c) ----
extern aether_set_new() -> ptr
extern aether_set_add(set: ptr, item: string) -> int
extern aether_set_has(set: ptr, item: string) -> int
extern aether_set_remove(set: ptr, item: string)
extern aether_set_size(set: ptr) -> int
extern aether_set_clear(set: ptr)
extern aether_set_free(set: ptr)
extern aether_set_items_raw(set: ptr) -> ptr
extern aether_set_items_free(items: ptr)
// aether_set_items_raw returns the same MapKeys snapshot map.keys does, so
// the read side is literally the same two functions (#1724).
extern map_keys_size_raw(items: ptr) -> int
extern map_keys_get_raw(items: ptr, index: int) -> string
// ---- Aether-side wrappers ----
// Create an empty set. Returns null on allocation failure.
new() -> ptr {
return aether_set_new()
}
// Insert `item`. Returns true if it was added, false if it was already
// present OR the insert failed — the two are indistinguishable here, which
// is why try_add exists. Keep using this where duplicate suppression is the
// whole point and an allocation failure would take the process down anyway.
add(set: ptr, item: string) -> bool {
return aether_set_add(set, item) == 1
}
// Insert `item`, distinguishing the three outcomes the layer below already
// knows about:
//
// (true, "") inserted
// (false, "") already present — normal, not an error
// (false, "set: ...") the insert FAILED (null set, or out of memory)
//
// `add` collapses the last two into a bare false, so a caller who checks it
// cannot tell "this was a duplicate" from "this was never stored". For a
// dedupe filter that difference is invisible; for anything that must know
// its data landed, it is the difference between correct and silently lossy.
try_add(set: ptr, item: string) -> (bool, string) {
rc = aether_set_add(set, item)
if rc == 1 {
return true, ""
}
if rc == 0 {
return false, ""
}
return false, "set: insert failed"
}
// True when `item` is in the set.
contains(set: ptr, item: string) -> bool {
return aether_set_has(set, item) == 1
}
// Drop `item`. Absent items are ignored.
remove(set: ptr, item: string) {
aether_set_remove(set, item)
}
// Number of items currently in the set.
size(set: ptr) -> int {
return aether_set_size(set)
}
// Drop every item, keeping the set usable.
clear(set: ptr) {
aether_set_clear(set)
}
// Release the set. Items were copied in, so nothing else needs freeing.
free(set: ptr) {
aether_set_free(set)
}
// Snapshot the set's items, in unspecified order. Returns
// (MapKeys ptr, "") on success, (null, error) otherwise. The snapshot
// is released with `set.items_free`.
items(set: ptr) -> {
if set == null {
return null, "null set"
}
it = aether_set_items_raw(set)
if it == null {
return null, "allocation failed"
}
return it, ""
}
// Release a snapshot returned by `set.items`.
items_free(items: ptr) {
aether_set_items_free(items)
}
// ---- reading an items snapshot (#1724) ------------------------------------
//
// Same contract as map.keys_size / map.keys_get, because `items` returns the
// same snapshot type: the strings are BORROWED, valid until `items_free` and
// only while the set still holds them, and iteration order is unspecified.
// Sort (std.sort.strings) for a deterministic order.
items_size(items: ptr) -> int {
if items == null {
return 0
}
return map_keys_size_raw(items)
}
// Out of range or null returns "" rather than trapping. An empty string is
// also a legitimate item, so callers who must distinguish check items_size.
items_get(items: ptr, index: int) -> string {
if items == null {
return ""
}
if index < 0 || index >= map_keys_size_raw(items) {
return ""
}
return map_keys_get_raw(items, index)
}