nomen-lang 0.0.15 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -356,7 +356,11 @@ pub struct Buffer<T> {
356
356
  ```
357
357
  }
358
358
 
359
- func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
359
+ // `inline` splices the (width-folded at monomorphization) raw body at
360
+ // call sites — the load/store pair behind every container `.at`/`set` is
361
+ // the hottest path in data-heavy code, and the naked-inline path keeps it
362
+ // to a handful of instructions with no call overhead.
363
+ inline func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
360
364
  ```
361
365
  #arch: c
362
366
  return ((T*)(unsigned long long)self->data)[i];
@@ -399,7 +403,7 @@ pub struct Buffer<T> {
399
403
  ```
400
404
  }
401
405
 
402
- func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
406
+ inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
403
407
  ```
404
408
  #arch: c
405
409
  ((T*)(unsigned long long)self->data)[i] = val;
@@ -57,6 +57,22 @@ pub struct LinkedList<T>: Enumerable {
57
57
  return self.values.load_T(idx)
58
58
  }
59
59
 
60
+ // Bounds-checked access: `fallback` when idx is outside [0, self.count).
61
+ pub func at_or = (self, int idx, T fallback, out T) {
62
+ if idx >= 0 && idx < self.count {
63
+ return self.at(idx)
64
+ }
65
+ return fallback
66
+ }
67
+
68
+ // Bounds-checked access that traps when idx is outside [0, self.count).
69
+ pub func at_or_panic = (self, int idx, out T) {
70
+ if idx >= 0 && idx < self.count {
71
+ return self.at(idx)
72
+ }
73
+ panic("index out of range")
74
+ }
75
+
60
76
  pub func length = (self, out int) {
61
77
  return self.count
62
78
  }
@@ -31,6 +31,26 @@ pub struct List<T>: Viewable {
31
31
  return self.items.load_T(i)
32
32
  }
33
33
 
34
+ // Bounds-checked access: `fallback` when i is outside [0, self.length) —
35
+ // for indices that can't be proven at compile time and out-of-range is an
36
+ // expected case.
37
+ pub func at_or = (self, int i, T fallback, out T) {
38
+ if i >= 0 && i < self.length {
39
+ return self.at(i)
40
+ }
41
+ return fallback
42
+ }
43
+
44
+ // Bounds-checked access that traps when i is outside [0, self.length) —
45
+ // for indices that can't be proven at compile time and out-of-range is a
46
+ // bug, not a case.
47
+ pub func at_or_panic = (self, int i, out T) {
48
+ if i >= 0 && i < self.length {
49
+ return self.at(i)
50
+ }
51
+ panic("index out of range")
52
+ }
53
+
34
54
  // A non-owning `view T` over [start, end). Delegates to the backing Buffer's
35
55
  // #arch slice primitive — no #arch code here. Borrows from self.
36
56
  pub func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
@@ -1,7 +1,12 @@
1
1
  /**
2
- * An ordered key-value map with `set`/`get`/`has`/`remove`. Keys must be
2
+ * An ordered key-value map with `set`/`get`/`get_or`/`has`/`remove`. Keys must be
3
3
  * `Hashable` (hashed to a `uint` via `key.hash()`) and `Equatable` (compared
4
4
  * with `==`); values may be any type.
5
+ *
6
+ * The capacity is always a power of two (initial 8, doubling on rehash), so
7
+ * bucket indexing is a mask (`hash & (cap - 1)`) instead of a division — and
8
+ * it is correct for negative hashes too: two's-complement `&` already lands
9
+ * in `[0, cap)`, which is why no negative adjustment is needed.
5
10
  **/
6
11
  pub struct Map<TK: Hashable + Equatable, TV> {
7
12
  var length = 0
@@ -53,6 +58,34 @@ pub struct Map<TK: Hashable + Equatable, TV> {
53
58
  return self.values.load_T(idx)
54
59
  }
55
60
 
61
+ // Fused lookup-with-fallback: one probe instead of the `has` + `get`
62
+ // pair (which probes twice) for the common "default when missing" shape.
63
+ pub func get_or = (self, TK key, TV fallback, out TV) {
64
+ var int cap = self.keys.cap
65
+ if cap == 0 {
66
+ return fallback
67
+ }
68
+ var int idx = self.find_slot(key, cap)
69
+ if self.used.load(idx) == 0 {
70
+ return fallback
71
+ }
72
+ return self.values.load_T(idx)
73
+ }
74
+
75
+ // Lookup that traps when the key is absent — for when a missing key is
76
+ // a bug, not a case (and `get`'s 0-for-missing would be ambiguous).
77
+ pub func get_or_panic = (self, TK key, out TV) {
78
+ var int cap = self.keys.cap
79
+ if cap == 0 {
80
+ panic("key not found")
81
+ }
82
+ var int idx = self.find_slot(key, cap)
83
+ if self.used.load(idx) == 0 {
84
+ panic("key not found")
85
+ }
86
+ return self.values.load_T(idx)
87
+ }
88
+
56
89
  pub func has = (self, TK key, out bool) {
57
90
  var int cap = self.keys.cap
58
91
  if cap == 0 {
@@ -91,10 +124,7 @@ pub struct Map<TK: Hashable + Equatable, TV> {
91
124
  if self.used.load(k) == 0 {
92
125
  break
93
126
  }
94
- var int home = (self.keys.load_T(k).hash() as int) % cap
95
- if home < 0 {
96
- home = home + cap
97
- }
127
+ var int home = (self.keys.load_T(k).hash() as int) & (cap - 1)
98
128
  var int dgap = gap - home
99
129
  if dgap < 0 {
100
130
  dgap = dgap + cap
@@ -115,10 +145,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
115
145
  }
116
146
 
117
147
  func find_slot = (self, TK key, int cap, out int: out >= 0 && out < cap) {
118
- var int idx = (key.hash() as int) % cap
119
- if idx < 0 {
120
- idx = idx + cap
121
- }
148
+ // cap is a power of two, so this is `hash mod cap` via a mask —
149
+ // non-negative for any hash (two's complement), no adjustment.
150
+ var int idx = (key.hash() as int) & (cap - 1)
122
151
  while self.used.load(idx) != 0 {
123
152
  if self.keys.load_T(idx) == key {
124
153
  return idx
@@ -2,6 +2,10 @@
2
2
  * An ordered set of unique values (`add`/`has`/`get`/`remove`). Elements must
3
3
  * be `Hashable` (hashed to a `uint` via `value.hash()`) and `Equatable`
4
4
  * (compared with `==`).
5
+ *
6
+ * The capacity is always a power of two (initial 8, doubling on rehash), so
7
+ * slot indexing is a mask (`hash & (cap - 1)`) — correct for negative hashes
8
+ * too (two's-complement `&` already lands in `[0, cap)`).
5
9
  **/
6
10
  pub struct Set<T: Hashable + Equatable> {
7
11
  var length = 0
@@ -47,6 +51,33 @@ pub struct Set<T: Hashable + Equatable> {
47
51
  return self.slots.load_T(idx)
48
52
  }
49
53
 
54
+ // Membership lookup with a fallback value: `fallback` when the value is
55
+ // not in the set (one probe instead of the `has` + `get` pair).
56
+ pub func get_or = (self, T key, T fallback, out T) {
57
+ var int cap = self.slots.cap
58
+ if cap == 0 {
59
+ return fallback
60
+ }
61
+ var int idx = self.find_slot(key, cap)
62
+ if self.used.load(idx) == 0 {
63
+ return fallback
64
+ }
65
+ return self.slots.load_T(idx)
66
+ }
67
+
68
+ // Membership lookup that traps when the value is not in the set.
69
+ pub func get_or_panic = (self, T key, out T) {
70
+ var int cap = self.slots.cap
71
+ if cap == 0 {
72
+ panic("value not found in set")
73
+ }
74
+ var int idx = self.find_slot(key, cap)
75
+ if self.used.load(idx) == 0 {
76
+ panic("value not found in set")
77
+ }
78
+ return self.slots.load_T(idx)
79
+ }
80
+
50
81
  pub func remove = (ref self, T value) {
51
82
  var int cap = self.slots.cap
52
83
  if cap == 0 {
@@ -76,10 +107,7 @@ pub struct Set<T: Hashable + Equatable> {
76
107
  if self.used.load(k) == 0 {
77
108
  break
78
109
  }
79
- var int home = (self.slots.load_T(k).hash() as int) % cap
80
- if home < 0 {
81
- home = home + cap
82
- }
110
+ var int home = (self.slots.load_T(k).hash() as int) & (cap - 1)
83
111
  var int dgap = gap - home
84
112
  if dgap < 0 {
85
113
  dgap = dgap + cap
@@ -99,10 +127,9 @@ pub struct Set<T: Hashable + Equatable> {
99
127
  }
100
128
 
101
129
  func find_slot = (self, T value, int cap, out int: out >= 0 && out < cap) {
102
- var int idx = (value.hash() as int) % cap
103
- if idx < 0 {
104
- idx = idx + cap
105
- }
130
+ // cap is a power of two: `hash mod cap` via a mask, non-negative
131
+ // for any hash — no adjustment needed.
132
+ var int idx = (value.hash() as int) & (cap - 1)
106
133
  while self.used.load(idx) != 0 {
107
134
  if self.slots.load_T(idx) == value {
108
135
  return idx
@@ -51,6 +51,24 @@ pub struct string: Stringable, Hashable, Equatable {
51
51
  ```
52
52
  }
53
53
 
54
+ // Bounds-checked access: `fallback` when index is outside
55
+ // [0, self.length).
56
+ pub func at_or = (self, int index, char fallback, out char) {
57
+ if index >= 0 && index < self.length {
58
+ return self.at(index)
59
+ }
60
+ return fallback
61
+ }
62
+
63
+ // Bounds-checked access that traps when index is outside
64
+ // [0, self.length) — out-of-range is a bug, not a case.
65
+ pub func at_or_panic = (self, int index, out char) {
66
+ if index >= 0 && index < self.length {
67
+ return self.at(index)
68
+ }
69
+ panic("index out of range")
70
+ }
71
+
54
72
  // A non-owning slice [start, end) into self's buffer. Returns a `view
55
73
  // string` (ptr, len) that borrows from self: it may not outlive self's
56
74
  // scope and is invalidated if self is reassigned. Use .to_string() to