Repository navigation
Expand file tree
/
Copy pathmodule.ae
More file actions
137 lines (128 loc) · 5.2 KB
/
Copy pathmodule.ae
File metadata and controls
137 lines (128 loc) · 5.2 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
// std.map - HashMap Operations (alias for std.collections)
//
// API shape:
// - Raw externs end in `_raw` and return ptr/int in the old C-style
// convention. They are the escape hatch for advanced callers.
// - Aether-native wrappers (below) use Go-style `(value, err)` / `err`
// returns.
exports(
map_new, map_put, map_put_raw, map_put_string_owned, map_get_raw, map_has, map_remove,
map_size, map_clear, map_free, map_keys_raw, map_keys_free,
map_keys_size_raw, map_keys_get_raw,
get, get_string, lookup, keys, keys_size, keys_get
)
// Keys cross as `@aether string`: the C map reads the AetherString's length,
// so a key with an embedded NUL is the whole key (#2469). Unwrapped to a C
// string, "a\0x" and "a\0y" were one key, "a".
extern map_new() -> ptr @fresh
// The stores keep their value past the call (#3086): a `ptr` stays the
// map's, so a function that puts a borrowed `ptr` parameter declares it
// `@keep`, and a string or a closure is handed a reference of its own
// (`@retain`, R4). The key is copied.
extern map_put_raw(map: @holds ptr, key: @aether string, value: @aether @retain ptr) -> int
// Insert or update a key-value pair. Returns "" on success, error on
// failure (null map/key or OOM).
extern map_put(map: @holds ptr, key: @aether string, value: @aether @retain ptr) -> string
// String-aware put, for C and `ptr` callers. The map takes a
// reference of its own: a counted string is retained, a plain C
// pointer is copied. The caller keeps and releases its own, so the
// same value can live in several containers. map_free releases each
// owned value. `map.put(m, k, s)` of a `string` in Aether code is a
// store into the map (R3): the compiler hands the map a reference,
// moving a fresh value in.
extern map_put_string_owned(map: @holds ptr, key: @aether string, value: @aether ptr) -> int
extern map_get_raw(map: ptr, key: @aether string) -> ptr
extern map_has(map: ptr, key: @aether string) -> int
extern map_remove(map: ptr, key: @aether string)
extern map_size(map: ptr) -> int
extern map_clear(map: ptr)
extern map_free(map: ptr)
extern map_keys_raw(map: ptr) -> ptr
extern map_keys_free(keys: ptr)
extern map_keys_size_raw(keys: ptr) -> int
extern map_keys_get_raw(keys: ptr, index: int) -> string
extern aether_string_is_string(p: @aether ptr) -> int
// Look up a key.
// - (value, "") : key present
// - (null, "") : key absent (not an error — use map.has)
// - (null, "null map") : `map` is null
get(map: ptr, key: string) -> {
if map == null {
return null, "null map"
}
v = map_get_raw(map, key)
return v, ""
}
// The value stored under `key`, or null when the map holds none (or the map
// is null): `get` without its error slot, for a caller that reads absence
// as null (#3107).
lookup(map: ptr, key: string) -> ptr {
if map == null {
return null
}
return map_get_raw(map, key)
}
// Look up a key whose value is a string. `get` hands back a `ptr`, which a
// `string` local would read as text whatever it points at (refused, E0202);
// this says the value is a string, and checks it is one:
// - (value, "") : key present, its value a string
// - (null, "") : key absent (not an error — use map.has)
// - (null, "not a string") : the value is some other pointer
// - (null, "null map") : `map` is null
get_string(map: ptr, key: string) -> (string, string) {
if map == null {
return null, "null map"
}
v = map_get_raw(map, key)
if v == null {
return null, ""
}
if aether_string_is_string(v) == 0 {
return null, "not a string"
}
return v, ""
}
// Snapshot a map's keys. Returns (MapKeys ptr, "") on success, (null,
// error) on allocation failure. Caller must free with map.keys_free.
keys(map: ptr) -> {
if map == null {
return null, "null map"
}
k = map_keys_raw(map)
if k == null {
return null, "allocation failed"
}
return k, ""
}
// ---- reading a keys snapshot (#1724) --------------------------------------
//
// `keys` hands back a snapshot; these read it. Before this pair the snapshot
// could only be allocated and freed, so a map's key set was unreachable from
// Aether and callers kept a parallel array of keys purely to have something
// iterable.
//
// The strings are BORROWED from the live map: valid until `keys_free`, and
// only while the map still holds that entry. The snapshot does not track
// later mutation -- a key removed from the map leaves a dangling entry here.
// Retain or copy anything that must outlive either.
//
// Iteration order is bucket order and is UNSPECIFIED. Callers who need a
// deterministic order sort the keys (std.sort.strings).
keys_size(keys: ptr) -> int {
if keys == null {
return 0
}
return map_keys_size_raw(keys)
}
// Out of range or null returns "" rather than trapping, so a bad index is a
// visible empty string instead of a wild read. An empty string is also a
// legitimate key, so callers who must distinguish check keys_size first.
keys_get(keys: ptr, index: int) -> string {
if keys == null {
return ""
}
if index < 0 || index >= map_keys_size_raw(keys) {
return ""
}
return map_keys_get_raw(keys, index)
}