Repository navigation
Expand file tree
/
Copy pathmodule.ae
More file actions
121 lines (111 loc) · 4 KB
/
Copy pathmodule.ae
File metadata and controls
121 lines (111 loc) · 4 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
// MIT License (https://opensource.org/licenses/MIT)
//
// Portions copyright (c) 2000-2026 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
//
// Portions copyright (c) 2026 Aether Developers.
//
// std.bits — unsigned-bit helpers.
//
// Aether's `>>` on int/long is arithmetic (sign-propagating) and the
// language has no unsigned integer types. Cryptography / codec code routinely
// needs the *unsigned* interpretation: logical right shift, rotates,
// popcount, count-leading-zeros, and unsigned division / remainder /
// compare. These map exactly onto C casts to the unsigned type, so each
// friendly name is a thin wrapper over an `aether_bits_*` extern.
//
// Width note: `int` is 32-bit and `long` is 64-bit on every target.
// The 32-bit ops take/return `int`; the 64-bit ops take/return `long`
// for the value with an `int` shift/rotate count.
exports(
lsr32, lsr64,
rotr32, rotl32, rotr64, rotl64,
popcount32, popcount64,
clz32, clz64,
udiv32, urem32, udiv64, urem64,
ucmp64,
wrapping_add64, wrapping_mul64
)
// ---- Raw externs ----
extern aether_bits_lsr32(x: int, n: int) -> int
extern aether_bits_lsr64(x: long, n: int) -> long
extern aether_bits_rotr32(x: int, n: int) -> int
extern aether_bits_rotl32(x: int, n: int) -> int
extern aether_bits_rotr64(x: long, n: int) -> long
extern aether_bits_rotl64(x: long, n: int) -> long
extern aether_bits_popcount32(x: int) -> int
extern aether_bits_popcount64(x: long) -> int
extern aether_bits_clz32(x: int) -> int
extern aether_bits_clz64(x: long) -> int
extern aether_bits_udiv32(a: int, b: int) -> int
extern aether_bits_urem32(a: int, b: int) -> int
extern aether_bits_udiv64(a: long, b: long) -> long
extern aether_bits_urem64(a: long, b: long) -> long
extern aether_bits_ucmp64(a: long, b: long) -> int
extern aether_bits_wrapping_add64(a: long, b: long) -> long
extern aether_bits_wrapping_mul64(a: long, b: long) -> long
// ---- Friendly wrappers ----
// Logical (unsigned) right shift of `x` by `n` bits. The shift count
// is masked by (W-1), so n is taken mod 32 (lsr32) / mod 64 (lsr64).
lsr32(x: int, n: int) -> int {
return aether_bits_lsr32(x, n)
}
lsr64(x: long, n: int) -> long {
return aether_bits_lsr64(x, n)
}
// Bit rotates. Count masked by (W-1); a count of 0 returns x unchanged.
rotr32(x: int, n: int) -> int {
return aether_bits_rotr32(x, n)
}
rotl32(x: int, n: int) -> int {
return aether_bits_rotl32(x, n)
}
rotr64(x: long, n: int) -> long {
return aether_bits_rotr64(x, n)
}
rotl64(x: long, n: int) -> long {
return aether_bits_rotl64(x, n)
}
// Count of set bits over the unsigned value.
popcount32(x: int) -> int {
return aether_bits_popcount32(x)
}
popcount64(x: long) -> int {
return aether_bits_popcount64(x)
}
// Count leading zeros over the unsigned value, MSB-first. Returns the
// width (32 / 64) for a zero input.
clz32(x: int) -> int {
return aether_bits_clz32(x)
}
clz64(x: long) -> int {
return aether_bits_clz64(x)
}
// Unsigned division / remainder. Returns 0 if the divisor is 0.
udiv32(a: int, b: int) -> int {
return aether_bits_udiv32(a, b)
}
urem32(a: int, b: int) -> int {
return aether_bits_urem32(a, b)
}
udiv64(a: long, b: long) -> long {
return aether_bits_udiv64(a, b)
}
urem64(a: long, b: long) -> long {
return aether_bits_urem64(a, b)
}
// Unsigned compare of two 64-bit values. Returns -1 / 0 / 1.
ucmp64(a: long, b: long) -> int {
return aether_bits_ucmp64(a, b)
}
// Wrapping (defined modulo-2^64) add / multiply. Carry the low 64 bits
// like C's `uint64` — computed in the unsigned domain so the overflow is
// *defined*, unlike a native `a * b` on `long`, which is signed-overflow
// UB (a `-fsanitize=undefined` build traps on it). Reach for these when
// an on-disk / wire format depends on defined unsigned overflow, e.g. an
// LCG like `x = x * 4294967311 + 17`.
wrapping_add64(a: long, b: long) -> long {
return aether_bits_wrapping_add64(a, b)
}
wrapping_mul64(a: long, b: long) -> long {
return aether_bits_wrapping_mul64(a, b)
}