std.bits
Reed's standard library. Imported with use std.bits; not on disk.
Functions
| pack_bytes | Packs four bytes into an i32, b0 occupying the least significant byte. |
func pack_bytes(b0: i32, b1: i32, b2: i32, b3: i32) -> i32
Packs four bytes into an i32, b0 occupying the least significant byte.
Only the low 8 bits of each argument are used, so an out-of-range byte cannot corrupt its neighbours.
A free function rather than a method, because it has no receiver: a method's first parameter is its receiver (spec section 7.1), and none of these four bytes is more the subject of the operation than the others.
- Parameters
- b0 — the least significant byte
- b1 — the second byte
- b2 — the third byte
- b3 — the most significant byte
- See also
i32.byte
Source
func pack_bytes(b0: i32, b1: i32, b2: i32, b3: i32) -> i32 {
return (b0 & 0xFF) | ((b1 & 0xFF) << 8) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 24);
}
Methods
| i32.mask_low | A mask of the low n bits: n ones in the least significant positions. |
| i32.bit_range | Extracts width bits starting at bit offset, as an unsigned value. |
| i32.set_bit_range | Replaces width bits at bit offset with the low width bits of value. |
| i32.bit | Whether bit index is set. |
| i32.with_bit | Returns self with bit index set to value's truth. |
| i32.reverse_bits | Reverses the order of all 32 bits. |
| i32.bswap | Reverses byte order, converting between little- and big-endian. |
| i64.bswap | Reverses byte order of a 64-bit value. |
| i32.clo | Counts leading one bits, the complement of clz. |
| i32.cto | Counts trailing one bits, the complement of ctz. |
| i32.parity | The parity of the set bits. |
| i32.lowest_bit | Isolates the lowest set bit, clearing every other bit. |
| i32.clear_lowest_bit | Clears the lowest set bit, leaving every other bit. |
| i32.highest_bit | Isolates the highest set bit: the largest power of two not exceeding self. |
| i32.shl_wide | A left shift that is not masked modulo the operand width. |
| i32.shr_wide | An unsigned right shift that is not masked modulo the operand width. |
| i32.sign_extend | Sign-extends the low width bits, treating bit width - 1 as the sign. |
| i32.byte | Extracts byte index as an unsigned value in 0..=255. |
func i32.mask_low(self: i32) -> i32
A mask of the low n bits: n ones in the least significant positions.
mask_low(0) is 0 and mask_low(32) is -1 (all ones). The second case is why this exists as a function: the obvious (1 << n) - 1 gives 0 at n == 32, because WebAssembly masks the shift count to 5 bits and 1 << 32 is 1. Counts above 32 also answer all-ones rather than wrapping around to a small mask.
- Parameters
- n — how many low bits to set, clamped to
0..=32
- Returns
- a mask with the low
n bits set
- See also
i32.bit_range
Source
func i32.mask_low(self: i32) -> i32 {
if (self <= 0) { return 0; }
if (self >= 32) { return -1; }
return (1 << self) - 1;
}
func i32.bit_range(self: i32, offset: i32, width: i32) -> i32
Extracts width bits starting at bit offset, as an unsigned value.
The extracted field is shifted down to bit 0 and zero-extended, so a 4-bit field of all ones reads as 15, never as -1.
An offset or width outside 0..=32, or a field extending past bit 31, yields 0 rather than trapping or reading adjacent bits.
- Parameters
- offset — the index of the field's lowest bit
- width — how many bits the field occupies
- See also
i32.set_bit_range, i32.mask_low
Source
func i32.bit_range(self: i32, offset: i32, width: i32) -> i32 {
if (offset < 0 || width <= 0 || offset >= 32 || offset + width > 32) { return 0; }
return (self >>> offset) & width.mask_low();
}
func i32.set_bit_range(self: i32, offset: i32, width: i32, value: i32) -> i32
Replaces width bits at bit offset with the low width bits of value.
Bits of value above width are discarded rather than corrupting neighbouring fields, which is the whole reason to use this over hand-rolled shifting.
An out-of-range offset/width returns self unchanged.
- Parameters
- offset — the index of the field's lowest bit
- width — how many bits the field occupies
- value — the new field contents, taken from its low
width bits
- See also
i32.bit_range
Source
func i32.set_bit_range(self: i32, offset: i32, width: i32, value: i32) -> i32 {
if (offset < 0 || width <= 0 || offset >= 32 || offset + width > 32) { return self; }
let mask: i32 = width.mask_low() << offset;
return (self & ~mask) | ((value << offset) & mask);
}
func i32.bit(self: i32, index: i32) -> i32
Whether bit index is set.
An index outside 0..=31 answers 0 rather than consulting a wrapped bit, which is what a bare (self >> index) & 1 would do.
- Parameters
- index — which bit to test, from 0 (least significant)
- Returns
1 when the bit is set, 0 otherwise
- See also
i32.with_bit
Source
func i32.bit(self: i32, index: i32) -> i32 {
if (index < 0 || index > 31) { return 0; }
return (self >>> index) & 1;
}
func i32.with_bit(self: i32, index: i32, value: i32) -> i32
Returns self with bit index set to value's truth.
An index outside 0..=31 returns self unchanged.
- Parameters
- index — which bit to write, from 0 (least significant)
- value — zero clears the bit; any nonzero value sets it
- See also
i32.bit
Source
func i32.with_bit(self: i32, index: i32, value: i32) -> i32 {
if (index < 0 || index > 31) { return self; }
if (value != 0) { return self | (1 << index); }
return self & ~(1 << index);
}
func i32.reverse_bits(self: i32) -> i32
Reverses the order of all 32 bits.
The standard five-step butterfly: swap adjacent bits, then pairs, then nibbles, then bytes, then halves. Constant time, no loop, no table.
- Returns
self with bit i moved to bit 31 - i
- See also
i32.bswap
Source
func i32.reverse_bits(self: i32) -> i32 {
var v: i32 = self;
v = ((v >>> 1) & 0x55555555) | ((v & 0x55555555) << 1);
v = ((v >>> 2) & 0x33333333) | ((v & 0x33333333) << 2);
v = ((v >>> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
v = ((v >>> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
return (v >>> 16) | (v << 16);
}
func i32.bswap(self: i32) -> i32
Reverses byte order, converting between little- and big-endian.
The conversion is its own inverse, so one function serves both directions.
- Returns
self with its four bytes in the opposite order
- See also
i32.reverse_bits
Source
func i32.bswap(self: i32) -> i32 {
let v: i32 = ((self >>> 8) & 0x00FF00FF) | ((self & 0x00FF00FF) << 8);
return (v >>> 16) | (v << 16);
}
func i64.bswap(self: i64) -> i64
Reverses byte order of a 64-bit value.
- Returns
self with its eight bytes in the opposite order
Source
func i64.bswap(self: i64) -> i64 {
var v: i64 = self;
v = ((v >>> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8);
v = ((v >>> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16);
return (v >>> 32) | (v << 32);
}
func i32.clo(self: i32) -> i32
Counts leading one bits, the complement of clz.
- Returns
- the number of ones above the highest zero bit,
0..=32
- See also
i32.clz (core)
Source
func i32.clo(self: i32) -> i32 {
return (~self).clz();
}
func i32.cto(self: i32) -> i32
Counts trailing one bits, the complement of ctz.
- Returns
- the number of ones below the lowest zero bit,
0..=32
- See also
i32.ctz (core)
Source
func i32.cto(self: i32) -> i32 {
return (~self).ctz();
}
func i32.parity(self: i32) -> i32
The parity of the set bits.
- Returns
1 when an odd number of bits are set, 0 when even
- See also
i32.popcnt (core)
Source
func i32.parity(self: i32) -> i32 {
return self.popcnt() & 1;
}
func i32.lowest_bit(self: i32) -> i32
Isolates the lowest set bit, clearing every other bit.
Returns 0 for an input of zero. This is the classic x & -x, correct at every input including i32 minimum.
- Returns
- a value with only
self's lowest set bit
- See also
i32.clear_lowest_bit
Source
func i32.lowest_bit(self: i32) -> i32 {
return self & (0 - self);
}
func i32.clear_lowest_bit(self: i32) -> i32
Clears the lowest set bit, leaving every other bit.
Returns 0 for an input of zero. Iterating this is the standard way to visit exactly the set bits of a word, one per iteration.
- Returns
self with its lowest set bit cleared
- See also
i32.lowest_bit
Source
func i32.clear_lowest_bit(self: i32) -> i32 {
return self & (self - 1);
}
func i32.highest_bit(self: i32) -> i32
Isolates the highest set bit: the largest power of two not exceeding self.
Returns 0 for zero. Treats self as unsigned, so a negative input answers the sign bit, -2147483648.
- Returns
- a value with only
self's highest set bit
Source
func i32.highest_bit(self: i32) -> i32 {
if (self == 0) { return 0; }
return 1 << (31 - self.clz());
}
func i32.shl_wide(self: i32, count: i32) -> i32
A left shift that is not masked modulo the operand width.
1 << 32 is 1 in WebAssembly, because the shift count is masked to five bits. This returns 0 for any count at or above 32, which is what the arithmetic meaning of a shift says it should be. A negative count also yields 0.
- Parameters
- count — how far to shift
- See also
i32.shr_wide
Source
func i32.shl_wide(self: i32, count: i32) -> i32 {
if (count < 0 || count >= 32) { return 0; }
return self << count;
}
func i32.shr_wide(self: i32, count: i32) -> i32
An unsigned right shift that is not masked modulo the operand width.
Returns 0 for any count at or above 32, rather than >>>'s masked behaviour.
- Parameters
- count — how far to shift
- See also
i32.shl_wide
Source
func i32.shr_wide(self: i32, count: i32) -> i32 {
if (count < 0 || count >= 32) { return 0; }
return self >>> count;
}
func i32.sign_extend(self: i32, width: i32) -> i32
Sign-extends the low width bits, treating bit width - 1 as the sign.
Turns a value read out of a narrow packed field back into a signed i32: a 4-bit field holding 0b1111 sign-extends to -1 rather than staying 15.
A width outside 1..=32 returns self unchanged.
- Parameters
- width — how many bits are significant
- See also
i32.bit_range
Source
func i32.sign_extend(self: i32, width: i32) -> i32 {
if (width < 1 || width > 32) { return self; }
let shift: i32 = 32 - width;
return (self << shift) >> shift;
}
func i32.byte(self: i32, index: i32) -> i32
Extracts byte index as an unsigned value in 0..=255.
An index outside 0..=3 yields 0.
- Parameters
- index — which byte, 0 being least significant
- See also
i32.pack_bytes
Source
func i32.byte(self: i32, index: i32) -> i32 {
if (index < 0 || index > 3) { return 0; }
return (self >>> (index * 8)) & 0xFF;
}