RawOrder
:= [After, Before, Same]
Builtin.Num :: # (opaque)
:= [After, Before, Same]
Builtin.Num.Range(num) :: # (opaque)
A reusable numeric range description. Range syntax constructs one of these
values; call Range.iter to iterate it, or use it directly in a for loop.
lower anchors the range's members even when direction is From. The
upper_bound therefore always applies to upper, and Range.step_by
replaces step rather than composing it with the previous step.
custom : {
lower : num,
upper : num,
step : num,
upper_bound : [Exclusive, Inclusive],
direction : [To, From],
len_if_known : [Known(U64), Unknown],
} -> Range(num)Construct a range description for a builtin or third-party numeric type.
A Known length must be the exact number of values the range will yield.
Return the exact range length when it fits in a U64.
step_by : Range(num), num -> Range(num) where [num.range_len_if_known : num, num, num, [Exclusive, Inclusive] -> [Known(U64), Unknown]]Replace this range's absolute step. The new step is expressed in the
range's numeric type so third-party numbers need no U64 conversion.
iter : Range(num) -> Iter(num) where [num.range_iter : num, num, num, [Exclusive, Inclusive], [To, From], [Known(U64), Unknown] -> Iter(num)]Iterate this range in its stored direction.
iter_rev : Range(num) -> Iter(num)
where [
num.range_exclusive_to : num, num -> Range(num),
num.range_inclusive_to : num, num -> Range(num),
num.range_exclusive_from : num, num -> Range(num),
num.range_inclusive_from : num, num -> Range(num),
num.range_len_if_known : num, num, num, [Exclusive, Inclusive] -> [Known(U64), Unknown],
num.range_iter : num, num, num, [Exclusive, Inclusive], [To, From], [Known(U64), Unknown] -> Iter(num),
]Iterate this range in the opposite direction. Reversal reconstructs the
corresponding range through the numeric type's _to/_from methods,
which means a type can support forward ranges without claiming that its
ranges are exactly reversible.
Builtin.Num.Numeral :: # (opaque)
Builtin.Num.U8 :: # (opaque)
The highest value representable by a U8, which is 255.
expect U8.highest == 255The lowest value representable by a U8, which is 0.
expect U8.lowest == 0Convert a U8 to its decimal string representation.
expect U8.to_str(42) == "42"Returns Bool.True if the value is 0.
expect U8.is_zero(0)
expect !U8.is_zero(7)Returns Bool.True if the two values are equal.
expect U8.is_eq(3, 3)
expect !U8.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect U8.is_gt(5, 3)
expect !U8.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect U8.is_gte(3, 3)
expect !U8.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect U8.is_lt(3, 5)
expect !U8.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect U8.is_lte(3, 3)
expect !U8.is_lte(5, 3)Compare two U8 values and return their ordering.
expect U8.order_relative_to(1, 2) == Before
expect U8.order_relative_to(2, 2) == Same
expect U8.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect U8.is_even(4)
expect !U8.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect U8.is_odd(5)
expect !U8.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect U8.is_multiple_of(12, 3)
expect U8.is_multiple_of(0, 0)
expect !U8.is_multiple_of(5, 0)Returns the greater of two U8 values.
expect U8.max(5, 3) == 5Returns the smaller of two U8 values.
expect U8.min(5, 3) == 3Add two U8 values.
expect U8.plus(2, 3) == 5Add two U8 values, wrapping on overflow.
expect U8.plus_wrap(U8.highest, 1) == 0Return Bool.True if adding these values would overflow a U8.
Add two U8 values, saturating at U8.highest on overflow rather than wrapping around.
expect U8.plus_saturated(U8.highest, 1) == U8.highest
expect U8.plus_saturated(2, 3) == 5Subtract the second U8 from the first.
expect U8.minus(5, 3) == 2Subtract the second U8 from the first, wrapping on overflow.
expect U8.minus_wrap(0, 1) == U8.highestReturn Bool.True if subtracting these values would overflow a U8.
Subtract the second U8 from the first, saturating at the nearest bound on overflow.
expect U8.minus_saturated(0, 1) == 0
expect U8.minus_saturated(5, 3) == 2Multiply two U8 values.
expect U8.times(4, 3) == 12Multiply two U8 values, wrapping on overflow.
expect U8.times_wrap(U8.highest, 2) == U8.highest - 1Return Bool.True if multiplying these values would overflow a U8.
Multiply two U8 values, saturating at the nearest bound on overflow.
expect U8.times_saturated(U8.highest, 2) == U8.highest
expect U8.times_saturated(4, 3) == 12Raise the first U8 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect U8.pow_try(2, 3) == Ok(8)
expect U8.pow_try(U8.highest, 2) == Err(Overflow)Divide the first U8 by the second, returning Err(DivByZero)
instead of crashing if the divisor is zero.
Divide the first U8 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect U8.div_ceil_try(7, 2) == Ok(4)
expect U8.div_ceil_try(1, 0) == Err(DivByZero)Return the remainder of dividing the first U8 by the second.
expect U8.rem_by(7, 3) == 1Return the absolute difference between two U8 values.
expect U8.abs_diff(2, 5) == 3
expect U8.abs_diff(5, 2) == 3Shift the bits of a U8 to the left by the given number of positions.
Bits shifted past the most significant bit are discarded, and zeros
are shifted in on the right. Each left shift by one is equivalent to
multiplying by 2 (modulo 256).
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U8.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect U8.shl_wrap(0b0000_0001, 8) == 0b0000_0001Shift the bits of a U8 to the right by the given number of positions.
Bits shifted past the least significant bit are discarded, and zeros
are shifted in on the left. Each right shift by one is equivalent to
integer division by 2. For unsigned integers this behaves the same as
U8.shr_zf_wrap.
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U8.shr_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U8.shr_wrap(0b0010_0000, 8) == 0b0010_0000Shift the bits of a U8 to the right by the given number of positions,
filling the vacated high bits with zeros ("zero-fill"). For unsigned
integers this behaves the same as U8.shr_wrap.
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U8.shr_zf_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U8.shr_zf_wrap(0b0010_0000, 8) == 0b0010_0000Returns the bitwise AND of two U8 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U8.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000Returns the bitwise OR of two U8 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U8.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110Returns the bitwise XOR of two U8 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U8.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110Returns the bitwise NOT of a U8 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0.
# 0b0000_0101 == 5
# 0b1111_1010 == 250
expect U8.bitwise_not(0b0000_0101) == 0b1111_1010Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# 0b0000_0001 == 1
expect U8.count_leading_zero_bits(0b0000_0001) == 7
# 0b0000_0000 == 0
expect U8.count_leading_zero_bits(0b0000_0000) == 8This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# 0b0000_1000 == 8
expect U8.count_trailing_zero_bits(0b0000_1000) == 3
# 0b0000_0000 == 0
expect U8.count_trailing_zero_bits(0b0000_0000) == 8This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# 0b0000_1011 == 11
expect U8.count_one_bits(0b0000_1011) == 3
# 0b0000_0000 == 0
expect U8.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Convert a numeric literal into a U8. This is the hook the
compiler uses when a literal is given type U8; most code should
parse user text with U8.from_str instead.
Parse a U8 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar U8.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
U8, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect U8.from_str_prefix("42,rest") == Ok({ value: 42, rest: ",rest" })
expect U8.from_str_prefix("300,") == Err(OutOfRange)
expect U8.from_str_prefix("abc") == Err(NotANumber)Parse a U8 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as U8.from_str_prefix.
The returned rest is a slice of the original list.
expect U8.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })
expect U8.from_utf8_prefix([0x33, 0x30, 0x30]) == Err(OutOfRange)Iterator of integers beginning with this U8 and ending with the other U8.
(Use U8.until instead to end with the other U8 minus one.)
Returns an empty iterator if this U8 is greater than the other.
expect Iter.fold(U8.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(U8.to(3, 3), [], |acc, item| acc.append(item)) == [3]
expect Iter.fold(U8.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this U8 and ending with the other U8 minus one.
(Use U8.to instead to end with the other U8 exactly, instead of minus one.)
Returns an empty iterator if this U8 is greater than or equal to the other.
expect Iter.fold(U8.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(U8.until(3, 3), [], |acc, item| acc.append(item)) == []
expect Iter.fold(U8.until(5, 2), [], |acc, item| acc.append(item)) == []Encode a U8 using a format that provides encode_u8
Decode a U8 using a format that provides decode_u8
Builtin.Num.I8 :: # (opaque)
The highest value representable by an I8, which is 127.
expect I8.highest == 127The lowest value representable by an I8, which is -128.
expect I8.lowest == -128Convert an I8 to its decimal string representation.
expect I8.to_str(42) == "42"
expect I8.to_str(-42) == "-42"Returns Bool.True if the value is 0.
expect I8.is_zero(0)
expect !I8.is_zero(7)Returns Bool.True if the value is less than 0.
expect I8.is_negative(-3)
expect !I8.is_negative(0)Returns Bool.True if the value is greater than 0.
expect I8.is_positive(3)
expect !I8.is_positive(0)Returns Bool.True if the two values are equal.
expect I8.is_eq(3, 3)
expect !I8.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect I8.is_gt(5, 3)
expect !I8.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect I8.is_gte(3, 3)
expect !I8.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect I8.is_lt(3, 5)
expect !I8.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect I8.is_lte(3, 3)
expect !I8.is_lte(5, 3)Compare two I8 values and return their ordering.
expect I8.order_relative_to(1, 2) == Before
expect I8.order_relative_to(2, 2) == Same
expect I8.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect I8.is_even(4)
expect !I8.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect I8.is_odd(5)
expect !I8.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect I8.is_multiple_of(12, 3)
expect I8.is_multiple_of(0, 0)
expect !I8.is_multiple_of(5, 0)
expect I8.is_multiple_of(I8.lowest, -1)Returns the greater of two I8 values.
expect I8.max(5, 3) == 5
expect I8.max(-3, -1) == -1Returns the smaller of two I8 values.
expect I8.min(5, 3) == 3
expect I8.min(-3, -1) == -3Add two I8 values.
expect I8.plus(2, 3) == 5Add two I8 values, wrapping on overflow.
expect I8.plus_wrap(I8.highest, 1) == I8.lowestReturn Bool.True if adding these values would overflow an I8.
Add two I8 values, saturating at I8.highest or I8.lowest on overflow rather than wrapping around.
expect I8.plus_saturated(I8.highest, 1) == I8.highest
expect I8.plus_saturated(I8.lowest, -1) == I8.lowest
expect I8.plus_saturated(2, 3) == 5Subtract the second I8 from the first.
expect I8.minus(5, 3) == 2Subtract the second I8 from the first, wrapping on overflow.
expect I8.minus_wrap(I8.lowest, 1) == I8.highestReturn Bool.True if subtracting these values would overflow an I8.
Subtract the second I8 from the first, saturating at the nearest bound on overflow.
expect I8.minus_saturated(I8.lowest, 1) == I8.lowest
expect I8.minus_saturated(I8.highest, -1) == I8.highest
expect I8.minus_saturated(5, 3) == 2Multiply two I8 values.
expect I8.times(4, 3) == 12Multiply two I8 values, wrapping on overflow.
expect I8.times_wrap(I8.lowest, -1) == I8.lowestReturn Bool.True if multiplying these values would overflow an I8.
Multiply two I8 values, saturating at the nearest bound on overflow.
expect I8.times_saturated(I8.highest, 2) == I8.highest
expect I8.times_saturated(I8.lowest, 2) == I8.lowest
expect I8.times_saturated(4, 3) == 12Raise the first I8 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect I8.pow_try(2, 3) == Ok(8)
expect I8.pow_try(I8.highest, 2) == Err(Overflow)
expect I8.pow_try(2, -1) == Err(Underflow)
expect I8.pow_try(-1, -3) == Ok(-1)Divide the first I8 by the second. Returns Err(DivByZero) if
the divisor is zero, or Err(Overflow) for I8.lowest / -1.
Divide the first I8 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect I8.div_ceil_try(7, 2) == Ok(4)
expect I8.div_ceil_try(1, 0) == Err(DivByZero)
expect I8.div_ceil_try(I8.lowest, -1) == Err(Overflow)Divide the first I8 by the second, rounding the result toward negative infinity.
expect I8.div_floor_by(7, 2) == 3
expect I8.div_floor_by(-7, 2) == -4
expect I8.div_floor_by(7, -2) == -4
expect I8.div_floor_by(-7, -2) == 3Divide the first I8 by the second, truncating toward zero.
expect I8.div_trunc_by(7, 2) == 3
expect I8.div_trunc_by(-7, 2) == -3Return the remainder of dividing the first I8 by the second. The
sign of the result matches the sign of the dividend.
expect I8.rem_by(7, 3) == 1
expect I8.rem_by(-7, 3) == -1Return the modulus of the first I8 by the second. The modulus is
the remainder left after dividing one number by another, and is
always in the range 0 up to (but not including) the absolute value
of the divisor. Unlike I8.rem_by, the sign of the result matches the
sign of the divisor.
expect I8.mod_by(7, 3) == 1
expect I8.mod_by(-7, 3) == 2Shift the bits of an I8 to the left by the given number of
positions. Bits shifted past the most significant bit are discarded,
and zeros are shifted in on the right.
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I8.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect I8.shl_wrap(0b0000_0001, 8) == 0b0000_0001Shift the bits of an I8 to the right by the given number of
positions, preserving the sign ("arithmetic shift"). The sign bit
is shifted in on the left, so negative values remain negative. Each
right shift by one is equivalent to integer division by 2 (rounding
toward negative infinity).
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I8.shr_wrap(0b0101_0000, 3) == 0b0000_1010
# -32 == 0b1110_0000
# -8 == 0b1111_1000
expect I8.shr_wrap(-32, 2) == -8
# 0b0010_0000 == 32
expect I8.shr_wrap(0b0010_0000, 8) == 0b0010_0000Shift the bits of an I8 to the right by the given number of
positions, filling the vacated high bits with zeros ("zero-fill").
The count is taken modulo 8, so shifting by 8 leaves the value unchanged and shifting by 9 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I8.shr_zf_wrap(0b0101_0000, 3) == 0b0000_1010
# -1 == 0b1111_1111
# 0b0000_1111 == 15
expect I8.shr_zf_wrap(-1, 4) == 0b0000_1111
# 0b0010_0000 == 32
expect I8.shr_zf_wrap(0b0010_0000, 8) == 0b0010_0000Returns the bitwise AND of two I8 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I8.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000
# -8 == 0b1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I8.bitwise_and(-8, 0b0001_1111) == 0b0001_1000Returns the bitwise OR of two I8 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I8.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110
# -8 == 0b1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1101
expect I8.bitwise_or(-8, 0b0000_0101) == -3Returns the bitwise XOR of two I8 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I8.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110
# -1 == 0b1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1010
expect I8.bitwise_xor(-1, 0b0000_0101) == -6Returns the bitwise NOT of an I8 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0. For signed integers
this is equivalent to -value - 1.
# 0b0000_0101 == 5
# -6 == 0b1111_1010
expect I8.bitwise_not(0b0000_0101) == -6Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# -1 == 0b1111_1111
expect I8.count_leading_zero_bits(-1) == 0
# 0b0000_0000 == 0
expect I8.count_leading_zero_bits(0b0000_0000) == 8This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# -8 == 0b1111_1000
expect I8.count_trailing_zero_bits(-8) == 3
# 0b0000_0000 == 0
expect I8.count_trailing_zero_bits(0b0000_0000) == 8This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# -1 == 0b1111_1111
expect I8.count_one_bits(-1) == 8
# 0b0000_0000 == 0
expect I8.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Iterator of integers beginning with this I8 and ending with the other I8.
(Use I8.until instead to end with the other I8 minus one.)
Returns an empty iterator if this I8 is greater than the other.
expect Iter.fold(I8.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(I8.to(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0, 1]
expect Iter.fold(I8.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this I8 and ending with the other I8 minus one.
(Use I8.to instead to end with the other I8 exactly, instead of minus one.)
Returns an empty iterator if this I8 is greater than or equal to the other.
expect Iter.fold(I8.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(I8.until(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0]
expect Iter.fold(I8.until(5, 2), [], |acc, item| acc.append(item)) == []Build an I8 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
I8 (-128 to 127), or if any item is not a valid digit. The
result is always non-negative; to build a negative value, I8.negate
the result.
expect I8.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into an I8. This is the hook the
compiler uses when a literal is given type I8; most code should
parse user text with I8.from_str instead.
Parse a I8 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar I8.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
I8, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect I8.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect I8.from_str_prefix("-7abc") == Ok({ value: -7, rest: "abc" })
expect I8.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect I8.from_str_prefix("abc") == Err(NotANumber)Parse a I8 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as I8.from_str_prefix.
The returned rest is a slice of the original list.
expect I8.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Encode an I8 using a format that provides encode_i8
Decode an I8 using a format that provides decode_i8
Builtin.Num.U16 :: # (opaque)
The highest value representable by a U16, which is 65535.
expect U16.highest == 65535The lowest value representable by a U16, which is 0.
expect U16.lowest == 0Convert a U16 to its decimal string representation.
expect U16.to_str(42) == "42"Returns Bool.True if the value is 0.
expect U16.is_zero(0)
expect !U16.is_zero(7)Returns Bool.True if the two values are equal.
expect U16.is_eq(3, 3)
expect !U16.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect U16.is_gt(5, 3)
expect !U16.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect U16.is_gte(3, 3)
expect !U16.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect U16.is_lt(3, 5)
expect !U16.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect U16.is_lte(3, 3)
expect !U16.is_lte(5, 3)Compare two U16 values and return their ordering.
expect U16.order_relative_to(1, 2) == Before
expect U16.order_relative_to(2, 2) == Same
expect U16.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect U16.is_even(4)
expect !U16.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect U16.is_odd(5)
expect !U16.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect U16.is_multiple_of(12, 3)
expect U16.is_multiple_of(0, 0)
expect !U16.is_multiple_of(5, 0)Returns the greater of two U16 values.
expect U16.max(5, 3) == 5Returns the smaller of two U16 values.
expect U16.min(5, 3) == 3Add two U16 values.
expect U16.plus(2, 3) == 5Add two U16 values, wrapping on overflow.
expect U16.plus_wrap(U16.highest, 1) == 0Return Bool.True if adding these values would overflow a U16.
Add two U16 values, saturating at U16.highest on overflow rather than wrapping around.
expect U16.plus_saturated(U16.highest, 1) == U16.highest
expect U16.plus_saturated(2, 3) == 5Subtract the second U16 from the first.
expect U16.minus(5, 3) == 2Subtract the second U16 from the first, wrapping on overflow.
expect U16.minus_wrap(0, 1) == U16.highestReturn Bool.True if subtracting these values would overflow a U16.
Subtract the second U16 from the first, saturating at the nearest bound on overflow.
expect U16.minus_saturated(0, 1) == 0
expect U16.minus_saturated(5, 3) == 2Multiply two U16 values.
expect U16.times(4, 3) == 12Multiply two U16 values, wrapping on overflow.
expect U16.times_wrap(U16.highest, 2) == U16.highest - 1Return Bool.True if multiplying these values would overflow a U16.
Multiply two U16 values, saturating at the nearest bound on overflow.
expect U16.times_saturated(U16.highest, 2) == U16.highest
expect U16.times_saturated(4, 3) == 12Raise the first U16 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect U16.pow_try(2, 3) == Ok(8)
expect U16.pow_try(U16.highest, 2) == Err(Overflow)Divide the first U16 by the second, returning Err(DivByZero)
instead of crashing if the divisor is zero.
Divide the first U16 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect U16.div_ceil_try(7, 2) == Ok(4)
expect U16.div_ceil_try(1, 0) == Err(DivByZero)Divide the first U16 by the second, rounding the result toward negative infinity.
For unsigned integers this behaves the same as U16.div_by.
expect U16.div_floor_by(7, 2) == 3Divide the first U16 by the second, truncating down (toward zero). For unsigned
integers this behaves the same as U16.div_by.
expect U16.div_trunc_by(7, 2) == 3Return the remainder of dividing the first U16 by the second.
expect U16.rem_by(7, 3) == 1Return the modulus of the first U16 by the second. The modulus is the
remainder left after dividing one number by another, and is always in
the range 0 up to (but not including) the divisor. For unsigned
integers this behaves the same as U16.rem_by.
expect U16.mod_by(7, 3) == 1Return the absolute difference between two U16 values.
expect U16.abs_diff(2, 5) == 3
expect U16.abs_diff(5, 2) == 3Shift the bits of a U16 to the left by the given number of positions.
Bits shifted past the most significant bit are discarded, and zeros
are shifted in on the right. Each left shift by one is equivalent to
multiplying by 2 (modulo 65536).
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U16.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect U16.shl_wrap(0b0000_0001, 16) == 0b0000_0001Shift the bits of a U16 to the right by the given number of positions.
Bits shifted past the least significant bit are discarded, and zeros
are shifted in on the left. Each right shift by one is equivalent to
integer division by 2. For unsigned integers this behaves the same as
U16.shr_zf_wrap.
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U16.shr_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U16.shr_wrap(0b0010_0000, 16) == 0b0010_0000Shift the bits of a U16 to the right by the given number of positions,
filling the vacated high bits with zeros ("zero-fill"). For unsigned
integers this behaves the same as U16.shr_wrap.
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U16.shr_zf_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U16.shr_zf_wrap(0b0010_0000, 16) == 0b0010_0000Returns the bitwise AND of two U16 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U16.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000Returns the bitwise OR of two U16 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U16.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110Returns the bitwise XOR of two U16 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U16.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110Returns the bitwise NOT of a U16 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1010 == 65530
expect U16.bitwise_not(0b0000_0101) == 0b1111_1111_1111_1010Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# 0b0000_0001 == 1
expect U16.count_leading_zero_bits(0b0000_0001) == 15
# 0b0000_0000 == 0
expect U16.count_leading_zero_bits(0b0000_0000) == 16This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# 0b0000_1000 == 8
expect U16.count_trailing_zero_bits(0b0000_1000) == 3
# 0b0000_0000 == 0
expect U16.count_trailing_zero_bits(0b0000_0000) == 16This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# 0b0000_1011 == 11
expect U16.count_one_bits(0b0000_1011) == 3
# 0b0000_0000 == 0
expect U16.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian U16 from the two bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 2 <= List.len(bytes).
expect U16.from_le_bytes([0x34, 0x12], 0) == Ok(0x1234)
expect U16.from_le_bytes([0x34], 0) == Err(OutOfBounds)Iterator of integers beginning with this U16 and ending with the other U16.
(Use U16.until instead to end with the other U16 minus one.)
Returns an empty iterator if this U16 is greater than the other.
expect Iter.fold(U16.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(U16.to(3, 3), [], |acc, item| acc.append(item)) == [3]
expect Iter.fold(U16.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this U16 and ending with the other U16 minus one.
(Use U16.to instead to end with the other U16 exactly, instead of minus one.)
Returns an empty iterator if this U16 is greater than or equal to the other.
expect Iter.fold(U16.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(U16.until(3, 3), [], |acc, item| acc.append(item)) == []
expect Iter.fold(U16.until(5, 2), [], |acc, item| acc.append(item)) == []Convert a numeric literal into a U16. This is the hook the
compiler uses when a literal is given type U16; most code should
parse user text with U16.from_str instead.
Parse a U16 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar U16.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
U16, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect U16.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect U16.from_str_prefix("-5") == Err(OutOfRange)
expect U16.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect U16.from_str_prefix("abc") == Err(NotANumber)Parse a U16 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as U16.from_str_prefix.
The returned rest is a slice of the original list.
expect U16.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Builtin.Num.I16 :: # (opaque)
The highest value representable by an I16, which is 32767.
expect I16.highest == 32767The lowest value representable by an I16, which is -32768.
expect I16.lowest == -32768Convert an I16 to its decimal string representation.
expect I16.to_str(42) == "42"
expect I16.to_str(-42) == "-42"Returns Bool.True if the value is 0.
expect I16.is_zero(0)
expect !I16.is_zero(7)Returns Bool.True if the value is less than 0.
expect I16.is_negative(-3)
expect !I16.is_negative(0)Returns Bool.True if the value is greater than 0.
expect I16.is_positive(3)
expect !I16.is_positive(0)Returns Bool.True if the two values are equal.
expect I16.is_eq(3, 3)
expect !I16.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect I16.is_gt(5, 3)
expect !I16.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect I16.is_gte(3, 3)
expect !I16.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect I16.is_lt(3, 5)
expect !I16.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect I16.is_lte(3, 3)
expect !I16.is_lte(5, 3)Compare two I16 values and return their ordering.
expect I16.order_relative_to(1, 2) == Before
expect I16.order_relative_to(2, 2) == Same
expect I16.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect I16.is_even(4)
expect !I16.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect I16.is_odd(5)
expect !I16.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect I16.is_multiple_of(12, 3)
expect I16.is_multiple_of(0, 0)
expect !I16.is_multiple_of(5, 0)
expect I16.is_multiple_of(I16.lowest, -1)Returns the greater of two I16 values.
expect I16.max(5, 3) == 5
expect I16.max(-3, -1) == -1Returns the smaller of two I16 values.
expect I16.min(5, 3) == 3
expect I16.min(-3, -1) == -3Add two I16 values.
expect I16.plus(2, 3) == 5Add two I16 values, wrapping on overflow.
expect I16.plus_wrap(I16.highest, 1) == I16.lowestReturn Bool.True if adding these values would overflow an I16.
Add two I16 values, saturating at I16.highest or I16.lowest on overflow rather than wrapping around.
expect I16.plus_saturated(I16.highest, 1) == I16.highest
expect I16.plus_saturated(I16.lowest, -1) == I16.lowest
expect I16.plus_saturated(2, 3) == 5Subtract the second I16 from the first.
expect I16.minus(5, 3) == 2Subtract the second I16 from the first, wrapping on overflow.
expect I16.minus_wrap(I16.lowest, 1) == I16.highestReturn Bool.True if subtracting these values would overflow an I16.
Subtract the second I16 from the first, saturating at the nearest bound on overflow.
expect I16.minus_saturated(I16.lowest, 1) == I16.lowest
expect I16.minus_saturated(I16.highest, -1) == I16.highest
expect I16.minus_saturated(5, 3) == 2Multiply two I16 values.
expect I16.times(4, 3) == 12Multiply two I16 values, wrapping on overflow.
expect I16.times_wrap(I16.lowest, -1) == I16.lowestReturn Bool.True if multiplying these values would overflow an I16.
Multiply two I16 values, saturating at the nearest bound on overflow.
expect I16.times_saturated(I16.highest, 2) == I16.highest
expect I16.times_saturated(I16.lowest, 2) == I16.lowest
expect I16.times_saturated(4, 3) == 12Raise the first I16 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect I16.pow_try(2, 3) == Ok(8)
expect I16.pow_try(I16.highest, 2) == Err(Overflow)
expect I16.pow_try(2, -1) == Err(Underflow)
expect I16.pow_try(-1, -3) == Ok(-1)Divide the first I16 by the second. Returns Err(DivByZero) if
the divisor is zero, or Err(Overflow) for I16.lowest / -1.
Divide the first I16 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect I16.div_ceil_try(7, 2) == Ok(4)
expect I16.div_ceil_try(1, 0) == Err(DivByZero)
expect I16.div_ceil_try(I16.lowest, -1) == Err(Overflow)Divide the first I16 by the second, rounding the result toward negative infinity.
expect I16.div_floor_by(7, 2) == 3
expect I16.div_floor_by(-7, 2) == -4
expect I16.div_floor_by(7, -2) == -4
expect I16.div_floor_by(-7, -2) == 3Divide the first I16 by the second, truncating toward zero.
expect I16.div_trunc_by(7, 2) == 3
expect I16.div_trunc_by(-7, 2) == -3Return the remainder of dividing the first I16 by the second. The
sign of the result matches the sign of the dividend.
expect I16.rem_by(7, 3) == 1
expect I16.rem_by(-7, 3) == -1Return the modulus of the first I16 by the second. The modulus is
the remainder left after dividing one number by another, and is
always in the range 0 up to (but not including) the absolute value
of the divisor. Unlike I16.rem_by, the sign of the result matches the
sign of the divisor.
expect I16.mod_by(7, 3) == 1
expect I16.mod_by(-7, 3) == 2Shift the bits of an I16 to the left by the given number of
positions. Bits shifted past the most significant bit are discarded,
and zeros are shifted in on the right.
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I16.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect I16.shl_wrap(0b0000_0001, 16) == 0b0000_0001Shift the bits of an I16 to the right by the given number of
positions, preserving the sign ("arithmetic shift"). The sign bit
is shifted in on the left, so negative values remain negative. Each
right shift by one is equivalent to integer division by 2 (rounding
toward negative infinity).
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I16.shr_wrap(0b0101_0000, 3) == 0b0000_1010
# -32 == 0b1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1000
expect I16.shr_wrap(-32, 2) == -8
# 0b0010_0000 == 32
expect I16.shr_wrap(0b0010_0000, 16) == 0b0010_0000Shift the bits of an I16 to the right by the given number of
positions, filling the vacated high bits with zeros ("zero-fill").
The count is taken modulo 16, so shifting by 16 leaves the value unchanged and shifting by 17 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I16.shr_zf_wrap(0b0101_0000, 3) == 0b0000_1010
# -1 == 0b1111_1111_1111_1111
# 0b0000_1111 == 15
expect I16.shr_zf_wrap(-1, 12) == 0b0000_1111
# 0b0010_0000 == 32
expect I16.shr_zf_wrap(0b0010_0000, 16) == 0b0010_0000Returns the bitwise AND of two I16 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I16.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000
# -8 == 0b1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I16.bitwise_and(-8, 0b0001_1111) == 0b0001_1000Returns the bitwise OR of two I16 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I16.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110
# -8 == 0b1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1101
expect I16.bitwise_or(-8, 0b0000_0101) == -3Returns the bitwise XOR of two I16 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I16.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110
# -1 == 0b1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1010
expect I16.bitwise_xor(-1, 0b0000_0101) == -6Returns the bitwise NOT of an I16 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0. For signed integers
this is equivalent to -value - 1.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1010
expect I16.bitwise_not(0b0000_0101) == -6Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# -1 == 0b1111_1111_1111_1111
expect I16.count_leading_zero_bits(-1) == 0
# 0b0000_0000 == 0
expect I16.count_leading_zero_bits(0b0000_0000) == 16This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# -8 == 0b1111_1111_1111_1000
expect I16.count_trailing_zero_bits(-8) == 3
# 0b0000_0000 == 0
expect I16.count_trailing_zero_bits(0b0000_0000) == 16This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# -1 == 0b1111_1111_1111_1111
expect I16.count_one_bits(-1) == 16
# 0b0000_0000 == 0
expect I16.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian I16 from the two bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 2 <= List.len(bytes).
expect I16.from_le_bytes([0x00, 0x80], 0) == Ok(I16.lowest)
expect I16.from_le_bytes([0x00], 0) == Err(OutOfBounds)Iterator of integers beginning with this I16 and ending with the other I16.
(Use I16.until instead to end with the other I16 minus one.)
Returns an empty iterator if this I16 is greater than the other.
expect Iter.fold(I16.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(I16.to(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0, 1]
expect Iter.fold(I16.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this I16 and ending with the other I16 minus one.
(Use I16.to instead to end with the other I16 exactly, instead of minus one.)
Returns an empty iterator if this I16 is greater than or equal to the other.
expect Iter.fold(I16.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(I16.until(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0]
expect Iter.fold(I16.until(5, 2), [], |acc, item| acc.append(item)) == []Build an I16 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
I16 (-32768 to 32767), or if any item is not a valid digit.
The result is always non-negative; to build a negative value, I16.negate
the result.
expect I16.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into an I16. This is the hook the
compiler uses when a literal is given type I16; most code should
parse user text with I16.from_str instead.
Parse a I16 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar I16.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
I16, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect I16.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect I16.from_str_prefix("-7abc") == Ok({ value: -7, rest: "abc" })
expect I16.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect I16.from_str_prefix("abc") == Err(NotANumber)Parse a I16 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as I16.from_str_prefix.
The returned rest is a slice of the original list.
expect I16.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Builtin.Num.U32 :: # (opaque)
The highest value representable by a U32, which is 4294967295.
expect U32.highest == 4294967295The lowest value representable by a U32, which is 0.
expect U32.lowest == 0Convert a U32 to its decimal string representation.
expect U32.to_str(42) == "42"Returns Bool.True if the value is 0.
expect U32.is_zero(0)
expect !U32.is_zero(7)Returns Bool.True if the two values are equal.
expect U32.is_eq(3, 3)
expect !U32.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect U32.is_gt(5, 3)
expect !U32.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect U32.is_gte(3, 3)
expect !U32.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect U32.is_lt(3, 5)
expect !U32.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect U32.is_lte(3, 3)
expect !U32.is_lte(5, 3)Compare two U32 values and return their ordering.
expect U32.order_relative_to(1, 2) == Before
expect U32.order_relative_to(2, 2) == Same
expect U32.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect U32.is_even(4)
expect !U32.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect U32.is_odd(5)
expect !U32.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect U32.is_multiple_of(12, 3)
expect U32.is_multiple_of(0, 0)
expect !U32.is_multiple_of(5, 0)Returns the greater of two U32 values.
expect U32.max(5, 3) == 5Returns the smaller of two U32 values.
expect U32.min(5, 3) == 3Add two U32 values.
expect U32.plus(2, 3) == 5Add two U32 values, wrapping on overflow.
expect U32.plus_wrap(U32.highest, 1) == 0Return Bool.True if adding these values would overflow a U32.
Add two U32 values, saturating at U32.highest on overflow rather than wrapping around.
expect U32.plus_saturated(U32.highest, 1) == U32.highest
expect U32.plus_saturated(2, 3) == 5Subtract the second U32 from the first.
expect U32.minus(5, 3) == 2Subtract the second U32 from the first, wrapping on overflow.
expect U32.minus_wrap(0, 1) == U32.highestReturn Bool.True if subtracting these values would overflow a U32.
Subtract the second U32 from the first, saturating at the nearest bound on overflow.
expect U32.minus_saturated(0, 1) == 0
expect U32.minus_saturated(5, 3) == 2Multiply two U32 values.
expect U32.times(4, 3) == 12Multiply two U32 values, wrapping on overflow.
expect U32.times_wrap(U32.highest, 2) == U32.highest - 1Return Bool.True if multiplying these values would overflow a U32.
Multiply two U32 values, saturating at the nearest bound on overflow.
expect U32.times_saturated(U32.highest, 2) == U32.highest
expect U32.times_saturated(4, 3) == 12Raise the first U32 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect U32.pow_try(2, 3) == Ok(8)
expect U32.pow_try(U32.highest, 2) == Err(Overflow)Divide the first U32 by the second, returning Err(DivByZero)
instead of crashing if the divisor is zero.
Divide the first U32 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect U32.div_ceil_try(7, 2) == Ok(4)
expect U32.div_ceil_try(1, 0) == Err(DivByZero)Divide the first U32 by the second, rounding the result toward negative infinity.
For unsigned integers this behaves the same as U32.div_by.
expect U32.div_floor_by(7, 2) == 3Divide the first U32 by the second, truncating down (toward zero). For unsigned
integers this behaves the same as U32.div_by.
expect U32.div_trunc_by(7, 2) == 3Return the remainder of dividing the first U32 by the second.
expect U32.rem_by(7, 3) == 1Return the modulus of the first U32 by the second. The modulus is the
remainder left after dividing one number by another, and is always in
the range 0 up to (but not including) the divisor. For unsigned
integers this behaves the same as U32.rem_by.
expect U32.mod_by(7, 3) == 1Return the absolute difference between two U32 values.
expect U32.abs_diff(2, 5) == 3
expect U32.abs_diff(5, 2) == 3Shift the bits of a U32 to the left by the given number of positions.
Bits shifted past the most significant bit are discarded, and zeros
are shifted in on the right. Each left shift by one is equivalent to
multiplying by 2 (modulo 4294967296).
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U32.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect U32.shl_wrap(0b0000_0001, 32) == 0b0000_0001Shift the bits of a U32 to the right by the given number of positions.
Bits shifted past the least significant bit are discarded, and zeros
are shifted in on the left. Each right shift by one is equivalent to
integer division by 2. For unsigned integers this behaves the same as
U32.shr_zf_wrap.
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U32.shr_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U32.shr_wrap(0b0010_0000, 32) == 0b0010_0000Shift the bits of a U32 to the right by the given number of positions,
filling the vacated high bits with zeros ("zero-fill"). For unsigned
integers this behaves the same as U32.shr_wrap.
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U32.shr_zf_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U32.shr_zf_wrap(0b0010_0000, 32) == 0b0010_0000Returns the bitwise AND of two U32 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U32.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000Returns the bitwise OR of two U32 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U32.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110Returns the bitwise XOR of two U32 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U32.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110Returns the bitwise NOT of a U32 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1111_1111_1111_1111_1010 == 4294967290
expect U32.bitwise_not(0b0000_0101) == 0b1111_1111_1111_1111_1111_1111_1111_1010Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# 0b0000_0001 == 1
expect U32.count_leading_zero_bits(0b0000_0001) == 31
# 0b0000_0000 == 0
expect U32.count_leading_zero_bits(0b0000_0000) == 32This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# 0b0000_1000 == 8
expect U32.count_trailing_zero_bits(0b0000_1000) == 3
# 0b0000_0000 == 0
expect U32.count_trailing_zero_bits(0b0000_0000) == 32This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# 0b0000_1011 == 11
expect U32.count_one_bits(0b0000_1011) == 3
# 0b0000_0000 == 0
expect U32.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian U32 from the four bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 4 <= List.len(bytes).
expect U32.from_le_bytes([0x78, 0x56, 0x34, 0x12], 0) == Ok(0x12345678)
expect U32.from_le_bytes([0x78, 0x56, 0x34], 0) == Err(OutOfBounds)Iterator of integers beginning with this U32 and ending with the other U32.
(Use U32.until instead to end with the other U32 minus one.)
Returns an empty iterator if this U32 is greater than the other.
expect Iter.fold(U32.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(U32.to(3, 3), [], |acc, item| acc.append(item)) == [3]
expect Iter.fold(U32.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this U32 and ending with the other U32 minus one.
(Use U32.to instead to end with the other U32 exactly, instead of minus one.)
Returns an empty iterator if this U32 is greater than or equal to the other.
expect Iter.fold(U32.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(U32.until(3, 3), [], |acc, item| acc.append(item)) == []
expect Iter.fold(U32.until(5, 2), [], |acc, item| acc.append(item)) == []Convert a numeric literal into a U32. This is the hook the
compiler uses when a literal is given type U32; most code should
parse user text with U32.from_str instead.
Parse a U32 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar U32.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
U32, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect U32.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect U32.from_str_prefix("-5") == Err(OutOfRange)
expect U32.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect U32.from_str_prefix("abc") == Err(NotANumber)Parse a U32 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as U32.from_str_prefix.
The returned rest is a slice of the original list.
expect U32.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Convert a U32 to an I32, wrapping on overflow. Values from 0 to
2147483647 are preserved; values from 2147483648 to 4294967295
wrap into the negative range -2147483648 to -1 (two's complement
reinterpretation of the bits).
expect U32.to_i32_wrap(42) == 42
expect U32.to_i32_wrap(3000000000) == -1294967296Builtin.Num.I32 :: # (opaque)
The highest value representable by an I32, which is 2147483647.
expect I32.highest == 2147483647The lowest value representable by an I32, which is -2147483648.
expect I32.lowest == -2147483648Convert an I32 to its decimal string representation.
expect I32.to_str(42) == "42"
expect I32.to_str(-42) == "-42"Returns Bool.True if the value is 0.
expect I32.is_zero(0)
expect !I32.is_zero(7)Returns Bool.True if the value is less than 0.
expect I32.is_negative(-3)
expect !I32.is_negative(0)Returns Bool.True if the value is greater than 0.
expect I32.is_positive(3)
expect !I32.is_positive(0)Returns Bool.True if the two values are equal.
expect I32.is_eq(3, 3)
expect !I32.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect I32.is_gt(5, 3)
expect !I32.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect I32.is_gte(3, 3)
expect !I32.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect I32.is_lt(3, 5)
expect !I32.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect I32.is_lte(3, 3)
expect !I32.is_lte(5, 3)Compare two I32 values and return their ordering.
expect I32.order_relative_to(1, 2) == Before
expect I32.order_relative_to(2, 2) == Same
expect I32.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect I32.is_even(4)
expect !I32.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect I32.is_odd(5)
expect !I32.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect I32.is_multiple_of(12, 3)
expect I32.is_multiple_of(0, 0)
expect !I32.is_multiple_of(5, 0)
expect I32.is_multiple_of(I32.lowest, -1)Returns the greater of two I32 values.
expect I32.max(5, 3) == 5
expect I32.max(-3, -1) == -1Returns the smaller of two I32 values.
expect I32.min(5, 3) == 3
expect I32.min(-3, -1) == -3Add two I32 values.
expect I32.plus(2, 3) == 5Add two I32 values, wrapping on overflow.
expect I32.plus_wrap(I32.highest, 1) == I32.lowestReturn Bool.True if adding these values would overflow an I32.
Add two I32 values, saturating at I32.highest or I32.lowest on overflow rather than wrapping around.
expect I32.plus_saturated(I32.highest, 1) == I32.highest
expect I32.plus_saturated(I32.lowest, -1) == I32.lowest
expect I32.plus_saturated(2, 3) == 5Subtract the second I32 from the first.
expect I32.minus(5, 3) == 2Subtract the second I32 from the first, wrapping on overflow.
expect I32.minus_wrap(I32.lowest, 1) == I32.highestReturn Bool.True if subtracting these values would overflow an I32.
Subtract the second I32 from the first, saturating at the nearest bound on overflow.
expect I32.minus_saturated(I32.lowest, 1) == I32.lowest
expect I32.minus_saturated(I32.highest, -1) == I32.highest
expect I32.minus_saturated(5, 3) == 2Multiply two I32 values.
expect I32.times(4, 3) == 12Multiply two I32 values, wrapping on overflow.
expect I32.times_wrap(I32.lowest, -1) == I32.lowestReturn Bool.True if multiplying these values would overflow an I32.
Multiply two I32 values, saturating at the nearest bound on overflow.
expect I32.times_saturated(I32.highest, 2) == I32.highest
expect I32.times_saturated(I32.lowest, 2) == I32.lowest
expect I32.times_saturated(4, 3) == 12Raise the first I32 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect I32.pow_try(2, 3) == Ok(8)
expect I32.pow_try(I32.highest, 2) == Err(Overflow)
expect I32.pow_try(2, -1) == Err(Underflow)
expect I32.pow_try(-1, -3) == Ok(-1)Divide the first I32 by the second. Returns Err(DivByZero) if
the divisor is zero, or Err(Overflow) for I32.lowest / -1.
Divide the first I32 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect I32.div_ceil_try(7, 2) == Ok(4)
expect I32.div_ceil_try(1, 0) == Err(DivByZero)
expect I32.div_ceil_try(I32.lowest, -1) == Err(Overflow)Divide the first I32 by the second, rounding the result toward negative infinity.
expect I32.div_floor_by(7, 2) == 3
expect I32.div_floor_by(-7, 2) == -4
expect I32.div_floor_by(7, -2) == -4
expect I32.div_floor_by(-7, -2) == 3Divide the first I32 by the second, truncating toward zero.
expect I32.div_trunc_by(7, 2) == 3
expect I32.div_trunc_by(-7, 2) == -3Return the remainder of dividing the first I32 by the second. The
sign of the result matches the sign of the dividend.
expect I32.rem_by(7, 3) == 1
expect I32.rem_by(-7, 3) == -1Return the modulus of the first I32 by the second. The modulus is
the remainder left after dividing one number by another, and is
always in the range 0 up to (but not including) the absolute value
of the divisor. Unlike I32.rem_by, the sign of the result matches the
sign of the divisor.
expect I32.mod_by(7, 3) == 1
expect I32.mod_by(-7, 3) == 2Shift the bits of an I32 to the left by the given number of
positions. Bits shifted past the most significant bit are discarded,
and zeros are shifted in on the right.
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I32.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect I32.shl_wrap(0b0000_0001, 32) == 0b0000_0001Shift the bits of an I32 to the right by the given number of
positions, preserving the sign ("arithmetic shift"). The sign bit
is shifted in on the left, so negative values remain negative. Each
right shift by one is equivalent to integer division by 2 (rounding
toward negative infinity).
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I32.shr_wrap(0b0101_0000, 3) == 0b0000_1010
# -32 == 0b1111_1111_1111_1111_1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
expect I32.shr_wrap(-32, 2) == -8
# 0b0010_0000 == 32
expect I32.shr_wrap(0b0010_0000, 32) == 0b0010_0000Shift the bits of an I32 to the right by the given number of
positions, filling the vacated high bits with zeros ("zero-fill").
The count is taken modulo 32, so shifting by 32 leaves the value unchanged and shifting by 33 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I32.shr_zf_wrap(0b0101_0000, 3) == 0b0000_1010
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_1111 == 15
expect I32.shr_zf_wrap(-1, 28) == 0b0000_1111
# 0b0010_0000 == 32
expect I32.shr_zf_wrap(0b0010_0000, 32) == 0b0010_0000Returns the bitwise AND of two I32 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I32.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I32.bitwise_and(-8, 0b0001_1111) == 0b0001_1000Returns the bitwise OR of two I32 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I32.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1111_1111_1111_1111_1101
expect I32.bitwise_or(-8, 0b0000_0101) == -3Returns the bitwise XOR of two I32 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I32.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1010
expect I32.bitwise_xor(-1, 0b0000_0101) == -6Returns the bitwise NOT of an I32 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0. For signed integers
this is equivalent to -value - 1.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1010
expect I32.bitwise_not(0b0000_0101) == -6Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
expect I32.count_leading_zero_bits(-1) == 0
# 0b0000_0000 == 0
expect I32.count_leading_zero_bits(0b0000_0000) == 32This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
expect I32.count_trailing_zero_bits(-8) == 3
# 0b0000_0000 == 0
expect I32.count_trailing_zero_bits(0b0000_0000) == 32This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
expect I32.count_one_bits(-1) == 32
# 0b0000_0000 == 0
expect I32.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian I32 from the four bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 4 <= List.len(bytes).
expect I32.from_le_bytes([0x00, 0x00, 0x00, 0x80], 0) == Ok(I32.lowest)
expect I32.from_le_bytes([0x00, 0x00, 0x00], 0) == Err(OutOfBounds)Iterator of integers beginning with this I32 and ending with the other I32.
(Use I32.until instead to end with the other I32 minus one.)
Returns an empty iterator if this I32 is greater than the other.
expect Iter.fold(I32.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(I32.to(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0, 1]
expect Iter.fold(I32.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this I32 and ending with the other I32 minus one.
(Use I32.to instead to end with the other I32 exactly, instead of minus one.)
Returns an empty iterator if this I32 is greater than or equal to the other.
expect Iter.fold(I32.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(I32.until(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0]
expect Iter.fold(I32.until(5, 2), [], |acc, item| acc.append(item)) == []Build an I32 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
I32 (-2147483648 to 2147483647), or if any item is not a valid digit.
The result is always non-negative; to build a negative value, I32.negate
the result.
expect I32.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into an I32. This is the hook the
compiler uses when a literal is given type I32; most code should
parse user text with I32.from_str instead.
Parse a I32 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar I32.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
I32, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect I32.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect I32.from_str_prefix("-7abc") == Ok({ value: -7, rest: "abc" })
expect I32.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect I32.from_str_prefix("abc") == Err(NotANumber)Parse a I32 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as I32.from_str_prefix.
The returned rest is a slice of the original list.
expect I32.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Builtin.Num.U64 :: # (opaque)
The highest value representable by a U64, which is
18446744073709551615.
expect U64.highest == 18446744073709551615The lowest value representable by a U64, which is 0.
expect U64.lowest == 0Convert a U64 to its decimal string representation.
expect U64.to_str(42) == "42"Returns Bool.True if the value is 0.
expect U64.is_zero(0)
expect !U64.is_zero(7)Returns Bool.True if the two values are equal.
expect U64.is_eq(3, 3)
expect !U64.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect U64.is_gt(5, 3)
expect !U64.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect U64.is_gte(3, 3)
expect !U64.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect U64.is_lt(3, 5)
expect !U64.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect U64.is_lte(3, 3)
expect !U64.is_lte(5, 3)Compare two U64 values and return their ordering.
expect U64.order_relative_to(1, 2) == Before
expect U64.order_relative_to(2, 2) == Same
expect U64.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect U64.is_even(4)
expect !U64.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect U64.is_odd(5)
expect !U64.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect U64.is_multiple_of(12, 3)
expect U64.is_multiple_of(0, 0)
expect !U64.is_multiple_of(5, 0)Returns the greater of two U64 values.
expect U64.max(5, 3) == 5Returns the smaller of two U64 values.
expect U64.min(5, 3) == 3Add two U64 values.
expect U64.plus(2, 3) == 5Add two U64 values, wrapping on overflow.
expect U64.plus_wrap(U64.highest, 1) == 0Return Bool.True if adding these values would overflow a U64.
Add two U64 values, saturating at U64.highest on overflow rather than wrapping around.
expect U64.plus_saturated(U64.highest, 1) == U64.highest
expect U64.plus_saturated(2, 3) == 5Subtract the second U64 from the first.
expect U64.minus(5, 3) == 2Subtract the second U64 from the first, wrapping on overflow.
expect U64.minus_wrap(0, 1) == U64.highestReturn Bool.True if subtracting these values would overflow a U64.
Subtract the second U64 from the first, saturating at the nearest bound on overflow.
expect U64.minus_saturated(0, 1) == 0
expect U64.minus_saturated(5, 3) == 2Multiply two U64 values.
expect U64.times(4, 3) == 12Multiply two U64 values, wrapping on overflow.
expect U64.times_wrap(U64.highest, 2) == U64.highest - 1Return Bool.True if multiplying these values would overflow a U64.
Multiply two U64 values, saturating at the nearest bound on overflow.
expect U64.times_saturated(U64.highest, 2) == U64.highest
expect U64.times_saturated(4, 3) == 12Raise the first U64 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect U64.pow_try(2, 3) == Ok(8)
expect U64.pow_try(U64.highest, 2) == Err(Overflow)Divide the first U64 by the second, returning Err(DivByZero)
instead of crashing if the divisor is zero.
Divide the first U64 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect U64.div_ceil_try(7, 2) == Ok(4)
expect U64.div_ceil_try(1, 0) == Err(DivByZero)Divide the first U64 by the second, rounding the result toward negative infinity.
For unsigned integers this behaves the same as U64.div_by.
expect U64.div_floor_by(7, 2) == 3Divide the first U64 by the second, truncating down (toward zero). For unsigned
integers this behaves the same as U64.div_by.
expect U64.div_trunc_by(7, 2) == 3Return the remainder of dividing the first U64 by the second.
expect U64.rem_by(7, 3) == 1Return the modulus of the first U64 by the second. The modulus is the
remainder left after dividing one number by another, and is always in
the range 0 up to (but not including) the divisor. For unsigned
integers this behaves the same as U64.rem_by.
expect U64.mod_by(7, 3) == 1Return the absolute difference between two U64 values.
expect U64.abs_diff(2, 5) == 3
expect U64.abs_diff(5, 2) == 3Shift the bits of a U64 to the left by the given number of positions.
Bits shifted past the most significant bit are discarded, and zeros
are shifted in on the right. Each left shift by one is equivalent to
multiplying by 2 (modulo 2^64).
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U64.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect U64.shl_wrap(0b0000_0001, 64) == 0b0000_0001Shift the bits of a U64 to the right by the given number of positions.
Bits shifted past the least significant bit are discarded, and zeros
are shifted in on the left. Each right shift by one is equivalent to
integer division by 2. For unsigned integers this behaves the same as
U64.shr_zf_wrap.
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U64.shr_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U64.shr_wrap(0b0010_0000, 64) == 0b0010_0000Shift the bits of a U64 to the right by the given number of positions,
filling the vacated high bits with zeros ("zero-fill"). For unsigned
integers this behaves the same as U64.shr_wrap.
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U64.shr_zf_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U64.shr_zf_wrap(0b0010_0000, 64) == 0b0010_0000Returns the bitwise AND of two U64 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U64.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000Returns the bitwise OR of two U64 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U64.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110Returns the bitwise XOR of two U64 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U64.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110Returns the bitwise NOT of a U64 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010 == 18446744073709551610
expect U64.bitwise_not(0b0000_0101) == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# 0b0000_0001 == 1
expect U64.count_leading_zero_bits(0b0000_0001) == 63
# 0b0000_0000 == 0
expect U64.count_leading_zero_bits(0b0000_0000) == 64This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# 0b0000_1000 == 8
expect U64.count_trailing_zero_bits(0b0000_1000) == 3
# 0b0000_0000 == 0
expect U64.count_trailing_zero_bits(0b0000_0000) == 64This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# 0b0000_1011 == 11
expect U64.count_one_bits(0b0000_1011) == 3
# 0b0000_0000 == 0
expect U64.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian U64 from the eight bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 8 <= List.len(bytes).
expect U64.from_le_bytes([1, 0, 0, 0, 0, 0, 0, 0], 0) == Ok(1)
expect U64.from_le_bytes([1, 0, 0, 0, 0, 0, 0], 0) == Err(OutOfBounds)Append this U64's count lowest bytes to the end of the list,
least significant byte first—that is, in
little-endian byte
order, which is what the le in the name refers to.
This is the writing mirror of U64.from_le_bytes.
Returns Err(OutOfBounds) when
count > 8, since a U64 has 8 bytes.
expect 0x1234.U64.append_le_bytes_to([], 2) == Ok([0x34, 0x12])
expect 0xFF.U64.append_le_bytes_to([9], 1) == Ok([9, 0xFF])
expect 1.U64.append_le_bytes_to([], 9) == Err(OutOfBounds)Iterator of integers beginning with this U64 and ending with the other U64.
(Use U64.until instead to end with the other U64 minus one.)
Returns an empty iterator if this U64 is greater than the other.
expect Iter.fold(U64.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(U64.to(3, 3), [], |acc, item| acc.append(item)) == [3]
expect Iter.fold(U64.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this U64 and ending with the other U64 minus one.
(Use U64.to instead to end with the other U64 exactly, instead of minus one.)
Returns an empty iterator if this U64 is greater than or equal to the other.
expect Iter.fold(U64.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(U64.until(3, 3), [], |acc, item| acc.append(item)) == []
expect Iter.fold(U64.until(5, 2), [], |acc, item| acc.append(item)) == []Build a U64 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in a
U64 (0 to 18446744073709551615), or if any item is not a valid digit.
expect U64.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into a U64. This is the hook the
compiler uses when a literal is given type U64; most code should
parse user text with U64.from_str instead.
Parse a U64 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar U64.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
U64, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect U64.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect U64.from_str_prefix("-5") == Err(OutOfRange)
expect U64.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect U64.from_str_prefix("abc") == Err(NotANumber)Parse a U64 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as U64.from_str_prefix.
The returned rest is a slice of the original list.
expect U64.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Convert a U64 to an I64, wrapping on overflow. Values from 0 to
9223372036854775807 are preserved; values from 9223372036854775808
to 18446744073709551615 wrap into the negative range
-9223372036854775808 to -1 (two's complement reinterpretation of
the bits).
expect U64.to_i64_wrap(42) == 42
expect U64.to_i64_wrap(10000000000000000000) == -8446744073709551616Builtin.Num.I64 :: # (opaque)
The highest value representable by an I64, which is
9223372036854775807.
expect I64.highest == 9223372036854775807The lowest value representable by an I64, which is
-9223372036854775808.
expect I64.lowest == -9223372036854775808Convert an I64 to its decimal string representation.
expect I64.to_str(42) == "42"
expect I64.to_str(-42) == "-42"Returns Bool.True if the value is 0.
expect I64.is_zero(0)
expect !I64.is_zero(7)Returns Bool.True if the value is less than 0.
expect I64.is_negative(-3)
expect !I64.is_negative(0)Returns Bool.True if the value is greater than 0.
expect I64.is_positive(3)
expect !I64.is_positive(0)Returns Bool.True if the two values are equal.
expect I64.is_eq(3, 3)
expect !I64.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect I64.is_gt(5, 3)
expect !I64.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect I64.is_gte(3, 3)
expect !I64.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect I64.is_lt(3, 5)
expect !I64.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect I64.is_lte(3, 3)
expect !I64.is_lte(5, 3)Compare two I64 values and return their ordering.
expect I64.order_relative_to(1, 2) == Before
expect I64.order_relative_to(2, 2) == Same
expect I64.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect I64.is_even(4)
expect !I64.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect I64.is_odd(5)
expect !I64.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect I64.is_multiple_of(12, 3)
expect I64.is_multiple_of(0, 0)
expect !I64.is_multiple_of(5, 0)
expect I64.is_multiple_of(I64.lowest, -1)Returns the greater of two I64 values.
expect I64.max(5, 3) == 5
expect I64.max(-3, -1) == -1Returns the smaller of two I64 values.
expect I64.min(5, 3) == 3
expect I64.min(-3, -1) == -3Add two I64 values.
expect I64.plus(2, 3) == 5Add two I64 values, wrapping on overflow.
expect I64.plus_wrap(I64.highest, 1) == I64.lowestReturn Bool.True if adding these values would overflow an I64.
Add two I64 values, saturating at I64.highest or I64.lowest on overflow rather than wrapping around.
expect I64.plus_saturated(I64.highest, 1) == I64.highest
expect I64.plus_saturated(I64.lowest, -1) == I64.lowest
expect I64.plus_saturated(2, 3) == 5Subtract the second I64 from the first.
expect I64.minus(5, 3) == 2Subtract the second I64 from the first, wrapping on overflow.
expect I64.minus_wrap(I64.lowest, 1) == I64.highestReturn Bool.True if subtracting these values would overflow an I64.
Subtract the second I64 from the first, saturating at the nearest bound on overflow.
expect I64.minus_saturated(I64.lowest, 1) == I64.lowest
expect I64.minus_saturated(I64.highest, -1) == I64.highest
expect I64.minus_saturated(5, 3) == 2Multiply two I64 values.
expect I64.times(4, 3) == 12Multiply two I64 values, wrapping on overflow.
expect I64.times_wrap(I64.lowest, -1) == I64.lowestReturn Bool.True if multiplying these values would overflow an I64.
Multiply two I64 values, saturating at the nearest bound on overflow.
expect I64.times_saturated(I64.highest, 2) == I64.highest
expect I64.times_saturated(I64.lowest, 2) == I64.lowest
expect I64.times_saturated(4, 3) == 12Raise the first I64 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect I64.pow_try(2, 3) == Ok(8)
expect I64.pow_try(I64.highest, 2) == Err(Overflow)
expect I64.pow_try(2, -1) == Err(Underflow)
expect I64.pow_try(-1, -3) == Ok(-1)Divide the first I64 by the second. Returns Err(DivByZero) if
the divisor is zero, or Err(Overflow) for I64.lowest / -1.
Divide the first I64 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect I64.div_ceil_try(7, 2) == Ok(4)
expect I64.div_ceil_try(1, 0) == Err(DivByZero)
expect I64.div_ceil_try(I64.lowest, -1) == Err(Overflow)Divide the first I64 by the second, rounding the result toward negative infinity.
expect I64.div_floor_by(7, 2) == 3
expect I64.div_floor_by(-7, 2) == -4
expect I64.div_floor_by(7, -2) == -4
expect I64.div_floor_by(-7, -2) == 3Divide the first I64 by the second, truncating toward zero.
expect I64.div_trunc_by(7, 2) == 3
expect I64.div_trunc_by(-7, 2) == -3Return the remainder of dividing the first I64 by the second. The
sign of the result matches the sign of the dividend.
expect I64.rem_by(7, 3) == 1
expect I64.rem_by(-7, 3) == -1Return the modulus of the first I64 by the second. The modulus is
the remainder left after dividing one number by another, and is
always in the range 0 up to (but not including) the absolute value
of the divisor. Unlike I64.rem_by, the sign of the result matches the
sign of the divisor.
expect I64.mod_by(7, 3) == 1
expect I64.mod_by(-7, 3) == 2Shift the bits of an I64 to the left by the given number of
positions. Bits shifted past the most significant bit are discarded,
and zeros are shifted in on the right.
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I64.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect I64.shl_wrap(0b0000_0001, 64) == 0b0000_0001Shift the bits of an I64 to the right by the given number of
positions, preserving the sign ("arithmetic shift"). The sign bit
is shifted in on the left, so negative values remain negative. Each
right shift by one is equivalent to integer division by 2 (rounding
toward negative infinity).
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I64.shr_wrap(0b0101_0000, 3) == 0b0000_1010
# -32 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
expect I64.shr_wrap(-32, 2) == -8
# 0b0010_0000 == 32
expect I64.shr_wrap(0b0010_0000, 64) == 0b0010_0000Shift the bits of an I64 to the right by the given number of
positions, filling the vacated high bits with zeros ("zero-fill").
The count is taken modulo 64, so shifting by 64 leaves the value unchanged and shifting by 65 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I64.shr_zf_wrap(0b0101_0000, 3) == 0b0000_1010
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_1111 == 15
expect I64.shr_zf_wrap(-1, 60) == 0b0000_1111
# 0b0010_0000 == 32
expect I64.shr_zf_wrap(0b0010_0000, 64) == 0b0010_0000Returns the bitwise AND of two I64 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I64.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I64.bitwise_and(-8, 0b0001_1111) == 0b0001_1000Returns the bitwise OR of two I64 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I64.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1101
expect I64.bitwise_or(-8, 0b0000_0101) == -3Returns the bitwise XOR of two I64 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I64.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010
expect I64.bitwise_xor(-1, 0b0000_0101) == -6Returns the bitwise NOT of an I64 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0. For signed integers
this is equivalent to -value - 1.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010
expect I64.bitwise_not(0b0000_0101) == -6Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
expect I64.count_leading_zero_bits(-1) == 0
# 0b0000_0000 == 0
expect I64.count_leading_zero_bits(0b0000_0000) == 64This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
expect I64.count_trailing_zero_bits(-8) == 3
# 0b0000_0000 == 0
expect I64.count_trailing_zero_bits(0b0000_0000) == 64This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
expect I64.count_one_bits(-1) == 64
# 0b0000_0000 == 0
expect I64.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian I64 from the eight bytes at the given byte
index. Returns Err(OutOfBounds) unless
index + 8 <= List.len(bytes).
expect I64.from_le_bytes([0, 0, 0, 0, 0, 0, 0, 0x80], 0) == Ok(I64.lowest)
expect I64.from_le_bytes([0, 0, 0, 0, 0, 0, 0], 0) == Err(OutOfBounds)Iterator of integers beginning with this I64 and ending with the other I64.
(Use I64.until instead to end with the other I64 minus one.)
Returns an empty iterator if this I64 is greater than the other.
expect Iter.fold(I64.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(I64.to(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0, 1]
expect Iter.fold(I64.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this I64 and ending with the other I64 minus one.
(Use I64.to instead to end with the other I64 exactly, instead of minus one.)
Returns an empty iterator if this I64 is greater than or equal to the other.
expect Iter.fold(I64.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(I64.until(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0]
expect Iter.fold(I64.until(5, 2), [], |acc, item| acc.append(item)) == []Build an I64 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
I64 (-9223372036854775808 to 9223372036854775807), or if any
item is not a valid digit. The result is always non-negative; to
build a negative value, I64.negate the result.
expect I64.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into an I64. This is the hook the
compiler uses when a literal is given type I64; most code should
parse user text with I64.from_str instead.
Parse a I64 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar I64.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
I64, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect I64.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect I64.from_str_prefix("-7abc") == Ok({ value: -7, rest: "abc" })
expect I64.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect I64.from_str_prefix("abc") == Err(NotANumber)Parse a I64 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as I64.from_str_prefix.
The returned rest is a slice of the original list.
expect I64.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Builtin.Num.U128 :: # (opaque)
The highest value representable by a U128, which is
340282366920938463463374607431768211455.
expect U128.highest == 340282366920938463463374607431768211455The lowest value representable by a U128, which is 0.
expect U128.lowest == 0Convert a U128 to its decimal string representation.
expect U128.to_str(42) == "42"Returns Bool.True if the value is 0.
expect U128.is_zero(0)
expect !U128.is_zero(7)Returns Bool.True if the two values are equal.
expect U128.is_eq(3, 3)
expect !U128.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect U128.is_gt(5, 3)
expect !U128.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect U128.is_gte(3, 3)
expect !U128.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect U128.is_lt(3, 5)
expect !U128.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect U128.is_lte(3, 3)
expect !U128.is_lte(5, 3)Compare two U128 values and return their ordering.
expect U128.order_relative_to(1, 2) == Before
expect U128.order_relative_to(2, 2) == Same
expect U128.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect U128.is_even(4)
expect !U128.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect U128.is_odd(5)
expect !U128.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect U128.is_multiple_of(12, 3)
expect U128.is_multiple_of(0, 0)
expect !U128.is_multiple_of(5, 0)Returns the greater of two U128 values.
expect U128.max(5, 3) == 5Returns the smaller of two U128 values.
expect U128.min(5, 3) == 3Add two U128 values.
expect U128.plus(2, 3) == 5Add two U128 values, wrapping on overflow.
expect U128.plus_wrap(U128.highest, 1) == 0Return Bool.True if adding these values would overflow a U128.
Add two U128 values, saturating at U128.highest on overflow rather than wrapping around.
expect U128.plus_saturated(U128.highest, 1) == U128.highest
expect U128.plus_saturated(2, 3) == 5Subtract the second U128 from the first.
expect U128.minus(5, 3) == 2Subtract the second U128 from the first, wrapping on overflow.
expect U128.minus_wrap(0, 1) == U128.highestReturn Bool.True if subtracting these values would overflow a U128.
Subtract the second U128 from the first, saturating at the nearest bound on overflow.
expect U128.minus_saturated(0, 1) == 0
expect U128.minus_saturated(5, 3) == 2Multiply two U128 values.
expect U128.times(4, 3) == 12Multiply two U128 values, wrapping on overflow.
expect U128.times_wrap(U128.highest, 2) == U128.highest - 1Return Bool.True if multiplying these values would overflow a U128.
Multiply two U128 values, saturating at the nearest bound on overflow.
expect U128.times_saturated(U128.highest, 2) == U128.highest
expect U128.times_saturated(4, 3) == 12Raise the first U128 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect U128.pow_try(2, 3) == Ok(8)
expect U128.pow_try(U128.highest, 2) == Err(Overflow)Divide the first U128 by the second, returning Err(DivByZero)
instead of crashing if the divisor is zero.
Divide the first U128 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect U128.div_ceil_try(7, 2) == Ok(4)
expect U128.div_ceil_try(1, 0) == Err(DivByZero)Divide the first U128 by the second, rounding the result toward negative infinity.
For unsigned integers this behaves the same as U128.div_by.
expect U128.div_floor_by(7, 2) == 3Divide the first U128 by the second, truncating down (toward zero). For unsigned
integers this behaves the same as U128.div_by.
expect U128.div_trunc_by(7, 2) == 3Return the remainder of dividing the first U128 by the second.
expect U128.rem_by(7, 3) == 1Return the modulus of the first U128 by the second. The modulus is the
remainder left after dividing one number by another, and is always in
the range 0 up to (but not including) the divisor. For unsigned
integers this behaves the same as U128.rem_by.
expect U128.mod_by(7, 3) == 1Return the absolute difference between two U128 values.
expect U128.abs_diff(2, 5) == 3
expect U128.abs_diff(5, 2) == 3Shift the bits of a U128 to the left by the given number of positions.
Bits shifted past the most significant bit are discarded, and zeros
are shifted in on the right. Each left shift by one is equivalent to
multiplying by 2 (modulo 2^128).
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U128.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect U128.shl_wrap(0b0000_0001, 128) == 0b0000_0001Shift the bits of a U128 to the right by the given number of positions.
Bits shifted past the least significant bit are discarded, and zeros
are shifted in on the left. Each right shift by one is equivalent to
integer division by 2. For unsigned integers this behaves the same as
U128.shr_zf_wrap.
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U128.shr_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U128.shr_wrap(0b0010_0000, 128) == 0b0010_0000Shift the bits of a U128 to the right by the given number of positions,
filling the vacated high bits with zeros ("zero-fill"). For unsigned
integers this behaves the same as U128.shr_wrap.
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U128.shr_zf_wrap(0b1010_0000, 3) == 0b0001_0100
# 0b0010_0000 == 32
expect U128.shr_zf_wrap(0b0010_0000, 128) == 0b0010_0000Returns the bitwise AND of two U128 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U128.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000Returns the bitwise OR of two U128 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U128.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110Returns the bitwise XOR of two U128 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U128.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110Returns the bitwise NOT of a U128 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0.
# 0b0000_0101 == 5
# 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFA == 0b1111_1111_…_1111_1010
expect U128.bitwise_not(0b0000_0101) == 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFACount the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# 0b0000_0001 == 1
expect U128.count_leading_zero_bits(0b0000_0001) == 127
# 0b0000_0000 == 0
expect U128.count_leading_zero_bits(0b0000_0000) == 128This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# 0b0000_1000 == 8
expect U128.count_trailing_zero_bits(0b0000_1000) == 3
# 0b0000_0000 == 0
expect U128.count_trailing_zero_bits(0b0000_0000) == 128This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# 0b0000_1011 == 11
expect U128.count_one_bits(0b0000_1011) == 3
# 0b0000_0000 == 0
expect U128.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian U128 from the sixteen bytes at the given
byte index. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
expect U128.from_le_bytes(List.repeat(0.U8, 16), 0) == Ok(0)
expect U128.from_le_bytes(List.repeat(0.U8, 15), 0) == Err(OutOfBounds)Iterator of integers beginning with this U128 and ending with the other U128.
(Use U128.until instead to end with the other U128 minus one.)
Returns an empty iterator if this U128 is greater than the other.
expect Iter.fold(U128.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(U128.to(3, 3), [], |acc, item| acc.append(item)) == [3]
expect Iter.fold(U128.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this U128 and ending with the other U128 minus one.
(Use U128.to instead to end with the other U128 exactly, instead of minus one.)
Returns an empty iterator if this U128 is greater than or equal to the other.
expect Iter.fold(U128.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(U128.until(3, 3), [], |acc, item| acc.append(item)) == []
expect Iter.fold(U128.until(5, 2), [], |acc, item| acc.append(item)) == []Build a U128 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in a
U128 (0 to 340282366920938463463374607431768211455), or if any
item is not a valid digit.
expect U128.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into a U128. This is the hook the
compiler uses when a literal is given type U128; most code should
parse user text with U128.from_str instead.
Parse a U128 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar U128.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
U128, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect U128.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect U128.from_str_prefix("-5") == Err(OutOfRange)
expect U128.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect U128.from_str_prefix("abc") == Err(NotANumber)Parse a U128 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as U128.from_str_prefix.
The returned rest is a slice of the original list.
expect U128.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Convert a U128 to an I128, wrapping on overflow. Values from 0
to 170141183460469231731687303715884105727 are preserved; larger
values wrap into the negative range (two's complement reinterpretation
of the bits).
expect U128.to_i128_wrap(42) == 42
expect U128.to_i128_wrap(200000000000000000000000000000000000000) == -140282366920938463463374607431768211456Convert a U128 to an I128, returning Err(OutOfRange) if the value
does not fit. Values from 0 to 170141183460469231731687303715884105727
succeed; larger values return Err(OutOfRange).
expect U128.to_i128_try(42) == Ok(42)
expect U128.to_i128_try(200000000000000000000000000000000000000) == Err(OutOfRange)Builtin.Num.I128 :: # (opaque)
The highest value representable by an I128, which is
170141183460469231731687303715884105727.
expect I128.highest == 170141183460469231731687303715884105727The lowest value representable by an I128, which is
-170141183460469231731687303715884105728.
expect I128.lowest == -170141183460469231731687303715884105728Convert an I128 to its decimal string representation.
expect I128.to_str(42) == "42"
expect I128.to_str(-42) == "-42"Returns Bool.True if the value is 0.
expect I128.is_zero(0)
expect !I128.is_zero(7)Returns Bool.True if the value is less than 0.
expect I128.is_negative(-3)
expect !I128.is_negative(0)Returns Bool.True if the value is greater than 0.
expect I128.is_positive(3)
expect !I128.is_positive(0)Returns Bool.True if the two values are equal.
expect I128.is_eq(3, 3)
expect !I128.is_eq(3, 4)Returns Bool.True if the first value is greater than the second.
expect I128.is_gt(5, 3)
expect !I128.is_gt(3, 3)Returns Bool.True if the first value is greater than or equal to the second.
expect I128.is_gte(3, 3)
expect !I128.is_gte(2, 3)Returns Bool.True if the first value is less than the second.
expect I128.is_lt(3, 5)
expect !I128.is_lt(3, 3)Returns Bool.True if the first value is less than or equal to the second.
expect I128.is_lte(3, 3)
expect !I128.is_lte(5, 3)Compare two I128 values and return their ordering.
expect I128.order_relative_to(1, 2) == Before
expect I128.order_relative_to(2, 2) == Same
expect I128.order_relative_to(3, 2) == AfterReturns Bool.True if the value is evenly divisible by 2.
expect I128.is_even(4)
expect !I128.is_even(5)Returns Bool.True if the value is not evenly divisible by 2.
expect I128.is_odd(5)
expect !I128.is_odd(4)Returns Bool.True if the first value is a multiple of the second.
A zero divisor returns Bool.True only when the first value is also zero.
expect I128.is_multiple_of(12, 3)
expect I128.is_multiple_of(0, 0)
expect !I128.is_multiple_of(5, 0)
expect I128.is_multiple_of(I128.lowest, -1)Returns the greater of two I128 values.
expect I128.max(5, 3) == 5
expect I128.max(-3, -1) == -1Returns the smaller of two I128 values.
expect I128.min(5, 3) == 3
expect I128.min(-3, -1) == -3Add two I128 values.
expect I128.plus(2, 3) == 5Add two I128 values, wrapping on overflow.
expect I128.plus_wrap(I128.highest, 1) == I128.lowestReturn Bool.True if adding these values would overflow an I128.
Add two I128 values, saturating at I128.highest or I128.lowest on overflow rather than wrapping around.
expect I128.plus_saturated(I128.highest, 1) == I128.highest
expect I128.plus_saturated(I128.lowest, -1) == I128.lowest
expect I128.plus_saturated(2, 3) == 5Subtract the second I128 from the first.
expect I128.minus(5, 3) == 2Subtract the second I128 from the first, wrapping on overflow.
expect I128.minus_wrap(I128.lowest, 1) == I128.highestReturn Bool.True if subtracting these values would overflow an I128.
Subtract the second I128 from the first, saturating at the nearest bound on overflow.
expect I128.minus_saturated(I128.lowest, 1) == I128.lowest
expect I128.minus_saturated(I128.highest, -1) == I128.highest
expect I128.minus_saturated(5, 3) == 2Multiply two I128 values.
expect I128.times(4, 3) == 12Multiply two I128 values, wrapping on overflow.
expect I128.times_wrap(I128.lowest, -1) == I128.lowestReturn Bool.True if multiplying these values would overflow an I128.
Multiply two I128 values, saturating at the nearest bound on overflow.
expect I128.times_saturated(I128.highest, 2) == I128.highest
expect I128.times_saturated(I128.lowest, 2) == I128.lowest
expect I128.times_saturated(4, 3) == 12Raise the first I128 value to the power of the second.
Returns an error instead of crashing when the exact result does not fit.
expect I128.pow_try(2, 3) == Ok(8)
expect I128.pow_try(I128.highest, 2) == Err(Overflow)
expect I128.pow_try(2, -1) == Err(Underflow)
expect I128.pow_try(-1, -3) == Ok(-1)Divide the first I128 by the second. Returns Err(DivByZero) if
the divisor is zero, or Err(Overflow) for I128.lowest / -1.
Divide the first I128 by the second, rounding the result toward positive infinity.
Returns an error instead of crashing when the divisor is zero or the exact result does not fit.
expect I128.div_ceil_try(7, 2) == Ok(4)
expect I128.div_ceil_try(1, 0) == Err(DivByZero)
expect I128.div_ceil_try(I128.lowest, -1) == Err(Overflow)Divide the first I128 by the second, rounding the result toward negative infinity.
expect I128.div_floor_by(7, 2) == 3
expect I128.div_floor_by(-7, 2) == -4
expect I128.div_floor_by(7, -2) == -4
expect I128.div_floor_by(-7, -2) == 3Divide the first I128 by the second, truncating toward zero.
expect I128.div_trunc_by(7, 2) == 3
expect I128.div_trunc_by(-7, 2) == -3Return the remainder of dividing the first I128 by the second. The
sign of the result matches the sign of the dividend.
expect I128.rem_by(7, 3) == 1
expect I128.rem_by(-7, 3) == -1Return the modulus of the first I128 by the second. The modulus is
the remainder left after dividing one number by another, and is
always in the range 0 up to (but not including) the absolute value
of the divisor. Unlike I128.rem_by, the sign of the result matches the
sign of the divisor.
expect I128.mod_by(7, 3) == 1
expect I128.mod_by(-7, 3) == 2Shift the bits of an I128 to the left by the given number of
positions. Bits shifted past the most significant bit are discarded,
and zeros are shifted in on the right.
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I128.shl_wrap(0b0000_0101, 2) == 0b0001_0100
# 0b0000_0001 == 1
expect I128.shl_wrap(0b0000_0001, 128) == 0b0000_0001Shift the bits of an I128 to the right by the given number of
positions, preserving the sign ("arithmetic shift"). The sign bit
is shifted in on the left, so negative values remain negative. Each
right shift by one is equivalent to integer division by 2 (rounding
toward negative infinity).
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I128.shr_wrap(0b0101_0000, 3) == 0b0000_1010
# -32 == 0b1111_1111_…_1110_0000
# -8 == 0b1111_1111_…_1111_1000
expect I128.shr_wrap(-32, 2) == -8
# 0b0010_0000 == 32
expect I128.shr_wrap(0b0010_0000, 128) == 0b0010_0000Shift the bits of an I128 to the right by the given number of
positions, filling the vacated high bits with zeros ("zero-fill").
The count is taken modulo 128, so shifting by 128 leaves the value unchanged and shifting by 129 shifts by 1.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I128.shr_zf_wrap(0b0101_0000, 3) == 0b0000_1010
# -1 == 0b1111_1111_…_1111_1111
# 0b0000_1111 == 15
expect I128.shr_zf_wrap(-1, 124) == 0b0000_1111
# 0b0010_0000 == 32
expect I128.shr_zf_wrap(0b0010_0000, 128) == 0b0010_0000Returns the bitwise AND of two I128 values. Each bit in the result is
1 only when the corresponding bit is 1 in both inputs.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I128.bitwise_and(0b0000_1100, 0b0000_1010) == 0b0000_1000
# -8 == 0b1111_1111_…_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I128.bitwise_and(-8, 0b0001_1111) == 0b0001_1000Returns the bitwise OR of two I128 values. Each bit in the result is
1 when the corresponding bit is 1 in either input.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I128.bitwise_or(0b0000_1100, 0b0000_1010) == 0b0000_1110
# -8 == 0b1111_1111_…_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_…_1111_1101
expect I128.bitwise_or(-8, 0b0000_0101) == -3Returns the bitwise XOR of two I128 values. Each bit in the result is
1 only when the corresponding bits of the inputs differ.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I128.bitwise_xor(0b0000_1100, 0b0000_1010) == 0b0000_0110
# -1 == 0b1111_1111_…_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_…_1111_1010
expect I128.bitwise_xor(-1, 0b0000_0101) == -6Returns the bitwise NOT of an I128 value, flipping every bit so that
each 0 becomes 1 and each 1 becomes 0. For signed integers
this is equivalent to -value - 1.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_…_1111_1010
expect I128.bitwise_not(0b0000_0101) == -6Count the leading zeros: the zero bits before the first one bit, starting at the most significant bit.
# -1 == 0b1111_1111_…_1111_1111
expect I128.count_leading_zero_bits(-1) == 0
# 0b0000_0000 == 0
expect I128.count_leading_zero_bits(0b0000_0000) == 128This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the trailing zeros: the zero bits before the first one bit, starting at the least significant bit.
# -8 == 0b1111_1111_…_1111_1000
expect I128.count_trailing_zero_bits(-8) == 3
# 0b0000_0000 == 0
expect I128.count_trailing_zero_bits(0b0000_0000) == 128This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Count the ones: the one bits in the value. This is also known as population count, or popcount.
# -1 == 0b1111_1111_…_1111_1111
expect I128.count_one_bits(-1) == 128
# 0b0000_0000 == 0
expect I128.count_one_bits(0b0000_0000) == 0This counts the bits of the number's value, not its bytes in memory, so it gives the same answer on big-endian and little-endian systems.
Read a little-endian I128 from the sixteen bytes at the given
byte index. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
expect I128.from_le_bytes(List.repeat(0.U8, 16), 0) == Ok(0)
expect I128.from_le_bytes(List.repeat(0.U8, 15), 0) == Err(OutOfBounds)Iterator of integers beginning with this I128 and ending with the other I128.
(Use I128.until instead to end with the other I128 minus one.)
Returns an empty iterator if this I128 is greater than the other.
expect Iter.fold(I128.to(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3, 4]
expect Iter.fold(I128.to(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0, 1]
expect Iter.fold(I128.to(5, 2), [], |acc, item| acc.append(item)) == []Iterator of integers beginning with this I128 and ending with the other I128 minus one.
(Use I128.to instead to end with the other I128 exactly, instead of minus one.)
Returns an empty iterator if this I128 is greater than or equal to the other.
expect Iter.fold(I128.until(1, 4), [], |acc, item| acc.append(item)) == [1, 2, 3]
expect Iter.fold(I128.until(-2, 1), [], |acc, item| acc.append(item)) == [-2, -1, 0]
expect Iter.fold(I128.until(5, 2), [], |acc, item| acc.append(item)) == []Build an I128 from a list of base-10 digits, most significant first.
Each item of the list must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
I128 (-170141183460469231731687303715884105728 to
170141183460469231731687303715884105727), or if any item is not
a valid digit. The result is always non-negative; to build a negative
value, I128.negate the result.
expect I128.from_int_digits([1, 2, 3]) == Ok(123)Convert a numeric literal into an I128. This is the hook the
compiler uses when a literal is given type I128; most code should
parse user text with I128.from_str instead.
Parse a I128 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar I128.from_str
accepts: an optional sign, then 0x, 0o or 0b followed by radix digits, or
decimal digits with an optional exponent (2e5, 2e-1). Digits may be
separated by single underscores. A . is never part of an integer, so
"1.2.3" parses 1 and leaves ".2.3".
There is no backtracking: if the longest match does not fit in a
I128, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect I128.from_str_prefix("12,34") == Ok({ value: 12, rest: ",34" })
expect I128.from_str_prefix("-7abc") == Ok({ value: -7, rest: "abc" })
expect I128.from_str_prefix("0b12") == Ok({ value: 1, rest: "2" })
expect I128.from_str_prefix("abc") == Err(NotANumber)Parse a I128 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as I128.from_str_prefix.
The returned rest is a slice of the original list.
expect I128.from_utf8_prefix([0x35, 0x0D, 0xFF]) == Ok({ value: 5, rest: [0x0D, 0xFF] })Encode an I128 using a format that provides encode_i128
decode : src, fmt -> (Try(I128, err), src) where [fmt.decode_i128 : fmt, src -> (Try(I128, err), src)]Decode an I128 using a format that provides decode_i128
Builtin.Num.Dec :: # (opaque)
The highest value representable by a Dec. Dec values have 18
fixed fractional decimal places, so this is
170141183460469231731.687303715884105727.
expect Dec.highest == 170141183460469231731.687303715884105727The lowest value representable by a Dec. Dec values have 18
fixed fractional decimal places, so this is
-170141183460469231731.687303715884105728.
expect Dec.lowest == -170141183460469231731.687303715884105728Euler's number as a Dec, truncated to 18 fractional decimal
places.
The circle constant pi as a Dec, truncated to 18 fractional
decimal places.
The circle constant tau as a Dec, truncated to 18 fractional
decimal places.
Convert a Dec to its decimal string representation.
expect Dec.to_str(42.5) == "42.5"
expect Dec.to_str(-42.5) == "-42.5"Returns Bool.True if the value is 0.0.
expect Dec.is_zero(0.0)
expect !Dec.is_zero(0.1)Returns Bool.True if the value is less than 0.0.
expect Dec.is_negative(-0.1)
expect !Dec.is_negative(0.0)Returns Bool.True if the value is greater than 0.0.
expect Dec.is_positive(0.1)
expect !Dec.is_positive(0.0)Returns Bool.True if the two values are equal.
expect Dec.is_eq(3.5, 3.5)
expect !Dec.is_eq(3.5, 4.0)Returns Bool.True if the first value is greater than the second.
expect Dec.is_gt(5.0, 3.0)
expect !Dec.is_gt(3.0, 3.0)Returns Bool.True if the first value is greater than or equal to the second.
expect Dec.is_gte(3.0, 3.0)
expect !Dec.is_gte(2.0, 3.0)Returns Bool.True if the first value is less than the second.
expect Dec.is_lt(3.0, 5.0)
expect !Dec.is_lt(3.0, 3.0)Returns Bool.True if the first value is less than or equal to the second.
expect Dec.is_lte(3.0, 3.0)
expect !Dec.is_lte(5.0, 3.0)Compare two Dec values and return their ordering.
expect Dec.order_relative_to(1.0, 2.0) == Before
expect Dec.order_relative_to(2.0, 2.0) == Same
expect Dec.order_relative_to(3.0, 2.0) == AfterReturns the greater of two Dec values.
expect Dec.max(5, 3) == 5
expect Dec.max(-3, -1) == -1Returns the smaller of two Dec values.
expect Dec.min(5, 3) == 3
expect Dec.min(-3, -1) == -3Returns True if a and b are within the given tolerances of each
other: |a - b| <= max(abs, rel * max(|a|, |b|)).
rel: allowed difference as a fraction of the larger magnitude.abs: allowed difference regardless of magnitude.Dec addition and subtraction are exact, so == is usually what you
want; this helps with rounded results such as division or sqrt. It never
overflows: a difference too large for a Dec is never approximately equal.
This is not transitive, so do not use it as equality for Dict/Set keys.
Crashes unless 0 <= rel <= 1 and abs >= 0.
expect Dec.is_approx_eq(1.0, 1.01, { rel: 0.01, abs: 0.0 })
expect Dec.is_approx_eq(100.0, 109.0, { rel: 0.0, abs: 10.0 })
expect !Dec.is_approx_eq(100.0, 111.0, { rel: 0.0, abs: 10.0 })
expect !Dec.is_approx_eq(Dec.highest, Dec.lowest, { rel: 1.0, abs: 0.0 })Negate a Dec.
expect Dec.negate(3.5) == -3.5
expect Dec.negate(-3.5) == 3.5Return the absolute value of a Dec. Crashes on Dec.lowest, since
its positive magnitude does not fit in a Dec.
expect Dec.abs(3.5) == 3.5
expect Dec.abs(-3.5) == 3.5Add two Dec values.
expect Dec.plus(1.5, 2.5) == 4.0Add two Dec values, returning Err(Overflow) instead of crashing or wrapping
if the result is outside Dec.lowest through Dec.highest.
Add two Dec values, saturating at Dec.highest or Dec.lowest on overflow rather than wrapping around.
expect Dec.plus_saturated(Dec.highest, 1.0) == Dec.highest
expect Dec.plus_saturated(Dec.lowest, -1.0) == Dec.lowest
expect Dec.plus_saturated(1.5, 2.5) == 4.0Subtract the second Dec from the first.
expect Dec.minus(5.0, 3.5) == 1.5Subtract the second Dec from the first, returning
Err(Overflow) instead of crashing or wrapping if the result is outside
Dec.lowest through Dec.highest.
Subtract the second Dec from the first, saturating at the nearest bound on overflow.
expect Dec.minus_saturated(Dec.lowest, 1.0) == Dec.lowest
expect Dec.minus_saturated(Dec.highest, -1.0) == Dec.highest
expect Dec.minus_saturated(5.0, 3.5) == 1.5Multiply two Dec values, saturating at the nearest bound on overflow.
expect Dec.times_saturated(Dec.highest, 2.0) == Dec.highest
expect Dec.times_saturated(Dec.lowest, 2.0) == Dec.lowest
expect Dec.times_saturated(2.5, 4.0) == 10.0Raise a Dec to a Dec power. Results are limited to Dec's
fixed 18 fractional decimal places. Fractional exponents require a
positive base; non-positive bases with fractional exponents crash.
Negative integer exponents divide by the positive power and crash
when that division is undefined, such as 0.0 to a negative power.
Return the sine of a Dec angle in radians. This is a fixed-point
approximation limited to 18 fractional decimal places.
Return the cosine of a Dec angle in radians. This is a
fixed-point approximation limited to 18 fractional decimal places.
Return the tangent of a Dec angle in radians. This is computed as
sine divided by cosine, so it can crash if the fixed-point cosine
result is zero or the division overflows.
Return the arcsine of a Dec value in radians. Crashes if the
input is outside -1.0 through 1.0.
Return the arccosine of a Dec value in radians. Crashes if the
input is outside -1.0 through 1.0.
Return the arctangent of a Dec value in radians. This is a
fixed-point approximation limited to 18 fractional decimal places.
Return the angle of (x, y) in radians, between -pi and pi. Fixed-point approximation with 18 fractional decimal places. The origin returns zero; the negative x-axis returns positive pi.
Divide the first Dec by the second, rounding the result toward negative infinity.
expect Dec.div_floor_by(7.5, 2.0) == 3.0
expect Dec.div_floor_by(-7.5, 2.0) == -4.0Return the remainder of dividing the first Dec by the second.
The sign of the result matches the sign of the dividend.
expect Dec.rem_by(7.5, 2.0) == 1.5
expect Dec.rem_by(-7.5, 2.0) == -1.5Return the absolute difference between two Dec values.
expect Dec.abs_diff(2.5, 5.0) == 2.5
expect Dec.abs_diff(-1.5, 5.0) == 6.5Round a Dec to the nearest whole number, keeping it a Dec. Halfway
values round away from zero, matching Dec.round_to_i128.
Crashes if the result does not fit in a Dec, which only happens within
half of one of Dec.highest or Dec.lowest. Use Dec.round_try to
handle that case.
expect Dec.round(2.5) == 3.0
expect Dec.round(-2.5) == -3.0
expect Dec.round(2.4999) == 2.0Round a Dec down to the nearest whole number, toward negative infinity.
Crashes if the result does not fit in a Dec, which only happens for
values below Dec.lowest + 1. Use Dec.floor_try to handle that case.
expect Dec.floor(2.7) == 2.0
expect Dec.floor(-2.1) == -3.0Round a Dec up to the nearest whole number, toward positive infinity.
Crashes if the result does not fit in a Dec, which only happens for
values above Dec.highest - 1. Use Dec.ceiling_try to handle that case.
expect Dec.ceiling(2.1) == 3.0
expect Dec.ceiling(-2.7) == -2.0Like Dec.ceiling, but returns Err(Overflow) instead of crashing when
the result does not fit in a Dec.
expect Dec.ceiling_try(2.1) == Ok(3.0)
expect Dec.ceiling_try(Dec.highest) == Err(Overflow)Drop the fractional part of a Dec, rounding toward zero. This never
overflows.
expect Dec.trunc(2.7) == 2.0
expect Dec.trunc(-2.7) == -2.0Round a Dec to the nearest multiple of step: 0.01 for cents, 0.05
for cash rounding, 1000 for thousands.
ties chooses what happens to values exactly halfway between two
multiples: AwayFromZero rounds them away from zero, and ToEven
(banker's rounding) picks the even multiple, which avoids systematic drift
when many rounded values are summed.
Crashes if step is not positive, or if the result does not fit in a
Dec. Use Dec.round_to_try to handle overflow.
expect Dec.round_to(19.995, { step: 0.01, ties: AwayFromZero }) == 20.0
expect Dec.round_to(2.345, { step: 0.01, ties: ToEven }) == 2.34
expect Dec.round_to(7.23, { step: 0.05, ties: AwayFromZero }) == 7.25
expect Dec.round_to(1500, { step: 1000, ties: ToEven }) == 2000Like Dec.round_to, but returns Err(Overflow) instead of crashing when
the result does not fit in a Dec. Still crashes if step is not
positive.
expect Dec.round_to_try(2.345, { step: 0.01, ties: AwayFromZero }) == Ok(2.35)
expect Dec.round_to_try(Dec.highest, { step: 1000, ties: ToEven }) == Err(Overflow)Build a Dec from a list of base-10 digits, most significant
first. Each item of the list must be a digit in the range 0
to 9. Returns Err(OutOfRange) if the resulting value does not
fit in a Dec, or if any item is not a valid digit. The result is always
non-negative; to build a negative value, Dec.negate the result.
expect Dec.from_int_digits([1, 2, 3]) == Ok(123.0)Build a Dec from a tuple of (integer digits, fractional digits),
each as a list of base-10 digits most significant first. Each
item of both lists must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in a
Dec, or if any item is not a valid digit. The result is
always non-negative; to build a negative value, Dec.negate the
result.
expect Dec.from_dec_digits(([1, 2], [5])) == Ok(12.5)Convert a numeric literal into a Dec. This is the hook the
compiler uses when a literal is given type Dec; most code should
parse user text with Dec.from_str instead.
Parse a Dec from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar Dec.from_str
accepts: an optional sign, decimal digits (with single _ between digits),
an optional fraction and an optional exponent. There is no hex, inf, or nan.
There is no backtracking: if the longest match does not fit in a
Dec, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect Dec.from_str_prefix("1.5]") == Ok({ value: 1.5, rest: "]" })
expect Dec.from_str_prefix("inf") == Err(NotANumber)Parse a Dec from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as Dec.from_str_prefix.
The returned rest is a slice of the original list.
expect Dec.from_utf8_prefix([0x31, 0x2E, 0x35, 0x5D]) == Ok({ value: 1.5, rest: [0x5D] })Convert a Dec to an I8. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -128 to 127 are preserved; other values wrap by
truncating to the low 8 bits and reinterpreting them in two's
complement.
expect Dec.to_i8_wrap(42.7) == 42
expect Dec.to_i8_wrap(200.0) == -56Convert a Dec to an I16. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -32768 to 32767 are preserved; other values wrap
by truncating to the low 16 bits and reinterpreting them in two's
complement.
expect Dec.to_i16_wrap(42.5) == 42
expect Dec.to_i16_wrap(40000.0) == -25536Convert a Dec to an I16, returning Err(OutOfRange) if the
integer part does not fit. The fractional part is truncated toward
zero. Integer-part values from -32768 to 32767 succeed; other
values return Err(OutOfRange).
expect Dec.to_i16_try(42.5) == Ok(42)
expect Dec.to_i16_try(40000.0) == Err(OutOfRange)Convert a Dec to an I32. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -2147483648 to 2147483647 are preserved; other
values wrap by truncating to the low 32 bits and reinterpreting
them in two's complement.
expect Dec.to_i32_wrap(42.5) == 42
expect Dec.to_i32_wrap(3000000000.0) == -1294967296Convert a Dec to an I32, returning Err(OutOfRange) if the
integer part does not fit. The fractional part is truncated toward
zero. Integer-part values from -2147483648 to 2147483647
succeed; other values return Err(OutOfRange).
expect Dec.to_i32_try(42.5) == Ok(42)
expect Dec.to_i32_try(3000000000.0) == Err(OutOfRange)Convert a Dec to an I64. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -9223372036854775808 to 9223372036854775807 are
preserved; other values wrap by truncating to the low 64 bits and
reinterpreting them in two's complement.
expect Dec.to_i64_wrap(42.5) == 42Convert a Dec to an I128. The fractional part is truncated
toward zero. The entire integer part of any Dec fits in an
I128, so this never fails. See Dec.to_attos to get the exact
value (scaled by 10^18) instead.
expect Dec.to_i128(42.5) == 42Convert a Dec to a U8. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from 0 to 255 are preserved; other values wrap by
truncating to the low 8 bits (two's complement reinterpretation
of those bits).
expect Dec.to_u8_wrap(42.7) == 42
expect Dec.to_u8_wrap(-1.0) == 255Convert a Dec to a U16. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from 0 to 65535 are preserved; other values wrap by
truncating to the low 16 bits (two's complement reinterpretation
of those bits).
expect Dec.to_u16_wrap(42.5) == 42
expect Dec.to_u16_wrap(-1.0) == 65535Convert a Dec to a U32. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from 0 to 4294967295 are preserved; other values wrap
by truncating to the low 32 bits (two's complement
reinterpretation of those bits).
expect Dec.to_u32_wrap(42.5) == 42
expect Dec.to_u32_wrap(-1.0) == 4294967295Convert a Dec to a U32, returning Err(OutOfRange) if the
integer part does not fit. The fractional part is truncated toward
zero. Integer-part values from 0 to 4294967295 succeed; other
values return Err(OutOfRange).
expect Dec.to_u32_try(42.5) == Ok(42)
expect Dec.to_u32_try(-1.0) == Err(OutOfRange)Convert a Dec to a U64. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from 0 to 18446744073709551615 are preserved; other
values wrap by truncating to the low 64 bits (two's complement
reinterpretation of those bits).
expect Dec.to_u64_wrap(42.5) == 42
expect Dec.to_u64_wrap(-1.0) == 18446744073709551615Iterator of decimals beginning with this Dec and ending with the
other Dec, stepping by 1.0. (Use Dec.until instead to end with
the other Dec minus one.) Returns an empty iterator if this Dec
is greater than the other.
expect Iter.fold(Dec.to(1.0, 4.0), [], |acc, item| acc.append(item)) == [1.0, 2.0, 3.0, 4.0]
expect Iter.fold(Dec.to(-2.0, 1.0), [], |acc, item| acc.append(item)) == [-2.0, -1.0, 0.0, 1.0]
expect Iter.fold(Dec.to(5.0, 2.0), [], |acc, item| acc.append(item)) == []Iterator of decimals beginning with this Dec and ending with the
other Dec minus one, stepping by 1.0. (Use Dec.to instead to
end with the other Dec exactly, instead of minus one.) Returns
an empty iterator if this Dec is greater than or equal to the
other.
expect Iter.fold(Dec.until(1.0, 4.0), [], |acc, item| acc.append(item)) == [1.0, 2.0, 3.0]
expect Iter.fold(Dec.until(-2.0, 1.0), [], |acc, item| acc.append(item)) == [-2.0, -1.0, 0.0]
expect Iter.fold(Dec.until(5.0, 2.0), [], |acc, item| acc.append(item)) == []Encode a Dec using a format that provides encode_dec
Decode a Dec using a format that provides decode_dec
Builtin.Num.F32 :: # (opaque)
The highest finite value representable by an F32, which is
3.40282347e38.
expect F32.to_bits(F32.highest) == 2139095039The lowest finite value representable by an F32, which is
-3.40282347e38.
expect F32.to_bits(F32.lowest) == 4286578687A quiet NaN F32 value.
expect F32.is_nan(F32.nan)Positive infinity as an F32.
expect F32.is_infinite(F32.infinity)
expect F32.infinity > F32.highestEuler's number as an F32.
expect F32.to_bits(F32.e) == 1076754516The circle constant pi as an F32.
expect F32.to_bits(F32.pi) == 1078530011The circle constant tau as an F32.
expect F32.to_bits(F32.tau) == 1086918619Convert an F32 to its decimal string representation. Every NaN
representation, including negative NaNs, becomes "nan".
expect F32.to_str(42.5) == "42.5"
expect F32.to_str(-42.5) == "-42.5"Return the IEEE 754 bit pattern of an F32. All NaN values return
the canonical quiet-NaN bits 2143289344; every non-NaN value
returns its exact bits.
expect F32.to_bits(F32.from_bits(1069547520)) == 1069547520
expect F32.from_bits(F32.to_bits(1.5)).to_str() == "1.5"Build an F32 from a raw IEEE 754 bit pattern. Any NaN payload or
sign can be supplied, but F32.to_bits and hashing intentionally
collapse all NaN representations.
expect F32.from_bits(F32.to_bits(-0.0)).to_bits() == F32.to_bits(-0.0)
expect F32.from_bits(0).to_bits() == 0Returns Bool.True if the value is NaN.
expect F32.is_nan(F32.nan)
expect !F32.is_nan(1.0)Returns Bool.True if the value is positive or negative infinity.
expect F32.is_infinite(F32.infinity)
expect F32.is_infinite(F32.negate(F32.infinity))
expect !F32.is_infinite(1.0)Returns Bool.True if the value is neither NaN nor infinity.
expect F32.is_finite(1.0)
expect !F32.is_finite(F32.infinity)
expect !F32.is_finite(F32.nan)Returns Bool.True if the value is 0.0. Both positive and
negative zero return Bool.True.
expect F32.is_zero(0.0)
expect !F32.is_zero(0.5)Returns Bool.True if two F32 values compare equal using the
IEEE 754 == operation. NaN does not compare equal to itself.
expect F32.is_float_eq(1.5, 1.5)
expect !F32.is_float_eq(F32.nan, F32.nan)Returns True if a and b are equal within the given tolerances:
exactly equal (including +0.0/-0.0 and same-sign infinities), or both
finite with |a - b| <= max(abs, rel * max(|a|, |b|)).
rel: allowed difference as a fraction of the larger magnitude.abs: allowed difference regardless of magnitude; needed near zero.NaN is never approximately equal to anything, including itself. An
infinity is only equal to the same infinity. This is not transitive, so do
not use it as equality for Dict/Set keys.
Crashes unless 0 <= rel <= 1 and abs is finite and >= 0.
expect F32.is_approx_eq(0.1 + 0.2, 0.3, { rel: 1e-6, abs: 0.0 })
expect F32.is_approx_eq(1e-20, 0.0, { rel: 1e-9, abs: 1e-12 })
expect !F32.is_approx_eq(1e-20, 0.0, { rel: 1e-9, abs: 0.0 })
expect !F32.is_approx_eq(F32.nan, F32.nan, { rel: 1.0, abs: 1.0 })Returns Bool.True if the value is less than 0.0.
expect F32.is_negative(-0.5)
expect !F32.is_negative(0.0)Returns Bool.True if the value is greater than 0.0.
expect F32.is_positive(0.5)
expect !F32.is_positive(0.0)Returns Bool.True if the first value is greater than the second.
Comparisons involving NaN always return Bool.False.
expect F32.is_gt(5.0, 3.0)
expect !F32.is_gt(3.0, 3.0)Returns Bool.True if the first value is greater than or equal to
the second. Comparisons involving NaN always return Bool.False.
expect F32.is_gte(3.0, 3.0)
expect !F32.is_gte(2.0, 3.0)Returns Bool.True if the first value is less than the second.
Comparisons involving NaN always return Bool.False.
expect F32.is_lt(3.0, 5.0)
expect !F32.is_lt(3.0, 3.0)Returns Bool.True if the first value is less than or equal to the
second. Comparisons involving NaN always return Bool.False.
expect F32.is_lte(3.0, 3.0)
expect !F32.is_lte(5.0, 3.0)Returns the greater of two F32 values.
expect F32.is_float_eq(F32.max(5, 3), 5)
expect F32.is_float_eq(F32.max(-3, -1), -1)Returns the smaller of two F32 values.
expect F32.is_float_eq(F32.min(5, 3), 3)
expect F32.is_float_eq(F32.min(-3, -1), -3)Negate an F32. Flips the sign bit, so negating 0.0 produces
-0.0 and negating NaN produces NaN.
expect F32.negate(3.5).to_str() == "-3.5"
expect F32.negate(-3.5).to_str() == "3.5"Return the absolute value of an F32. The result of abs(NaN) is
NaN.
expect F32.abs(3.5).to_str() == "3.5"
expect F32.abs(-3.5).to_str() == "3.5"Return the square root of an F32. Crashes if the input is
negative. NaN and positive infinity follow IEEE 754 behavior:
NaN returns NaN, and positive infinity returns positive
infinity.
expect F32.to_str(F32.sqrt(9.0)) == "3"
expect F32.to_str(F32.sqrt(2.25)) == "1.5"Return the square root of an F32, or Err(SqrtOfNegative) if
the input is negative. NaN and positive infinity return Ok
with the IEEE 754 result.
expect F32.is_float_eq(F32.sqrt_try(9.0).ok_or(0.0), 3.0)
expect F32.sqrt_try(-1.0) == Err(SqrtOfNegative)Return the sine of an F32 angle in radians. NaN and infinite
inputs follow IEEE 754 behavior and return NaN.
expect F32.sin(0.0).to_str() == "0"Return the cosine of an F32 angle in radians. NaN and infinite
inputs follow IEEE 754 behavior and return NaN.
expect F32.cos(0.0).to_str() == "1"Return the tangent of an F32 angle in radians. The result follows
IEEE 754 behavior and may be inf, -inf, or NaN; NaN and
infinite inputs return NaN.
expect F32.tan(0.0).to_str() == "0"Return the arcsine of an F32 value in radians. Inputs outside
-1.0 through 1.0, NaN, and infinities return NaN.
expect F32.asin(0.0).to_str() == "0"Return the arccosine of an F32 value in radians. Inputs outside
-1.0 through 1.0, NaN, and infinities return NaN.
expect F32.acos(1.0).to_str() == "0"Return the arctangent of an F32 value in radians. NaN returns
NaN; infinities follow IEEE 754 behavior.
expect F32.atan(0.0).to_str() == "0"Return the angle of (x, y) in radians, between -pi and pi. Finite results are approximations in the original float width. Signed zeros and infinities follow IEEE 754; either NaN input returns NaN. For y = +/-0, negative x (including -0) returns +/-pi; positive x (including +0) returns +/-0, with the sign of y.
Add two F32 values. Addition is subject to IEEE 754 rounding; the
result may be inf, -inf, or NaN.
expect F32.plus(1.5, 2.5).to_str() == "4"Subtract the second F32 from the first. Subtraction is subject to
IEEE 754 rounding; the result may be inf, -inf, or NaN.
expect F32.minus(5.0, 3.5).to_str() == "1.5"Multiply two F32 values. Multiplication is subject to IEEE 754
rounding; the result may be inf, -inf, or NaN.
expect F32.times(2.5, 4.0).to_str() == "10"Divide the first F32 by the second. Unlike integer division,
division by zero does not crash: it produces inf, -inf, or
NaN as specified by IEEE 754.
expect F32.div_by(10.0, 4.0).to_str() == "2.5"Divide the first F32 by the second, rounding the result toward negative infinity.
expect F32.div_floor_by(7.5, 2.0).to_str() == "3"
expect F32.div_floor_by(-7.5, 2.0).to_str() == "-4"Return the remainder of dividing the first F32 by the second.
The sign of the result matches the sign of the dividend.
expect F32.rem_by(7.5, 2.0).to_str() == "1.5"
expect F32.rem_by(-7.5, 2.0).to_str() == "-1.5"Return the absolute difference between two F32 values.
expect F32.abs_diff(2.5, 5.0).to_str() == "2.5"
expect F32.abs_diff(-1.5, 5.0).to_str() == "6.5"Build an F32 from a list of base-10 digits, most significant
first. Each item of the list must be a digit in the range 0
to 9. Returns Err(OutOfRange) if the resulting value does not
fit in an F32, or if any item is not a valid digit. The
result is always non-negative; to build a negative value, F32.negate
the result.
expect F32.to_str(F32.from_int_digits([1, 2, 3]).ok_or(0.0)) == "123"Build an F32 from a tuple of (integer digits, fractional digits),
each as a list of base-10 digits most significant first. Each
item of both lists must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
F32, or if any item is not a valid digit. The result is
always non-negative; to build a negative value, F32.negate the
result.
expect F32.to_str(F32.from_dec_digits(([1, 2], [5])).ok_or(0.0)) == "12.5"Convert a numeric literal into an F32. This is the hook the
compiler uses when a literal is given type F32; most code should
parse user text with F32.from_str instead.
Parse an F32 from a Str. Returns Err(BadNumStr) if the
string is not a valid decimal number, or if the parsed value does
not fit in an F32.
expect F32.to_str(F32.from_str("42.5").ok_or(0.0)) == "42.5"
expect F32.to_str(F32.from_str("-1.25").ok_or(0.0)) == "-1.25"
expect Try.is_err(F32.from_str("not a number"))Parse a F32 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar F32.from_str
accepts: an optional sign, then inf, infinity or nan (any case), a decimal
mantissa with an optional exponent, or a 0x hex float with an optional p exponent.
There is no backtracking: if the longest match does not fit in a
F32, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect F32.from_str_prefix("1.5e3]") == Ok({ value: 1500.0, rest: "]" })
expect F32.from_str_prefix("x1") == Err(NotANumber)Parse a F32 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as F32.from_str_prefix.
The returned rest is a slice of the original list.
expect F32.from_utf8_prefix([0x32, 0x2E, 0x35, 0x2C]) == Ok({ value: 2.5, rest: [0x2C] })Convert an F32 to an I8. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -128 to 127 are preserved; other values wrap by
truncating to the low 8 bits and reinterpreting them in two's
complement. NaN, inf, and -inf all return 0.
expect F32.to_i8_wrap(42.7) == 42Convert an F32 to an I8, returning Err(OutOfRange) if the
integer part does not fit, or if the value is NaN, inf, or
-inf. The fractional part is truncated toward zero.
Integer-part values from -128 to 127 succeed; other values
return Err(OutOfRange).
expect F32.to_i8_try(42.7) == Ok(42)
expect F32.to_i8_try(200.0) == Err(OutOfRange)Convert an F32 to an I16. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -32768 to 32767 are preserved; other values wrap
by truncating to the low 16 bits and reinterpreting them in two's
complement. NaN, inf, and -inf all return 0.
expect F32.to_i16_wrap(42.5) == 42Convert an F32 to an I16, returning Err(OutOfRange) if the
integer part does not fit, or if the value is NaN, inf, or
-inf. The fractional part is truncated toward zero.
Integer-part values from -32768 to 32767 succeed; other values
return Err(OutOfRange).
expect F32.to_i16_try(42.5) == Ok(42)
expect F32.to_i16_try(40000.0) == Err(OutOfRange)Encode an F32 using a format that provides encode_f32
Decode an F32 using a format that provides decode_f32
Builtin.Num.F64 :: # (opaque)
The highest finite value representable by an F64, which is
1.7976931348623157e308.
expect F64.to_bits(F64.highest) == 9218868437227405311The lowest finite value representable by an F64, which is
-1.7976931348623157e308.
expect F64.to_bits(F64.lowest) == 18442240474082181119A quiet NaN F64 value.
expect F64.is_nan(F64.nan)Positive infinity as an F64.
expect F64.is_infinite(F64.infinity)
expect F64.infinity > F64.highestEuler's number as an F64.
expect F64.to_bits(F64.e) == 4613303445314885481The circle constant pi as an F64.
expect F64.to_bits(F64.pi) == 4614256656552045848The circle constant tau as an F64.
expect F64.to_bits(F64.tau) == 4618760256179416344Convert an F64 to its decimal string representation. Every NaN
representation, including negative NaNs, becomes "nan".
expect F64.to_str(42.5) == "42.5"
expect F64.to_str(-42.5) == "-42.5"Return the IEEE 754 bit pattern of an F64. All NaN values return
the canonical quiet-NaN bits 9221120237041090560; every non-NaN
value returns its exact bits.
expect F64.to_bits(F64.from_bits(4609434218613702656)) == 4609434218613702656
expect F64.from_bits(F64.to_bits(1.5)).to_str() == "1.5"Build an F64 from a raw IEEE 754 bit pattern. Any NaN payload or
sign can be supplied, but F64.to_bits and hashing intentionally
collapse all NaN representations.
expect F64.from_bits(F64.to_bits(-0.0)).to_bits() == F64.to_bits(-0.0)
expect F64.from_bits(0).to_bits() == 0Returns Bool.True if the value is NaN.
expect F64.is_nan(F64.nan)
expect !F64.is_nan(1.0)Returns Bool.True if the value is positive or negative infinity.
expect F64.is_infinite(F64.infinity)
expect F64.is_infinite(F64.negate(F64.infinity))
expect !F64.is_infinite(1.0)Returns Bool.True if the value is neither NaN nor infinity.
expect F64.is_finite(1.0)
expect !F64.is_finite(F64.infinity)
expect !F64.is_finite(F64.nan)Returns Bool.True if the value is 0.0. Both positive and
negative zero return Bool.True.
expect F64.is_zero(0.0)
expect !F64.is_zero(0.5)Returns Bool.True if two F64 values compare equal using the
IEEE 754 == operation. NaN does not compare equal to itself.
expect F64.is_float_eq(1.5, 1.5)
expect !F64.is_float_eq(F64.nan, F64.nan)Returns True if a and b are equal within the given tolerances:
exactly equal (including +0.0/-0.0 and same-sign infinities), or both
finite with |a - b| <= max(abs, rel * max(|a|, |b|)).
rel: allowed difference as a fraction of the larger magnitude.abs: allowed difference regardless of magnitude; needed near zero.NaN is never approximately equal to anything, including itself. An
infinity is only equal to the same infinity. This is not transitive, so do
not use it as equality for Dict/Set keys.
Crashes unless 0 <= rel <= 1 and abs is finite and >= 0.
expect F64.is_approx_eq(0.1 + 0.2, 0.3, { rel: 1e-12, abs: 0.0 })
expect F64.is_approx_eq(1e-20, 0.0, { rel: 1e-9, abs: 1e-12 })
expect !F64.is_approx_eq(1e-20, 0.0, { rel: 1e-9, abs: 0.0 })
expect !F64.is_approx_eq(F64.nan, F64.nan, { rel: 1.0, abs: 1.0 })Returns Bool.True if the value is less than 0.0.
expect F64.is_negative(-0.5)
expect !F64.is_negative(0.0)Returns Bool.True if the value is greater than 0.0.
expect F64.is_positive(0.5)
expect !F64.is_positive(0.0)Returns Bool.True if the first value is greater than the second.
Comparisons involving NaN always return Bool.False.
expect F64.is_gt(5.0, 3.0)
expect !F64.is_gt(3.0, 3.0)Returns Bool.True if the first value is greater than or equal to
the second. Comparisons involving NaN always return Bool.False.
expect F64.is_gte(3.0, 3.0)
expect !F64.is_gte(2.0, 3.0)Returns Bool.True if the first value is less than the second.
Comparisons involving NaN always return Bool.False.
expect F64.is_lt(3.0, 5.0)
expect !F64.is_lt(3.0, 3.0)Returns Bool.True if the first value is less than or equal to the
second. Comparisons involving NaN always return Bool.False.
expect F64.is_lte(3.0, 3.0)
expect !F64.is_lte(5.0, 3.0)Returns the greater of two F64 values.
expect F64.is_float_eq(F64.max(5, 3), 5)
expect F64.is_float_eq(F64.max(-3, -1), -1)Returns the smaller of two F64 values.
expect F64.is_float_eq(F64.min(5, 3), 3)
expect F64.is_float_eq(F64.min(-3, -1), -3)Negate an F64. Flips the sign bit, so negating 0.0 produces
-0.0 and negating NaN produces NaN.
expect F64.negate(3.5).to_str() == "-3.5"
expect F64.negate(-3.5).to_str() == "3.5"Return the absolute value of an F64. The result of abs(NaN) is
NaN.
expect F64.abs(3.5).to_str() == "3.5"
expect F64.abs(-3.5).to_str() == "3.5"Return the square root of an F64. Crashes if the input is
negative. NaN and positive infinity follow IEEE 754 behavior:
NaN returns NaN, and positive infinity returns positive
infinity.
expect F64.to_str(F64.sqrt(9.0)) == "3"
expect F64.to_str(F64.sqrt(2.25)) == "1.5"Return the square root of an F64, or Err(SqrtOfNegative) if
the input is negative. NaN and positive infinity return Ok
with the IEEE 754 result.
expect F64.is_float_eq(F64.sqrt_try(9.0).ok_or(0.0), 3.0)
expect F64.sqrt_try(-1.0) == Err(SqrtOfNegative)Return the sine of an F64 angle in radians. NaN and infinite
inputs follow IEEE 754 behavior and return NaN.
expect F64.sin(0.0).to_str() == "0"Return the cosine of an F64 angle in radians. NaN and infinite
inputs follow IEEE 754 behavior and return NaN.
expect F64.cos(0.0).to_str() == "1"Return the tangent of an F64 angle in radians. The result follows
IEEE 754 behavior and may be inf, -inf, or NaN; NaN and
infinite inputs return NaN.
expect F64.tan(0.0).to_str() == "0"Return the arcsine of an F64 value in radians. Inputs outside
-1.0 through 1.0, NaN, and infinities return NaN.
expect F64.asin(0.0).to_str() == "0"Return the arccosine of an F64 value in radians. Inputs outside
-1.0 through 1.0, NaN, and infinities return NaN.
expect F64.acos(1.0).to_str() == "0"Return the arctangent of an F64 value in radians. NaN returns
NaN; infinities follow IEEE 754 behavior.
expect F64.atan(0.0).to_str() == "0"Return the angle of (x, y) in radians, between -pi and pi. Finite results are approximations in the original float width. Signed zeros and infinities follow IEEE 754; either NaN input returns NaN. For y = +/-0, negative x (including -0) returns +/-pi; positive x (including +0) returns +/-0, with the sign of y.
Add two F64 values. Addition is subject to IEEE 754 rounding; the
result may be inf, -inf, or NaN.
expect F64.plus(1.5, 2.5).to_str() == "4"Subtract the second F64 from the first. Subtraction is subject to
IEEE 754 rounding; the result may be inf, -inf, or NaN.
expect F64.minus(5.0, 3.5).to_str() == "1.5"Multiply two F64 values. Multiplication is subject to IEEE 754
rounding; the result may be inf, -inf, or NaN.
expect F64.times(2.5, 4.0).to_str() == "10"Divide the first F64 by the second. Unlike integer division,
division by zero does not crash: it produces inf, -inf, or
NaN as specified by IEEE 754.
expect F64.div_by(10.0, 4.0).to_str() == "2.5"Divide the first F64 by the second, rounding the result toward negative infinity.
expect F64.div_floor_by(7.5, 2.0).to_str() == "3"
expect F64.div_floor_by(-7.5, 2.0).to_str() == "-4"Return the remainder of dividing the first F64 by the second.
The sign of the result matches the sign of the dividend.
expect F64.rem_by(7.5, 2.0).to_str() == "1.5"
expect F64.rem_by(-7.5, 2.0).to_str() == "-1.5"Return the absolute difference between two F64 values.
expect F64.abs_diff(2.5, 5.0).to_str() == "2.5"
expect F64.abs_diff(-1.5, 5.0).to_str() == "6.5"Build an F64 from a list of base-10 digits, most significant
first. Each item of the list must be a digit in the range 0
to 9. Returns Err(OutOfRange) if the resulting value does not
fit in an F64, or if any item is not a valid digit. The
result is always non-negative; to build a negative value, F64.negate
the result.
expect F64.to_str(F64.from_int_digits([1, 2, 3]).ok_or(0.0)) == "123"Build an F64 from a tuple of (integer digits, fractional digits),
each as a list of base-10 digits most significant first. Each
item of both lists must be a digit in the range 0 to 9.
Returns Err(OutOfRange) if the resulting value does not fit in an
F64, or if any item is not a valid digit. The result is
always non-negative; to build a negative value, F64.negate the
result.
expect F64.to_str(F64.from_dec_digits(([1, 2], [5])).ok_or(0.0)) == "12.5"Convert a numeric literal into an F64. This is the hook the
compiler uses when a literal is given type F64; most code should
parse user text with F64.from_str instead.
Parse an F64 from a Str. Returns Err(BadNumStr) if the
string is not a valid decimal number, or if the parsed value does
not fit in an F64.
expect F64.to_str(F64.from_str("42.5").ok_or(0.0)) == "42.5"
expect F64.to_str(F64.from_str("-1.25").ok_or(0.0)) == "-1.25"
expect Try.is_err(F64.from_str("not a number"))Parse a F64 from the start of a Str, returning the parsed value
and the rest of the string after it.
The number is the longest prefix that matches the grammar F64.from_str
accepts: an optional sign, then inf, infinity or nan (any case), a decimal
mantissa with an optional exponent, or a 0x hex float with an optional p exponent.
There is no backtracking: if the longest match does not fit in a
F64, the result is Err(OutOfRange) even when a shorter prefix would.
If no number starts the input, the result is Err(NotANumber).
No leading whitespace is skipped.
The returned rest is a slice of the original string.
expect F64.from_str_prefix("1.5e3]") == Ok({ value: 1500.0, rest: "]" })
expect F64.from_str_prefix("x1") == Err(NotANumber)Parse a F64 from the start of a list of UTF-8 bytes, returning the
parsed value and the bytes after it. The bytes after the number do not
need to be valid UTF-8, so this works on mixed binary/text formats.
The grammar is the same as F64.from_str_prefix.
The returned rest is a slice of the original list.
expect F64.from_utf8_prefix([0x32, 0x2E, 0x35, 0x2C]) == Ok({ value: 2.5, rest: [0x2C] })Convert an F64 to an I8. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -128 to 127 are preserved; other values wrap by
truncating to the low 8 bits and reinterpreting them in two's
complement. NaN, inf, and -inf all return 0.
expect F64.to_i8_wrap(42.7) == 42Convert an F64 to an I8, returning Err(OutOfRange) if the
integer part does not fit, or if the value is NaN, inf, or
-inf. The fractional part is truncated toward zero.
Integer-part values from -128 to 127 succeed; other values
return Err(OutOfRange).
expect F64.to_i8_try(42.7) == Ok(42)
expect F64.to_i8_try(200.0) == Err(OutOfRange)Convert an F64 to an I16. The fractional part is truncated
toward zero; the integer part wraps on overflow. Integer-part
values from -32768 to 32767 are preserved; other values wrap
by truncating to the low 16 bits and reinterpreting them in two's
complement. NaN, inf, and -inf all return 0.
expect F64.to_i16_wrap(42.5) == 42Convert an F64 to an I16, returning Err(OutOfRange) if the
integer part does not fit, or if the value is NaN, inf, or
-inf. The fractional part is truncated toward zero.
Integer-part values from -32768 to 32767 succeed; other values
return Err(OutOfRange).
expect F64.to_i16_try(42.5) == Ok(42)
expect F64.to_i16_try(40000.0) == Err(OutOfRange)Convert an F64 to an F32, returning Err(OutOfRange) if the
value's magnitude exceeds the F32 range (which would otherwise
overflow to inf or -inf), or if the value is NaN. Values
that fit in an F32 succeed, though precision may still be lost
due to F32's smaller mantissa.
expect F32.to_str(F64.to_f32_try(1.5).ok_or(0.0)) == "1.5"Encode an F64 using a format that provides encode_f64
Decode an F64 using a format that provides decode_f64
Builtin.Num.U8x16 :: # (opaque)
A 128-bit SIMD vector of 16 unsigned 8-bit lanes.
Lane i occupies bits [i * 8, (i + 1) * 8) of the vector, and the
byte-serialized form (used by U8x16.load, U8x16.store, and
U8x16.to_list) is little-endian with lane 0 first. Every operation
has one pinned meaning that is bit-identical on every target; the
compiler lowers each operation to the best instruction sequence for
the target CPU (SSE/AVX on x86-64, NEON on AArch64, simd128 on wasm).
Returns the U8x16 with every lane 0.
expect U8x16.default() == U8x16.splat(0)Build a U8x16 from exactly 16 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 16.
The 16 lane values as a list, lane 0 first.
expect U8x16.splat(9).to_list() == List.repeat(9.U8, 16)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see U8x16.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. U8x16(1, 2, 3, ...).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 8, (i + 1) * 8). Free at runtime—no instructions.
Build a U8x16 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 256.
Lowers to paddb on x86-64, add (16×8-bit) on AArch64 NEON,
and i8x16.add on wasm.
expect U8x16.splat(200).plus_wrap(U8x16.splat(100)).get_lane(0) == 44Subtract lane-wise, each lane wrapping mod 256.
Lowers to psubb on x86-64, sub (16×8-bit) on AArch64 NEON,
and i8x16.sub on wasm.
Add lane-wise, each lane saturating at 255 instead of wrapping.
Lowers to paddusb on x86-64, uqadd on AArch64 NEON, and
i8x16.add_sat_u on wasm.
expect U8x16.splat(200).plus_saturated(U8x16.splat(100)).get_lane(0) == 255Subtract lane-wise, each lane saturating at 0 instead of wrapping.
Lowers to psubusb on x86-64, uqsub on AArch64 NEON, and
i8x16.sub_sat_u on wasm.
The smaller of each pair of lanes.
Lowers to pminub on x86-64, umin on AArch64 NEON, and
i8x16.min_u on wasm.
The larger of each pair of lanes.
Lowers to pmaxub on x86-64, umax on AArch64 NEON, and
i8x16.max_u on wasm.
The absolute difference of each pair of lanes: max - min.
A core building block of PNG's Paeth filter and video codec
loop filters.
Lowers to psubusb twice + por on x86-64 (no single
instruction), uabd on AArch64 NEON, and i8x16.max_u +
i8x16.min_u + i8x16.sub on wasm.
The rounding average of each pair of lanes: (a + b + 1) >> 1.
Used by chroma upsampling and intra prediction in image codecs.
Lowers to pavgb on x86-64, urhadd on AArch64 NEON, and
i8x16.avgr_u on wasm.
expect U8x16.splat(1).avg_rounded(U8x16.splat(2)).get_lane(0) == 2Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U8x16.splat(0b0000_1100).bitwise_and(U8x16.splat(0b0000_1010)) == U8x16.splat(0b0000_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U8x16.splat(0b0000_1100).bitwise_or(U8x16.splat(0b0000_1010)) == U8x16.splat(0b0000_1110)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U8x16.splat(0b0000_1100).bitwise_xor(U8x16.splat(0b0000_1010)) == U8x16.splat(0b0000_0110)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# 0b1111_1010 == 250
expect U8x16.splat(0b0000_0101).bitwise_not() == U8x16.splat(0b1111_1010)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect U8x16.splat(0b0011_1100).bit_select(U8x16.splat(0b0101_0101), U8x16.splat(0b0110_0110)) == U8x16.splat(0b0101_0110)Compare lane-wise for equality: each result lane is 255 where the lanes are equal and 0 where they differ.
Lowers to pcmpeqb on x86-64, cmeq on AArch64 NEON, and
i8x16.eq on wasm.
Compare lane-wise: each result lane is 255 where a's lane is greater than b's (unsigned), else 0.
x86-64 has no unsigned byte compare, so this lowers to
pmaxub + pcmpeqb + inversion (or a sign-bias + pcmpgtb);
AArch64 NEON cmhi; wasm i8x16.gt_u.
Compare lane-wise: each result lane is 255 where a's lane is
less than b's (unsigned), else 0. See U8x16.gt_lanes for the
per-target lowerings.
Compare lane-wise: each result lane is 255 where a's lane is greater than or equal to b's (unsigned), else 0.
Lowers to pmaxub + pcmpeqb on x86-64, cmhs on AArch64
NEON, and i8x16.ge_u on wasm.
Compare lane-wise: each result lane is 255 where a's lane is
less than or equal to b's (unsigned), else 0. See
U8x16.gte_lanes for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant bit is set. On the all-0/all-1 masks produced by the
_lanes comparisons, this packs the comparison results into a
U16 for scalar decision-making (find-first-match scans, etc.).
Lowers to pmovmskb on x86-64, a short ushr/usra narrowing
sequence on AArch64 NEON (no single instruction), and
i8x16.bitmask on wasm.
# 0b1000_0000 == 128
# 0b0000_0000_0000_0010 == 2
expect U8x16.splat(0).with_lane(1, 0b1000_0000).to_bitmask() == 0b0000_0000_0000_0010
# 0b1000_0000 == 128
# 0b1111_1111_1111_1111 == 65535
expect U8x16.splat(0b1000_0000).to_bitmask() == 0b1111_1111_1111_1111Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 8: shifting by 8 leaves every lane unchanged and
shifting by 9 shifts by 1, matching U8.shl_wrap.
x86-64 has no 8-bit lane shift, so this lowers to a 16-bit
psllw + pand mask, with the count masked to the lane width
first; AArch64 NEON shl takes the pre-masked count; wasm
i8x16.shl masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U8x16.splat(0b0000_0101).shl_wrap(2) == U8x16.splat(0b0001_0100)
# 0b0000_0001 == 1
expect U8x16.splat(0b0000_0001).shl_wrap(8) == U8x16.splat(0b0000_0001)Shift every lane's bits right by the same count, filling with
zeros. The count is taken modulo 8. For unsigned lanes this
behaves the same as U8x16.shr_zf_wrap.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U8x16.splat(0b1010_0000).shr_wrap(3) == U8x16.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U8x16.splat(0b0010_0000).shr_wrap(8) == U8x16.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 8:
shifting by 8 leaves every lane unchanged and shifting by 9
shifts by 1, matching U8.shr_zf_wrap.
Lowers to psrlw + pand on x86-64 (no 8-bit lane shift), with
the count masked to the lane width first; ushr on AArch64 NEON
takes the pre-masked count; i8x16.shr_u on wasm masks the count
natively.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U8x16.splat(0b1010_0000).shr_zf_wrap(3) == U8x16.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U8x16.splat(0b0010_0000).shr_zf_wrap(8) == U8x16.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 16 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrb on x86-64, umov on AArch64 NEON, and
i8x16.extract_lane_u on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 16 or greater.
Lowers to pinsrb on x86-64, ins on AArch64 NEON, and
i8x16.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 16 or greater.
Lowers to pshufb with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i8x16.shuffle on
wasm.
Interleave the low 8 lanes of the two vectors: result lanes are
a0, b0, a1, b1, ... up through a7, b7. With
U8x16.interleave_hi, this is the building block of matrix
transposes and of widening pixel data.
Lowers to punpcklbw on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high 8 lanes of the two vectors: result lanes are
a8, b8, a9, b9, ... up through a15, b15.
Lowers to punpckhbw on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to pshufb-based shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to pshufb-based shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
Returns the vector with its 16 lanes in reverse order.
Lowers to pshufb with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Treat lo and hi as one 32-byte sequence (lo's bytes first)
and return 16 consecutive bytes of it starting at byte count.
count 0 returns lo; 16 returns hi. Crashes if count is
greater than 16. This is the sliding-window operation behind
filter kernels and overlapped LZ77 copies.
A compile-time-constant count lowers to immediate palignr on
x86-64, ext on AArch64 NEON, and i8x16.shuffle on wasm.
Those instructions cannot take a runtime count; a dynamic count
uses bit shifts and combines on native targets, and an equivalent
spill plus dynamic 16-byte load on wasm.
For each lane of indices: the lane of table it names, or 0
if the index is 16 or greater. This dynamic byte shuffle powers
palette lookups, nibble-table tricks, and byte rearrangement
with runtime patterns. Other libraries call this operation a
swizzle, a shuffle, or a permute.
Lowers to pshufb plus a one-instruction fixup on x86-64
(pshufb alone wraps indices 16-127), tbl on AArch64 NEON,
and i8x16.swizzle on wasm—the out-of-range-to-zero
semantics here matches tbl and swizzle exactly.
expect U8x16.splat(42).table_lookup(U8x16.splat(20)).get_lane(0) == 0Zero-extend the low 8 lanes into the 8 16-bit lanes of a
U16x8. With U8x16.to_u16x8_hi, this is the widening step of
the widen-compute-narrow pattern most codec kernels use.
Lowers to pmovzxbw on x86-64, uxtl on AArch64 NEON, and
i16x8.extend_low_i8x16_u on wasm.
Zero-extend the high 8 lanes into the 8 16-bit lanes of a
U16x8.
Lowers to punpckhbw with zero on x86-64, uxtl2 on AArch64
NEON, and i16x8.extend_high_i8x16_u on wasm.
Add adjacent pairs of lanes into the 8 16-bit lanes of a
U16x8: result lane i is lane(2i) + lane(2i+1). Used by
checksum and histogram accumulation.
Lowers to pmaddubsw with a ones vector on x86-64, uaddlp on
AArch64 NEON, and i16x8.extadd_pairwise_i8x16_u on wasm.
Multiply the low 8 lanes of the two vectors pairwise into the 8
16-bit lanes of a U16x8 (no overflow is possible).
Lowers to punpcklbw + pmullw on x86-64 (no single
instruction), umull on AArch64 NEON, and
i16x8.extmul_low_i8x16_u on wasm.
Multiply the high 8 lanes of the two vectors pairwise into the
8 16-bit lanes of a U16x8.
Lowers to punpckhbw + pmullw on x86-64, umull2 on AArch64
NEON, and i16x8.extmul_high_i8x16_u on wasm.
Multiply each unsigned lane of this vector with the signed lane
of the I8x16 at the same index, then add adjacent product
pairs into the 8 16-bit lanes of an I16x8, saturating on
overflow: result lane i is
saturate(u(2i) * s(2i) + u(2i+1) * s(2i+1)). This is the
8-tap-filter workhorse of convolution and color conversion
kernels.
Lowers to pmaddubsw on x86-64 (whose saturation semantics
this operation pins), and to widening-multiply + saturating
pairwise-add sequences on AArch64 NEON and wasm (no single
instruction there).
Sums of absolute differences: result lane 0 of the U64x2 is
the sum of |a_i - b_i| for lanes 0-7, and result lane 1 is
the same for lanes 8-15. This is the encoder-search workhorse
(SAD-based block matching, PNG filter selection).
Lowers to psadbw on x86-64 (whose output layout this
operation pins), a uabdl/uadalp sequence on AArch64 NEON,
and an emulated sequence on wasm (no single instruction).
expect U8x16.splat(9).sums_of_abs_diffs(U8x16.splat(6)).get_lane(0) == 24The sum of all 16 lanes (at most 4080, so it always fits).
Lowers to psadbw against zero + extract on x86-64, uaddlv
on AArch64 NEON, and pairwise-add chains on wasm.
Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.
Iterate the list 16 bytes at a time: chunks yields one
U8x16 per full 16 bytes, and tail is the fewer-than-16
leftover bytes. This is the streaming driver for chunked byte
processing.
Builtin.Num.I8x16 :: # (opaque)
A 128-bit SIMD vector of 16 signed 8-bit lanes (two's complement).
Lane i occupies bits [i * 8, (i + 1) * 8) of the vector, and the
byte-serialized form (used by I8x16.load, I8x16.store, and
I8x16.to_list) is little-endian with lane 0 first. Every operation
has one pinned meaning that is bit-identical on every target; the
compiler lowers each operation to the best instruction sequence for
the target CPU (SSE/AVX on x86-64, NEON on AArch64, simd128 on wasm).
Returns the I8x16 with every lane 0.
expect I8x16.default() == I8x16.splat(0)Build an I8x16 from exactly 16 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 16.
The 16 lane values as a list, lane 0 first.
expect I8x16.splat(9).to_list() == List.repeat(9.I8, 16)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see I8x16.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. I8x16(1, 2, 3, ...).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 8, (i + 1) * 8). Free at runtime—no instructions.
Build an I8x16 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 256 (two's complement).
Lowers to paddb on x86-64, add (16×8-bit) on AArch64 NEON,
and i8x16.add on wasm.
expect I8x16.splat(127).plus_wrap(I8x16.splat(1)).get_lane(0) == -128Subtract lane-wise, each lane wrapping mod 256 (two's complement).
Lowers to psubb on x86-64, sub (16×8-bit) on AArch64 NEON,
and i8x16.sub on wasm.
Add lane-wise, each lane saturating within the signed range -128 to 127 instead of wrapping.
Lowers to paddsb on x86-64, sqadd on AArch64 NEON, and
i8x16.add_sat_s on wasm.
expect I8x16.splat(100).plus_saturated(I8x16.splat(100)).get_lane(0) == 127Subtract lane-wise, each lane saturating within the signed range -128 to 127 instead of wrapping.
Lowers to psubsb on x86-64, sqsub on AArch64 NEON, and
i8x16.sub_sat_s on wasm.
Negate each lane, wrapping mod 256. The lane holding -128 negates to itself (-128), since +128 is not representable.
Lowers to psubb from zero on x86-64, neg on AArch64 NEON, and
i8x16.neg on wasm.
expect I8x16.splat(5).negate_wrap().get_lane(0) == -5The absolute value of each lane. The lane holding -128 has no representable positive absolute value, so it wraps back to -128.
Lowers to pabsb on x86-64, abs on AArch64 NEON, and
i8x16.abs on wasm.
expect I8x16.splat(-5).abs_wrap().get_lane(0) == 5The smaller of each pair of lanes (signed).
Lowers to pminsb (SSE4.1) on x86-64, smin on AArch64 NEON,
and i8x16.min_s on wasm.
expect I8x16.splat(-3).min(I8x16.splat(2)).get_lane(0) == -3The larger of each pair of lanes (signed).
Lowers to pmaxsb (SSE4.1) on x86-64, smax on AArch64 NEON,
and i8x16.max_s on wasm.
Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I8x16.splat(0b0000_1100).bitwise_and(I8x16.splat(0b0000_1010)) == I8x16.splat(0b0000_1000)
# -8 == 0b1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I8x16.splat(-8).bitwise_and(I8x16.splat(0b0001_1111)) == I8x16.splat(0b0001_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I8x16.splat(0b0000_1100).bitwise_or(I8x16.splat(0b0000_1010)) == I8x16.splat(0b0000_1110)
# -8 == 0b1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1101
expect I8x16.splat(-8).bitwise_or(I8x16.splat(0b0000_0101)) == I8x16.splat(-3)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I8x16.splat(0b0000_1100).bitwise_xor(I8x16.splat(0b0000_1010)) == I8x16.splat(0b0000_0110)
# -1 == 0b1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1010
expect I8x16.splat(-1).bitwise_xor(I8x16.splat(0b0000_0101)) == I8x16.splat(-6)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# -6 == 0b1111_1010
expect I8x16.splat(0b0000_0101).bitwise_not() == I8x16.splat(-6)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect I8x16.splat(0b0011_1100).bit_select(I8x16.splat(0b0101_0101), I8x16.splat(0b0110_0110)) == I8x16.splat(0b0101_0110)Compare lane-wise for equality: each result lane is -1 (all bits set) where the lanes are equal and 0 where they differ.
Lowers to pcmpeqb on x86-64, cmeq on AArch64 NEON, and
i8x16.eq on wasm.
Compare lane-wise: each result lane is -1 (all bits set) where a's lane is greater than b's (signed), else 0.
Lowers to pcmpgtb on x86-64, cmgt on AArch64 NEON, and
i8x16.gt_s on wasm.
expect I8x16.splat(1).gt_lanes(I8x16.splat(-1)).get_lane(0) == -1Compare lane-wise: each result lane is -1 (all bits set) where a's
lane is less than b's (signed), else 0. See I8x16.gt_lanes for
the per-target lowerings.
Compare lane-wise: each result lane is -1 (all bits set) where a's lane is greater than or equal to b's (signed), else 0.
Lowers to pcmpgtb + pcmpeqb + por on x86-64, cmge on
AArch64 NEON, and i8x16.ge_s on wasm.
Compare lane-wise: each result lane is -1 (all bits set) where a's
lane is less than or equal to b's (signed), else 0. See
I8x16.gte_lanes for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant bit is set. On the all-0/all-1 masks produced by the
_lanes comparisons, this packs the comparison results into a
U16 for scalar decision-making (find-first-match scans, etc.).
Lowers to pmovmskb on x86-64, a short ushr/usra narrowing
sequence on AArch64 NEON (no single instruction), and
i8x16.bitmask on wasm.
# -1 == 0b1111_1111
# 0b0000_0000_0000_0010 == 2
expect I8x16.splat(0).with_lane(1, -1).to_bitmask() == 0b0000_0000_0000_0010
# -1 == 0b1111_1111
# 0b1111_1111_1111_1111 == 65535
expect I8x16.splat(-1).to_bitmask() == 0b1111_1111_1111_1111Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 8: shifting by 8 leaves every lane unchanged and
shifting by 9 shifts by 1, matching I8.shl_wrap.
x86-64 has no 8-bit lane shift, so this lowers to a 16-bit
psllw + pand mask, with the count masked to the lane width
first; AArch64 NEON shl takes the pre-masked count; wasm
i8x16.shl masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I8x16.splat(0b0000_0101).shl_wrap(2) == I8x16.splat(0b0001_0100)
# 0b0000_0001 == 1
expect I8x16.splat(0b0000_0001).shl_wrap(8) == I8x16.splat(0b0000_0001)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 8:
shifting by 8 leaves every lane unchanged and shifting by 9
shifts by 1, matching I8.shr_zf_wrap.
Lowers to psrlw + pand on x86-64 (no 8-bit lane shift), with
the count masked to the lane width first; ushr on AArch64 NEON
takes the pre-masked count; i8x16.shr_u on wasm masks the count
natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I8x16.splat(0b0101_0000).shr_zf_wrap(3) == I8x16.splat(0b0000_1010)
# -1 == 0b1111_1111
# 0b0000_1111 == 15
expect I8x16.splat(-1).shr_zf_wrap(4) == I8x16.splat(0b0000_1111)
# 0b0010_0000 == 32
expect I8x16.splat(0b0010_0000).shr_zf_wrap(8) == I8x16.splat(0b0010_0000)Shift every lane's bits right by the same count, replicating the
sign bit into the vacated high bits. The count is taken modulo 8:
shifting by 8 leaves every lane unchanged and shifting by 9
shifts by 1, matching I8.shr_wrap.
Lowers to psraw + a mask sequence on x86-64 (no 8-bit lane
shift), with the count masked to the lane width first; sshr on
AArch64 NEON takes the pre-masked count; i8x16.shr_s on wasm
masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I8x16.splat(0b0101_0000).shr_wrap(3) == I8x16.splat(0b0000_1010)
# -32 == 0b1110_0000
# -8 == 0b1111_1000
expect I8x16.splat(-32).shr_wrap(2) == I8x16.splat(-8)
# 0b0010_0000 == 32
expect I8x16.splat(0b0010_0000).shr_wrap(8) == I8x16.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 16 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrb on x86-64, smov on AArch64 NEON, and
i8x16.extract_lane_s on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 16 or greater.
Lowers to pinsrb on x86-64, ins on AArch64 NEON, and
i8x16.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 16 or greater.
Lowers to pshufb with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i8x16.shuffle on
wasm.
Interleave the low 8 lanes of the two vectors: result lanes are
a0, b0, a1, b1, ... up through a7, b7. With
I8x16.interleave_hi, this is the building block of matrix
transposes and of widening pixel data.
Lowers to punpcklbw on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high 8 lanes of the two vectors: result lanes are
a8, b8, a9, b9, ... up through a15, b15.
Lowers to punpckhbw on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to pshufb-based shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to pshufb-based shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
Returns the vector with its 16 lanes in reverse order.
Lowers to pshufb with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Sign-extend the low 8 lanes into the 8 16-bit lanes of an
I16x8. With I8x16.to_i16x8_hi, this is the widening step of
the widen-compute-narrow pattern most codec kernels use.
Lowers to pmovsxbw (SSE4.1) on x86-64, sxtl on AArch64 NEON,
and i16x8.extend_low_i8x16_s on wasm.
Sign-extend the high 8 lanes into the 8 16-bit lanes of an
I16x8.
Lowers to pmovsxbw of the high half on x86-64, sxtl2 on
AArch64 NEON, and i16x8.extend_high_i8x16_s on wasm.
Add adjacent pairs of lanes into the 8 16-bit lanes of an
I16x8: result lane i is lane(2i) + lane(2i+1) (signed, always
in range). Used by checksum and histogram accumulation.
Lowers to an emulated sequence on x86-64 (no single instruction),
saddlp on AArch64 NEON, and i16x8.extadd_pairwise_i8x16_s on
wasm.
Multiply the low 8 lanes of the two vectors pairwise (signed)
into the 8 16-bit lanes of an I16x8 (no overflow is possible).
Lowers to pmovsxbw + pmullw on x86-64 (no single
instruction), smull on AArch64 NEON, and
i16x8.extmul_low_i8x16_s on wasm.
Multiply the high 8 lanes of the two vectors pairwise (signed)
into the 8 16-bit lanes of an I16x8.
Lowers to pmovsxbw + pmullw on x86-64 (no single
instruction), smull2 on AArch64 NEON, and
i16x8.extmul_high_i8x16_s on wasm.
The sum of all 16 lanes (signed, in the range -2048 to 2032, so it always fits).
Lowers to an emulated sequence on x86-64, saddlv on AArch64
NEON, and pairwise-add chains on wasm.
expect I8x16.splat(1).sum_lanes() == 16Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.
Builtin.Num.U16x8 :: # (opaque)
A 128-bit SIMD vector of 8 unsigned 16-bit lanes.
Lane i occupies bits [i * 16, (i + 1) * 16) of the vector, and
the byte-serialized form (used by U16x8.load and U16x8.store) is
little-endian: lane 0 first, each lane's two bytes least-significant
first. Every operation has one pinned meaning that is bit-identical
on every target; the compiler lowers each operation to the best
instruction sequence for the target CPU (SSE/AVX on x86-64, NEON on
AArch64, simd128 on wasm).
Returns the U16x8 with every lane 0.
expect U16x8.default() == U16x8.splat(0)Build a U16x8 from exactly 8 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 8.
The 8 lane values as a list, lane 0 first.
expect U16x8.splat(9).to_list() == List.repeat(9.U16, 8)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see U16x8.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. U16x8(1, 2, 3, ...).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 16, (i + 1) * 16). Free at runtime—no instructions.
Build a U16x8 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 65536.
Lowers to paddw on x86-64, add (8×16-bit) on AArch64 NEON,
and i16x8.add on wasm.
expect U16x8.splat(60000).plus_wrap(U16x8.splat(10000)).get_lane(0) == 4464Subtract lane-wise, each lane wrapping mod 65536.
Lowers to psubw on x86-64, sub (8×16-bit) on AArch64 NEON,
and i16x8.sub on wasm.
Add lane-wise, each lane saturating at 65535 instead of wrapping.
Lowers to paddusw on x86-64, uqadd on AArch64 NEON, and
i16x8.add_sat_u on wasm.
expect U16x8.splat(60000).plus_saturated(U16x8.splat(10000)).get_lane(0) == 65535Subtract lane-wise, each lane saturating at 0 instead of wrapping.
Lowers to psubusw on x86-64, uqsub on AArch64 NEON, and
i16x8.sub_sat_u on wasm.
The smaller of each pair of lanes.
Lowers to pminuw (SSE4.1) on x86-64, umin on AArch64 NEON,
and i16x8.min_u on wasm.
The larger of each pair of lanes.
Lowers to pmaxuw (SSE4.1) on x86-64, umax on AArch64 NEON,
and i16x8.max_u on wasm.
The absolute difference of each pair of lanes: max - min.
Lowers to psubusw twice + por on x86-64 (no single
instruction), uabd on AArch64 NEON, and i16x8.max_u +
i16x8.min_u + i16x8.sub on wasm.
The rounding average of each pair of lanes: (a + b + 1) >> 1.
Lowers to pavgw on x86-64, urhadd on AArch64 NEON, and
i16x8.avgr_u on wasm.
expect U16x8.splat(10).avg_rounded(U16x8.splat(15)).get_lane(0) == 13Multiply lane-wise, each lane wrapping mod 65536.
Lowers to pmullw on x86-64, mul on AArch64 NEON, and
i16x8.mul on wasm.
expect U16x8.splat(1000).times_wrap(U16x8.splat(1000)).get_lane(0) == 16960The high 16 bits of each lane-wise product: (a * b) >> 16.
Lowers to pmulhuw on x86-64, a umull + shrn sequence on
AArch64 NEON (no single instruction), and an emulated sequence on
wasm (no single instruction).
expect U16x8.splat(1000).times_high(U16x8.splat(1000)).get_lane(0) == 15Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U16x8.splat(0b0000_1100).bitwise_and(U16x8.splat(0b0000_1010)) == U16x8.splat(0b0000_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U16x8.splat(0b0000_1100).bitwise_or(U16x8.splat(0b0000_1010)) == U16x8.splat(0b0000_1110)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U16x8.splat(0b0000_1100).bitwise_xor(U16x8.splat(0b0000_1010)) == U16x8.splat(0b0000_0110)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1010 == 65530
expect U16x8.splat(0b0000_0101).bitwise_not() == U16x8.splat(0b1111_1111_1111_1010)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect U16x8.splat(0b0011_1100).bit_select(U16x8.splat(0b0101_0101), U16x8.splat(0b0110_0110)) == U16x8.splat(0b0101_0110)Compare lane-wise for equality: each result lane is 65535 where the lanes are equal and 0 where they differ.
Lowers to pcmpeqw on x86-64, cmeq on AArch64 NEON, and
i16x8.eq on wasm.
Compare lane-wise: each result lane is 65535 where a's lane is greater than b's (unsigned), else 0.
x86-64 has no unsigned 16-bit compare, so this lowers to
pmaxuw + pcmpeqw + inversion (or a sign-bias + pcmpgtw);
AArch64 NEON cmhi; wasm i16x8.gt_u.
Compare lane-wise: each result lane is 65535 where a's lane is
less than b's (unsigned), else 0. See U16x8.gt_lanes for the
per-target lowerings.
Compare lane-wise: each result lane is 65535 where a's lane is greater than or equal to b's (unsigned), else 0.
Lowers to pmaxuw + pcmpeqw on x86-64, cmhs on AArch64
NEON, and i16x8.ge_u on wasm.
Compare lane-wise: each result lane is 65535 where a's lane is
less than or equal to b's (unsigned), else 0. See
U16x8.gte_lanes for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant bit is set. On the all-0/all-1 masks produced by the
_lanes comparisons, this packs the comparison results into a
U8 for scalar decision-making (find-first-match scans, etc.).
Lowers to a packsswb + pmovmskb sequence on x86-64, a short
narrowing sequence on AArch64 NEON (no single instruction), and
i16x8.bitmask on wasm.
# 0b1000_0000_0000_0000 == 32768
# 0b0000_0010 == 2
expect U16x8.splat(0).with_lane(1, 0b1000_0000_0000_0000).to_bitmask() == 0b0000_0010
# 0b1000_0000_0000_0000 == 32768
# 0b1111_1111 == 255
expect U16x8.splat(0b1000_0000_0000_0000).to_bitmask() == 0b1111_1111Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 16: shifting by 16 leaves every lane unchanged and
shifting by 17 shifts by 1, matching U16.shl_wrap.
Lowers to psllw on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i16x8.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U16x8.splat(0b0000_0101).shl_wrap(2) == U16x8.splat(0b0001_0100)
# 0b0000_0001 == 1
expect U16x8.splat(0b0000_0001).shl_wrap(16) == U16x8.splat(0b0000_0001)Shift every lane's bits right by the same count, filling with
zeros. The count is taken modulo 16. For unsigned lanes this
behaves the same as U16x8.shr_zf_wrap.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U16x8.splat(0b1010_0000).shr_wrap(3) == U16x8.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U16x8.splat(0b0010_0000).shr_wrap(16) == U16x8.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 16:
shifting by 16 leaves every lane unchanged and shifting by 17
shifts by 1, matching U16.shr_zf_wrap.
Lowers to psrlw on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i16x8.shr_u on wasm, which masks the count natively.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U16x8.splat(0b1010_0000).shr_zf_wrap(3) == U16x8.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U16x8.splat(0b0010_0000).shr_zf_wrap(16) == U16x8.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 8 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrw on x86-64, umov on AArch64 NEON, and
i16x8.extract_lane_u on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 8 or greater.
Lowers to pinsrw on x86-64, ins on AArch64 NEON, and
i16x8.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 8 or greater.
Lowers to pshufb with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i8x16.shuffle on
wasm.
Interleave the low 4 lanes of the two vectors: result lanes are
a0, b0, a1, b1, ... up through a3, b3. With
U16x8.interleave_hi, this is the building block of matrix
transposes and of widening lane data.
Lowers to punpcklwd on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high 4 lanes of the two vectors: result lanes are
a4, b4, a5, b5, ... up through a7, b7.
Lowers to punpckhwd on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to pshufb-based shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to pshufb-based shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
Returns the vector with its 8 lanes in reverse order.
Lowers to pshufb with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Zero-extend the low 4 lanes into the 4 32-bit lanes of a
U32x4. With U16x8.to_u32x4_hi, this is the widening step of
the widen-compute-narrow pattern most codec kernels use.
Lowers to pmovzxwd (SSE4.1) on x86-64, uxtl on AArch64 NEON,
and i32x4.extend_low_i16x8_u on wasm.
Zero-extend the high 4 lanes into the 4 32-bit lanes of a
U32x4.
Lowers to punpckhwd with zero on x86-64, uxtl2 on AArch64
NEON, and i32x4.extend_high_i16x8_u on wasm.
Add adjacent pairs of lanes into the 4 32-bit lanes of a
U32x4: result lane i is lane(2i) + lane(2i+1). Used by
checksum and histogram accumulation.
Lowers to an emulated sequence on x86-64 (no unsigned
pairwise-add instruction), uaddlp on AArch64 NEON, and
i32x4.extadd_pairwise_i16x8_u on wasm.
Multiply the low 4 lanes of the two vectors pairwise into the 4
32-bit lanes of a U32x4 (no overflow is possible).
Lowers to a pmullw + pmulhuw + punpcklwd sequence on
x86-64 (no single instruction), umull on AArch64 NEON, and
i32x4.extmul_low_i16x8_u on wasm.
Multiply the high 4 lanes of the two vectors pairwise into the 4
32-bit lanes of a U32x4.
Lowers to a pmullw + pmulhuw + punpckhwd sequence on
x86-64, umull2 on AArch64 NEON, and i32x4.extmul_high_i16x8_u
on wasm.
Truncate each 16-bit lane of the two vectors to its low 8 bits
and pack them into a U8x16: result lanes 0-7 come from a,
lanes 8-15 from b.
Lowers to a pand + packuswb sequence on x86-64, xtn +
xtn2 on AArch64 NEON, and an emulated mask + narrow sequence on
wasm.
Clamp each 16-bit lane of the two vectors to at most 255 and
pack the results into a U8x16: result lanes 0-7 come from a,
lanes 8-15 from b.
Lowers to a pminuw + packuswb sequence on x86-64 (no direct
unsigned-source pack), uqxtn + uqxtn2 on AArch64 NEON, and an
emulated sequence on wasm.
The sum of all 8 lanes (at most 524280, so it always fits).
Lowers to an emulated sequence on x86-64, uaddlv on AArch64
NEON, and pairwise-add chains on wasm.
Read 16 bytes starting at the given byte index as 8 little-endian
16-bit lanes. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Read 8 numeric U16 units starting at the given unit index.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm. Each lane preserves its input unit value.
Write these 8 lanes as 16 bytes into the list starting at the
given byte index (in place when the list is unique),
little-endian. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 8 lanes as 16 bytes (little-endian) to the end of the list.
Builtin.Num.I16x8 :: # (opaque)
A 128-bit SIMD vector of 8 signed 16-bit lanes (two's complement).
Lane i occupies bits [i * 16, (i + 1) * 16) of the vector, and
the byte-serialized form (used by I16x8.load and I16x8.store) is
little-endian: lane 0 first, each lane's two bytes least-significant
first. Every operation has one pinned meaning that is bit-identical
on every target; the compiler lowers each operation to the best
instruction sequence for the target CPU (SSE/AVX on x86-64, NEON on
AArch64, simd128 on wasm).
Returns the I16x8 with every lane 0.
expect I16x8.default() == I16x8.splat(0)Build an I16x8 from exactly 8 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 8.
The 8 lane values as a list, lane 0 first.
expect I16x8.splat(9).to_list() == List.repeat(9.I16, 8)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see I16x8.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. I16x8(1, 2, 3, ...).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 16, (i + 1) * 16). Free at runtime—no instructions.
Build an I16x8 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping around mod 65536 (two's complement).
Lowers to paddw on x86-64, add (8×16-bit) on AArch64 NEON,
and i16x8.add on wasm.
Subtract lane-wise, each lane wrapping around mod 65536 (two's complement).
Lowers to psubw on x86-64, sub (8×16-bit) on AArch64 NEON,
and i16x8.sub on wasm.
Add lane-wise, each lane saturating at 32767 or -32768 instead of wrapping.
Lowers to paddsw on x86-64, sqadd on AArch64 NEON, and
i16x8.add_sat_s on wasm.
expect I16x8.splat(30000).plus_saturated(I16x8.splat(30000)).get_lane(0) == 32767Subtract lane-wise, each lane saturating at 32767 or -32768 instead of wrapping.
Lowers to psubsw on x86-64, sqsub on AArch64 NEON, and
i16x8.sub_sat_s on wasm.
Negate each lane, wrapping around mod 65536. -32768 negates to
itself, since 32768 does not fit in a signed 16-bit lane.
Lowers to psubw from zero on x86-64, neg on AArch64 NEON,
and i16x8.neg on wasm.
expect I16x8.splat(5).negate_wrap().get_lane(0) == -5The absolute value of each lane, wrapping around mod 65536.
-32768 maps to itself, since 32768 does not fit in a signed
16-bit lane.
Lowers to pabsw on x86-64, abs on AArch64 NEON, and
i16x8.abs on wasm.
expect I16x8.splat(-5).abs_wrap().get_lane(0) == 5The smaller of each pair of lanes (signed).
Lowers to pminsw on x86-64, smin on AArch64 NEON, and
i16x8.min_s on wasm.
The larger of each pair of lanes (signed).
Lowers to pmaxsw on x86-64, smax on AArch64 NEON, and
i16x8.max_s on wasm.
Multiply lane-wise, each lane wrapping around mod 65536 (the low 16 bits of the product are the same whether the lanes are read as signed or unsigned).
Lowers to pmullw on x86-64, mul on AArch64 NEON, and
i16x8.mul on wasm.
The high 16 bits of each lane-wise signed product:
(a * b) >> 16 with a sign-preserving (arithmetic) shift.
Lowers to pmulhw on x86-64, a smull + shrn sequence on
AArch64 NEON (no single instruction), and an emulated sequence on
wasm (no single instruction).
Fixed-point Q15 multiply with rounding and saturation: each lane
is saturate((2 * a * b + 32768) >> 16), treating the lanes as
signed Q15 fractions. (-32768, -32768) saturates to 32767,
since its exact product +1.0 is not representable. This is the
fixed-point workhorse of color conversion and DCT kernels.
Lowers to pmulhrsw plus a fixup for the (-32768, -32768)
input on x86-64, sqrdmulh on AArch64 NEON, and
i16x8.q15mulr_sat_s on wasm.
expect I16x8.splat(-32768).times_fixed_q15_saturated(I16x8.splat(-32768)).get_lane(0) == 32767Multiply lanes pairwise and sum adjacent products into the 4
32-bit lanes of an I32x4: result lane i is
a(2i) * b(2i) + a(2i+1) * b(2i+1). The only input that wraps
the 32-bit result is all four lanes -32768, matching the
hardware. This is the DCT/IDCT/FIR workhorse—multiply-accumulate
over signed 16-bit taps.
Lowers to pmaddwd on x86-64, a smull + smull2 +
pairwise-add sequence on AArch64 NEON, and i32x4.dot_i16x8_s
on wasm.
Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I16x8.splat(0b0000_1100).bitwise_and(I16x8.splat(0b0000_1010)) == I16x8.splat(0b0000_1000)
# -8 == 0b1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I16x8.splat(-8).bitwise_and(I16x8.splat(0b0001_1111)) == I16x8.splat(0b0001_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I16x8.splat(0b0000_1100).bitwise_or(I16x8.splat(0b0000_1010)) == I16x8.splat(0b0000_1110)
# -8 == 0b1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1101
expect I16x8.splat(-8).bitwise_or(I16x8.splat(0b0000_0101)) == I16x8.splat(-3)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I16x8.splat(0b0000_1100).bitwise_xor(I16x8.splat(0b0000_1010)) == I16x8.splat(0b0000_0110)
# -1 == 0b1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1010
expect I16x8.splat(-1).bitwise_xor(I16x8.splat(0b0000_0101)) == I16x8.splat(-6)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1010
expect I16x8.splat(0b0000_0101).bitwise_not() == I16x8.splat(-6)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect I16x8.splat(0b0011_1100).bit_select(I16x8.splat(0b0101_0101), I16x8.splat(0b0110_0110)) == I16x8.splat(0b0101_0110)Compare lane-wise for equality: each result lane is all-ones
(-1) where the lanes are equal and 0 where they differ.
Lowers to pcmpeqw on x86-64, cmeq on AArch64 NEON, and
i16x8.eq on wasm.
Compare lane-wise: each result lane is all-ones (-1) where a's
lane is greater than b's (signed), else 0.
Lowers to pcmpgtw on x86-64, cmgt on AArch64 NEON, and
i16x8.gt_s on wasm.
Compare lane-wise: each result lane is all-ones (-1) where a's
lane is less than b's (signed), else 0. See I16x8.gt_lanes for
the per-target lowerings.
Compare lane-wise: each result lane is all-ones (-1) where a's
lane is greater than or equal to b's (signed), else 0.
Lowers to pcmpgtw + pcmpeqw + por on x86-64, cmge on
AArch64 NEON, and i16x8.ge_s on wasm.
Compare lane-wise: each result lane is all-ones (-1) where a's
lane is less than or equal to b's (signed), else 0. See
I16x8.gte_lanes for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant (sign) bit is set. On the all-0/all-1 masks produced
by the _lanes comparisons, this packs the comparison results
into a U8 for scalar decision-making (find-first-match scans,
etc.).
Lowers to a packsswb + pmovmskb sequence on x86-64, a short
narrowing sequence on AArch64 NEON (no single instruction), and
i16x8.bitmask on wasm.
# -1 == 0b1111_1111_1111_1111
# 0b0000_0010 == 2
expect I16x8.splat(0).with_lane(1, -1).to_bitmask() == 0b0000_0010
# -1 == 0b1111_1111_1111_1111
# 0b1111_1111 == 255
expect I16x8.splat(-1).to_bitmask() == 0b1111_1111Returns Bool.True if any lane's sign bit is set (any lane is
negative). On comparison masks: "did any lane match?"
Returns Bool.True if every lane's sign bit is set (every lane
is negative). On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 16: shifting by 16 leaves every lane unchanged and
shifting by 17 shifts by 1, matching I16.shl_wrap.
Lowers to psllw on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i16x8.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I16x8.splat(0b0000_0101).shl_wrap(2) == I16x8.splat(0b0001_0100)
# 0b0000_0001 == 1
expect I16x8.splat(0b0000_0001).shl_wrap(16) == I16x8.splat(0b0000_0001)Shift every lane's bits right by the same count, preserving the
sign ("arithmetic shift"). The count is taken modulo 16: shifting
by 16 leaves every lane unchanged and shifting by 17 shifts by 1,
matching I16.shr_wrap.
Lowers to psraw on x86-64 with the count masked to the lane
width first, sshr on AArch64 NEON taking the pre-masked count,
and i16x8.shr_s on wasm, which masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I16x8.splat(0b0101_0000).shr_wrap(3) == I16x8.splat(0b0000_1010)
# -32 == 0b1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1000
expect I16x8.splat(-32).shr_wrap(2) == I16x8.splat(-8)
# 0b0010_0000 == 32
expect I16x8.splat(0b0010_0000).shr_wrap(16) == I16x8.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros ("zero-fill"). The count is taken
modulo 16: shifting by 16 leaves every lane unchanged and shifting
by 17 shifts by 1, matching I16.shr_zf_wrap.
Lowers to psrlw on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i16x8.shr_u on wasm, which masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I16x8.splat(0b0101_0000).shr_zf_wrap(3) == I16x8.splat(0b0000_1010)
# -1 == 0b1111_1111_1111_1111
# 0b0000_1111 == 15
expect I16x8.splat(-1).shr_zf_wrap(12) == I16x8.splat(0b0000_1111)
# 0b0010_0000 == 32
expect I16x8.splat(0b0010_0000).shr_zf_wrap(16) == I16x8.splat(0b0010_0000)Shift every lane right by the same count, rounding to nearest
(round half up): each lane becomes
(a + (1 << (count - 1))) >> count with a sign-preserving shift.
A count of 0 returns the vector unchanged; counts of 16 or more
produce 0 in every lane. This is the rounding-shift idiom of
every transform stage.
Lowers to a paddw + psraw sequence on x86-64 (no single
instruction), srshr on AArch64 NEON, and an emulated sequence
on wasm (no single instruction).
expect I16x8.splat(5).shift_right_rounded_by(1).get_lane(0) == 3Clamp each 16-bit lane of the two vectors to the signed 8-bit
range -128 to 127 and pack the results into an I8x16:
result lanes 0-7 come from a, lanes 8-15 from b.
Lowers to packsswb on x86-64, sqxtn + sqxtn2 on AArch64
NEON, and i8x16.narrow_i16x8_s on wasm.
Clamp each 16-bit lane of the two vectors to the unsigned 8-bit
range 0 to 255 and pack the results into a U8x16: result
lanes 0-7 come from a, lanes 8-15 from b. This is the final
clamp-to-pixel step of image reconstruction.
Lowers to packuswb on x86-64, sqxtun + sqxtun2 on AArch64
NEON, and i8x16.narrow_i16x8_u on wasm.
Sign-extend the low 4 lanes into the 4 32-bit lanes of an
I32x4. With I16x8.to_i32x4_hi, this is the widening step of
the widen-compute-narrow pattern most codec kernels use.
Lowers to pmovsxwd on x86-64, sxtl on AArch64 NEON, and
i32x4.extend_low_i16x8_s on wasm.
Sign-extend the high 4 lanes into the 4 32-bit lanes of an
I32x4.
Lowers to a psrldq + pmovsxwd sequence on x86-64, sxtl2 on
AArch64 NEON, and i32x4.extend_high_i16x8_s on wasm.
Add adjacent pairs of lanes into the 4 32-bit lanes of an
I32x4: result lane i is a(2i) + a(2i+1) (signed). Used by
transform column sums and histogram accumulation.
Lowers to pmaddwd with a ones vector on x86-64, saddlp on
AArch64 NEON, and i32x4.extadd_pairwise_i16x8_s on wasm.
Multiply the low 4 lanes of the two vectors pairwise into the 4
32-bit lanes of an I32x4 (no overflow is possible).
Lowers to a pmullw + pmulhw + punpcklwd sequence on x86-64
(no single instruction), smull on AArch64 NEON, and
i32x4.extmul_low_i16x8_s on wasm.
Multiply the high 4 lanes of the two vectors pairwise into the 4
32-bit lanes of an I32x4.
Lowers to a pmullw + pmulhw + punpckhwd sequence on
x86-64, smull2 on AArch64 NEON, and i32x4.extmul_high_i16x8_s
on wasm.
The sum of all 8 lanes (signed; ranges from -262144 to 262136,
so it always fits in an I32).
Lowers to an emulated sequence on x86-64, saddlv on AArch64
NEON, and pairwise-add chains on wasm.
The value of the lane at the given index. Crashes if the index is 8 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrw on x86-64, smov on AArch64 NEON, and
i16x8.extract_lane_s on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 8 or greater.
Lowers to pinsrw on x86-64, ins on AArch64 NEON, and
i16x8.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 8 or greater.
Lowers to pshufb with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i8x16.shuffle on
wasm.
Interleave the low 4 lanes of the two vectors: result lanes are
a0, b0, a1, b1, ... up through a3, b3. With
I16x8.interleave_hi, this is the building block of matrix
transposes and of widening lane data.
Lowers to punpcklwd on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high 4 lanes of the two vectors: result lanes are
a4, b4, a5, b5, ... up through a7, b7.
Lowers to punpckhwd on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to pshufb-based shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to pshufb-based shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i8x16.shuffle on wasm.
Returns the vector with its 8 lanes in reverse order.
Lowers to pshufb with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Read 16 bytes starting at the given byte index as 8 little-endian
16-bit lanes. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 8 lanes as 16 bytes into the list starting at the
given byte index (in place when the list is unique),
little-endian. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 8 lanes as 16 bytes (little-endian) to the end of the list.
Builtin.Num.U32x4 :: # (opaque)
A 128-bit SIMD vector of 4 unsigned 32-bit lanes.
Lane i occupies bits [i * 32, (i + 1) * 32) of the vector, and the
byte-serialized form (used by U32x4.load, U32x4.store, and
U32x4.to_list) is little-endian with lane 0 first. Every operation
has one pinned meaning that is bit-identical on every target; the
compiler lowers each operation to the best instruction sequence for
the target CPU (SSE/AVX on x86-64, NEON on AArch64, simd128 on wasm).
Returns the U32x4 with every lane 0.
expect U32x4.default() == U32x4.splat(0)Build a U32x4 from exactly 4 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 4.
The 4 lane values as a list, lane 0 first.
expect U32x4.splat(9).to_list() == List.repeat(9.U32, 4)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see U32x4.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. U32x4(1, 2, 3, 4).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 32, (i + 1) * 32). Free at runtime—no instructions.
Build a U32x4 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 4294967296.
Lowers to paddd on x86-64, add (4×32-bit) on AArch64 NEON,
and i32x4.add on wasm.
expect U32x4.splat(4294967295).plus_wrap(U32x4.splat(1)).get_lane(0) == 0Subtract lane-wise, each lane wrapping mod 4294967296.
Lowers to psubd on x86-64, sub (4×32-bit) on AArch64 NEON,
and i32x4.sub on wasm.
expect U32x4.splat(0).minus_wrap(U32x4.splat(1)).get_lane(0) == 4294967295The smaller of each pair of lanes (unsigned).
Lowers to pminud (SSE4.1) on x86-64, umin on AArch64 NEON,
and i32x4.min_u on wasm.
The larger of each pair of lanes (unsigned).
Lowers to pmaxud (SSE4.1) on x86-64, umax on AArch64 NEON,
and i32x4.max_u on wasm.
Multiply lane-wise, each lane wrapping mod 4294967296.
Lowers to pmulld (SSE4.1) on x86-64, mul (4×32-bit) on
AArch64 NEON, and i32x4.mul on wasm.
expect U32x4.splat(65536).times_wrap(U32x4.splat(65536)).get_lane(0) == 0Multiply lanes 0 and 1 of the two vectors pairwise into the two
64-bit lanes of a U64x2 (no overflow is possible).
Lowers to a pmuludq-based sequence on x86-64, umull on AArch64
NEON, and i64x2.extmul_low_i32x4_u on wasm.
Multiply lanes 2 and 3 of the two vectors pairwise into the two
64-bit lanes of a U64x2 (no overflow is possible).
Lowers to a pmuludq-based sequence on x86-64, umull2 on
AArch64 NEON, and i64x2.extmul_high_i32x4_u on wasm.
Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U32x4.splat(0b0000_1100).bitwise_and(U32x4.splat(0b0000_1010)) == U32x4.splat(0b0000_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U32x4.splat(0b0000_1100).bitwise_or(U32x4.splat(0b0000_1010)) == U32x4.splat(0b0000_1110)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U32x4.splat(0b0000_1100).bitwise_xor(U32x4.splat(0b0000_1010)) == U32x4.splat(0b0000_0110)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1111_1111_1111_1111_1010 == 4294967290
expect U32x4.splat(0b0000_0101).bitwise_not() == U32x4.splat(0b1111_1111_1111_1111_1111_1111_1111_1010)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect U32x4.splat(0b0011_1100).bit_select(U32x4.splat(0b0101_0101), U32x4.splat(0b0110_0110)) == U32x4.splat(0b0101_0110)Compare lane-wise for equality: each result lane is all-ones (4294967295) where the lanes are equal and 0 where they differ.
Lowers to pcmpeqd on x86-64, cmeq on AArch64 NEON, and
i32x4.eq on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is greater than b's (unsigned), else 0.
x86-64 has no unsigned dword compare, so this lowers to a
sign-bias + pcmpgtd; AArch64 NEON cmhi; wasm i32x4.gt_u.
Compare lane-wise: each result lane is all-ones where a's lane is
less than b's (unsigned), else 0. See U32x4.gt_lanes for the
per-target lowerings.
Compare lane-wise: each result lane is all-ones where a's lane is greater than or equal to b's (unsigned), else 0.
x86-64 has no unsigned dword compare, so this lowers to a
sign-bias + pcmpgtd + inversion; AArch64 NEON cmhs; wasm
i32x4.ge_u.
Compare lane-wise: each result lane is all-ones where a's lane is
less than or equal to b's (unsigned), else 0. See
U32x4.gte_lanes for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant bit is set. On the all-0/all-1 masks produced by the
_lanes comparisons, this packs the comparison results into a
U8 for scalar decision-making.
Lowers to movmskps on x86-64, a short emulated narrowing
sequence on AArch64 NEON (no single instruction), and
i32x4.bitmask on wasm.
# 0b1000_0000_0000_0000_0000_0000_0000_0000 == 2147483648
# 0b0000_0010 == 2
expect U32x4.splat(0).with_lane(1, 0b1000_0000_0000_0000_0000_0000_0000_0000).to_bitmask() == 0b0000_0010
# 0b1000_0000_0000_0000_0000_0000_0000_0000 == 2147483648
# 0b0000_1111 == 15
expect U32x4.splat(0b1000_0000_0000_0000_0000_0000_0000_0000).to_bitmask() == 0b0000_1111Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 32: shifting by 32 leaves every lane unchanged and
shifting by 33 shifts by 1, matching U32.shl_wrap.
Lowers to pslld on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i32x4.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U32x4.splat(0b0000_0101).shl_wrap(2) == U32x4.splat(0b0001_0100)
# 0b0000_0001 == 1
expect U32x4.splat(0b0000_0001).shl_wrap(32) == U32x4.splat(0b0000_0001)Shift every lane's bits right by the same count, filling with
zeros. The count is taken modulo 32. For unsigned lanes this
behaves the same as U32x4.shr_zf_wrap.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U32x4.splat(0b1010_0000).shr_wrap(3) == U32x4.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U32x4.splat(0b0010_0000).shr_wrap(32) == U32x4.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 32:
shifting by 32 leaves every lane unchanged and shifting by 33
shifts by 1, matching U32.shr_zf_wrap.
Lowers to psrld on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i32x4.shr_u on wasm, which masks the count natively.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U32x4.splat(0b1010_0000).shr_zf_wrap(3) == U32x4.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U32x4.splat(0b0010_0000).shr_zf_wrap(32) == U32x4.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 4 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrd (SSE4.1) on x86-64, umov on AArch64 NEON,
and i32x4.extract_lane on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 4 or greater.
Lowers to pinsrd (SSE4.1) on x86-64, ins on AArch64 NEON, and
i32x4.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 4 or greater.
Lowers to pshufd with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i32x4.shuffle on
wasm.
Interleave the low 2 lanes of the two vectors: result lanes are
a0, b0, a1, b1. With U32x4.interleave_hi, this is the building
block of matrix transposes and of widening data.
Lowers to punpckldq on x86-64, zip1 on AArch64 NEON, and a
constant i32x4.shuffle on wasm.
Interleave the high 2 lanes of the two vectors: result lanes are
a2, b2, a3, b3.
Lowers to punpckhdq on x86-64, zip2 on AArch64 NEON, and a
constant i32x4.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to shufps-class shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i32x4.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to shufps-class shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i32x4.shuffle on wasm.
Returns the vector with its 4 lanes in reverse order.
Lowers to pshufd with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i32x4.shuffle on wasm.
Zero-extend lanes 0 and 1 into the two 64-bit lanes of a U64x2.
With U32x4.to_u64x2_hi, this is the widening step of the
widen-compute-narrow pattern.
Lowers to pmovzxdq (SSE4.1) on x86-64, uxtl on AArch64 NEON,
and i64x2.extend_low_i32x4_u on wasm.
Zero-extend lanes 2 and 3 into the two 64-bit lanes of a U64x2.
Lowers to punpckhdq with zero on x86-64, uxtl2 on AArch64
NEON, and i64x2.extend_high_i32x4_u on wasm.
Truncate each lane to its low 16 bits and pack into a U16x8:
result lanes 0-3 come from a, lanes 4-7 from b.
Lowers to a pand + packusdw sequence on x86-64, xtn + xtn2
on AArch64 NEON, and an emulated sequence on wasm.
Clamp each lane to 65535 and pack into a U16x8: result lanes
0-3 come from a, lanes 4-7 from b.
Lowers to pminud + packusdw (SSE4.1) on x86-64, uqxtn +
uqxtn2 on AArch64 NEON, and an emulated sequence on wasm.
The sum of all 4 lanes (at most 17179869180, so it always fits a
U64).
Lowers to a phaddd-style shuffle-add sequence on x86-64,
uaddlv on AArch64 NEON, and a pairwise-add chain on wasm.
Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Read 4 numeric U32 units starting at the given unit index.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm. Each lane preserves its input unit value.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.
Builtin.Num.I32x4 :: # (opaque)
A 128-bit SIMD vector of 4 signed 32-bit lanes.
Lane i occupies bits [i * 32, (i + 1) * 32) of the vector (two's
complement), and the byte-serialized form (used by I32x4.load,
I32x4.store, and I32x4.to_list) is little-endian with lane 0
first. Every operation has one pinned meaning that is bit-identical
on every target; the compiler lowers each operation to the best
instruction sequence for the target CPU (SSE/AVX on x86-64, NEON on
AArch64, simd128 on wasm).
Returns the I32x4 with every lane 0.
expect I32x4.default() == I32x4.splat(0)Build an I32x4 from exactly 4 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 4.
The 4 lane values as a list, lane 0 first.
expect I32x4.splat(9).to_list() == List.repeat(9.I32, 4)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see I32x4.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. I32x4(-1, 2, -3, 4).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 32, (i + 1) * 32). Free at runtime—no instructions.
Build an I32x4 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 4294967296.
Lowers to paddd on x86-64, add (4×32-bit) on AArch64 NEON,
and i32x4.add on wasm.
Subtract lane-wise, each lane wrapping mod 4294967296.
Lowers to psubd on x86-64, sub (4×32-bit) on AArch64 NEON,
and i32x4.sub on wasm.
Negate each lane, wrapping mod 4294967296. The most negative lane (-2147483648) negates to itself.
Lowers to psubd from zero on x86-64, neg on AArch64 NEON, and
i32x4.neg on wasm.
expect I32x4.splat(5).negate_wrap().get_lane(0) == -5The absolute value of each lane, wrapping mod 4294967296. The most negative lane (-2147483648) has no positive counterpart and stays -2147483648.
Lowers to pabsd (SSSE3) on x86-64, abs on AArch64 NEON, and
i32x4.abs on wasm.
expect I32x4.splat(-5).abs_wrap().get_lane(0) == 5The smaller of each pair of lanes (signed).
Lowers to pminsd (SSE4.1) on x86-64, smin on AArch64 NEON,
and i32x4.min_s on wasm.
expect I32x4.splat(-5).min(I32x4.splat(3)).get_lane(0) == -5The larger of each pair of lanes (signed).
Lowers to pmaxsd (SSE4.1) on x86-64, smax on AArch64 NEON,
and i32x4.max_s on wasm.
Multiply lane-wise, each lane wrapping mod 4294967296.
Lowers to pmulld (SSE4.1) on x86-64, mul (4×32-bit) on
AArch64 NEON, and i32x4.mul on wasm.
Multiply lanes 0 and 1 of the two vectors pairwise (signed) into
the two 64-bit lanes of an I64x2 (no overflow is possible).
Lowers to pmuldq (SSE4.1) on x86-64, smull on AArch64 NEON,
and i64x2.extmul_low_i32x4_s on wasm.
Multiply lanes 2 and 3 of the two vectors pairwise (signed) into
the two 64-bit lanes of an I64x2 (no overflow is possible).
Lowers to pmuldq (SSE4.1) on x86-64, smull2 on AArch64 NEON,
and i64x2.extmul_high_i32x4_s on wasm.
Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I32x4.splat(0b0000_1100).bitwise_and(I32x4.splat(0b0000_1010)) == I32x4.splat(0b0000_1000)
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I32x4.splat(-8).bitwise_and(I32x4.splat(0b0001_1111)) == I32x4.splat(0b0001_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I32x4.splat(0b0000_1100).bitwise_or(I32x4.splat(0b0000_1010)) == I32x4.splat(0b0000_1110)
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1111_1111_1111_1111_1101
expect I32x4.splat(-8).bitwise_or(I32x4.splat(0b0000_0101)) == I32x4.splat(-3)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I32x4.splat(0b0000_1100).bitwise_xor(I32x4.splat(0b0000_1010)) == I32x4.splat(0b0000_0110)
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1010
expect I32x4.splat(-1).bitwise_xor(I32x4.splat(0b0000_0101)) == I32x4.splat(-6)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1010
expect I32x4.splat(0b0000_0101).bitwise_not() == I32x4.splat(-6)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect I32x4.splat(0b0011_1100).bit_select(I32x4.splat(0b0101_0101), I32x4.splat(0b0110_0110)) == I32x4.splat(0b0101_0110)Compare lane-wise for equality: each result lane is all-ones where the lanes are equal and 0 where they differ.
Lowers to pcmpeqd on x86-64, cmeq on AArch64 NEON, and
i32x4.eq on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is greater than b's (signed), else 0.
Lowers to pcmpgtd on x86-64, cmgt on AArch64 NEON, and
i32x4.gt_s on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is
less than b's (signed), else 0. See I32x4.gt_lanes for the
per-target lowerings.
Compare lane-wise: each result lane is all-ones where a's lane is greater than or equal to b's (signed), else 0.
Lowers to pcmpgtd + pcmpeqd + por on x86-64, cmge on
AArch64 NEON, and i32x4.ge_s on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is
less than or equal to b's (signed), else 0. See I32x4.gte_lanes
for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant (sign) bit is set. On the all-0/all-1 masks produced
by the _lanes comparisons, this packs the comparison results
into a U8 for scalar decision-making.
Lowers to movmskps on x86-64, a short emulated narrowing
sequence on AArch64 NEON (no single instruction), and
i32x4.bitmask on wasm.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0010 == 2
expect I32x4.splat(0).with_lane(1, -1).to_bitmask() == 0b0000_0010
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_1111 == 15
expect I32x4.splat(-1).to_bitmask() == 0b0000_1111Returns Bool.True if any lane's sign bit is set (any lane is
negative, or on a comparison mask, "did any lane match?").
Returns Bool.True if every lane's sign bit is set (every lane
is negative, or on a comparison mask, "did all lanes match?").
Shift every lane's bits left by the same count. The count is
taken modulo 32: shifting by 32 leaves every lane unchanged and
shifting by 33 shifts by 1, matching I32.shl_wrap.
Lowers to pslld on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i32x4.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I32x4.splat(0b0000_0101).shl_wrap(2) == I32x4.splat(0b0001_0100)
# 0b0000_0001 == 1
expect I32x4.splat(0b0000_0001).shl_wrap(32) == I32x4.splat(0b0000_0001)Shift every lane's bits right by the same count, replicating the
sign bit into the vacated high bits (arithmetic shift). The count
is taken modulo 32: shifting by 32 leaves every lane unchanged and
shifting by 33 shifts by 1, matching I32.shr_wrap.
Lowers to psrad on x86-64 with the count masked to the lane
width first, sshr on AArch64 NEON taking the pre-masked count,
and i32x4.shr_s on wasm, which masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I32x4.splat(0b0101_0000).shr_wrap(3) == I32x4.splat(0b0000_1010)
# -32 == 0b1111_1111_1111_1111_1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1000
expect I32x4.splat(-32).shr_wrap(2) == I32x4.splat(-8)
# 0b0010_0000 == 32
expect I32x4.splat(0b0010_0000).shr_wrap(32) == I32x4.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 32:
shifting by 32 leaves every lane unchanged and shifting by 33
shifts by 1, matching I32.shr_zf_wrap.
Lowers to psrld on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i32x4.shr_u on wasm, which masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I32x4.splat(0b0101_0000).shr_zf_wrap(3) == I32x4.splat(0b0000_1010)
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_1111 == 15
expect I32x4.splat(-1).shr_zf_wrap(28) == I32x4.splat(0b0000_1111)
# 0b0010_0000 == 32
expect I32x4.splat(0b0010_0000).shr_zf_wrap(32) == I32x4.splat(0b0010_0000)Arithmetic right shift that rounds to nearest by adding a
half-ULP bias first: each lane becomes
(lane + 2^(count-1)) >> count, so halves round toward positive
infinity. A count of 0 leaves the lane unchanged; counts of 32
or more produce 0. This is the rounding step of fixed-point
transform kernels.
Lowers to a paddd + psrad sequence on x86-64, srshr on
AArch64 NEON, and an emulated sequence on wasm.
Sign-extend lanes 0 and 1 into the two 64-bit lanes of an I64x2.
With I32x4.to_i64x2_hi, this is the widening step of the
widen-compute-narrow pattern.
Lowers to pmovsxdq (SSE4.1) on x86-64, sxtl on AArch64 NEON,
and i64x2.extend_low_i32x4_s on wasm.
Sign-extend lanes 2 and 3 into the two 64-bit lanes of an I64x2.
Lowers to pmovsxdq (SSE4.1) on the high two lanes on x86-64,
sxtl2 on AArch64 NEON, and i64x2.extend_high_i32x4_s on wasm.
The sum of all 4 lanes (signed), as an I64 (the sum always
fits).
Lowers to a phaddd-style shuffle-add sequence on x86-64,
saddlv on AArch64 NEON, and a pairwise-add chain on wasm.
The value of the lane at the given index. Crashes if the index is 4 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrd (SSE4.1) on x86-64, smov on AArch64 NEON,
and i32x4.extract_lane on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 4 or greater.
Lowers to pinsrd (SSE4.1) on x86-64, ins on AArch64 NEON, and
i32x4.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 4 or greater.
Lowers to pshufd with a constant pattern on x86-64, dup
(lane form) on AArch64 NEON, and a constant i32x4.shuffle on
wasm.
Interleave the low 2 lanes of the two vectors: result lanes are
a0, b0, a1, b1. With I32x4.interleave_hi, this is the building
block of matrix transposes and of widening data.
Lowers to punpckldq on x86-64, zip1 on AArch64 NEON, and a
constant i32x4.shuffle on wasm.
Interleave the high 2 lanes of the two vectors: result lanes are
a2, b2, a3, b3.
Lowers to punpckhdq on x86-64, zip2 on AArch64 NEON, and a
constant i32x4.shuffle on wasm.
The even-indexed lanes of a followed by the even-indexed lanes of b—the deinterleaving inverse of the interleave operations, used to split interleaved channel data apart.
Lowers to shufps-class shuffles on x86-64, uzp1 on AArch64
NEON, and a constant i32x4.shuffle on wasm.
The odd-indexed lanes of a followed by the odd-indexed lanes of b.
Lowers to shufps-class shuffles on x86-64, uzp2 on AArch64
NEON, and a constant i32x4.shuffle on wasm.
Returns the vector with its 4 lanes in reverse order.
Lowers to pshufd with a constant pattern on x86-64, rev64 +
ext on AArch64 NEON, and a constant i32x4.shuffle on wasm.
Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.
Builtin.Num.U64x2 :: # (opaque)
A 128-bit SIMD vector of 2 unsigned 64-bit lanes.
Lane i occupies bits [i * 64, (i + 1) * 64) of the vector, and
the byte-serialized form (used by U64x2.load, U64x2.store, and
U64x2.append_to) is little-endian with lane 0 first. Every operation
has one pinned meaning that is bit-identical on every target; the
compiler lowers each operation to the best instruction sequence for
the target CPU (SSE/AVX on x86-64, NEON on AArch64, simd128 on wasm).
Returns the U64x2 with every lane 0.
expect U64x2.default() == U64x2.splat(0)Build a U64x2 from exactly 2 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 2.
The 2 lane values as a list, lane 0 first.
expect U64x2.splat(9).to_list() == List.repeat(9.U64, 2)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see U64x2.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. U64x2(1, 2).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 64, (i + 1) * 64). Free at runtime—no instructions.
Build a U64x2 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as an I64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 2^64. Each lane widens to a
U128 for the add so the intermediate cannot overflow, then wraps
back to 64 bits.
Lowers to paddq on x86-64, add (2×64-bit) on AArch64 NEON, and
i64x2.add on wasm.
expect U64x2.splat(1).plus_wrap(U64x2.splat(2)).get_lane(0) == 3Subtract lane-wise, each lane wrapping mod 2^64. Each lane widens to
a U128 and borrows 2^64 before subtracting so the intermediate
stays non-negative, then wraps back to 64 bits.
Lowers to psubq on x86-64, sub (2×64-bit) on AArch64 NEON, and
i64x2.sub on wasm.
Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect U64x2.splat(0b0000_1100).bitwise_and(U64x2.splat(0b0000_1010)) == U64x2.splat(0b0000_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect U64x2.splat(0b0000_1100).bitwise_or(U64x2.splat(0b0000_1010)) == U64x2.splat(0b0000_1110)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect U64x2.splat(0b0000_1100).bitwise_xor(U64x2.splat(0b0000_1010)) == U64x2.splat(0b0000_0110)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010 == 18446744073709551610
expect U64x2.splat(0b0000_0101).bitwise_not() == U64x2.splat(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect U64x2.splat(0b0011_1100).bit_select(U64x2.splat(0b0101_0101), U64x2.splat(0b0110_0110)) == U64x2.splat(0b0101_0110)Compare lane-wise for equality: each result lane is all-ones where the lanes are equal and 0 where they differ.
Lowers to pcmpeqq (SSE4.1) on x86-64, cmeq on AArch64 NEON, and
i64x2.eq on wasm.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant bit is set. On the all-0/all-1 masks produced by
U64x2.eq_lanes, this packs the comparison results into a U8 for
scalar decision-making.
Lowers to movmskpd on x86-64, a short emulated sequence on AArch64
NEON (no single instruction), and i64x2.bitmask on wasm.
# 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000 == 9223372036854775808
# 0b0000_0010 == 2
expect U64x2.splat(0).with_lane(1, 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000).to_bitmask() == 0b0000_0010
# 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000 == 9223372036854775808
# 0b0000_0011 == 3
expect U64x2.splat(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000).to_bitmask() == 0b0000_0011Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 64: shifting by 64 leaves every lane unchanged and
shifting by 65 shifts by 1, matching U64.shl_wrap.
Lowers to psllq on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i64x2.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect U64x2.splat(0b0000_0101).shl_wrap(2) == U64x2.splat(0b0001_0100)
# 0b0000_0001 == 1
expect U64x2.splat(0b0000_0001).shl_wrap(64) == U64x2.splat(0b0000_0001)Shift every lane's bits right by the same count, filling with
zeros. The count is taken modulo 64. For unsigned lanes this
behaves the same as U64x2.shr_zf_wrap.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U64x2.splat(0b1010_0000).shr_wrap(3) == U64x2.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U64x2.splat(0b0010_0000).shr_wrap(64) == U64x2.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 64:
shifting by 64 leaves every lane unchanged and shifting by 65
shifts by 1, matching U64.shr_zf_wrap.
Lowers to psrlq on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i64x2.shr_u on wasm, which masks the count natively.
# 0b1010_0000 == 160
# 0b0001_0100 == 20
expect U64x2.splat(0b1010_0000).shr_zf_wrap(3) == U64x2.splat(0b0001_0100)
# 0b0010_0000 == 32
expect U64x2.splat(0b0010_0000).shr_zf_wrap(64) == U64x2.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 2 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrq (SSE4.1) on x86-64, umov on AArch64 NEON, and
i64x2.extract_lane on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 2 or greater.
Lowers to pinsrq (SSE4.1) on x86-64, ins on AArch64 NEON, and
i64x2.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 2 or greater.
Lowers to pshufd with a constant pattern on x86-64, dup (lane
form) on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Interleave the low lanes of the two vectors: result lanes are
a0, b0. With U64x2.interleave_hi, this is the building block of
matrix transposes and of widening data.
Lowers to punpcklqdq on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high lanes of the two vectors: result lanes are
a1, b1.
Lowers to punpckhqdq on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Returns the vector with its 2 lanes in reverse order.
Lowers to pshufd with a constant pattern on x86-64, ext on
AArch64 NEON, and a constant i8x16.shuffle on wasm.
Truncate each 64-bit lane of both vectors to its low 32 bits,
packing the four results into the 4 lanes of a U32x4: result
lanes are a0, a1, b0, b1.
Lowers to a shufps-class shuffle on x86-64, xtn + xtn2 on
AArch64 NEON, and an emulated shuffle on wasm.
The wrapping sum of both lanes (mod 2^64). Both lanes widen to a
U128 for the add so the intermediate cannot overflow, then wrap
back to 64 bits.
Lowers to paddq + a shuffle on x86-64, addp (scalar d-form)
on AArch64 NEON, and an emulated sequence on wasm.
expect U64x2.splat(10).sum_lanes_wrap() == 20The carryless (XOR-accumulate, no carries) 128-bit product of lane 0 of each input. The result vector's 128 bits are that product: result lane 0 is its low 64 bits and result lane 1 its high 64 bits. This is the engine of CRC-32/CRC-64 folding and GHASH.
Lowers to pclmulqdq (immediate 0x00) on x86-64, pmull
(polynomial, crypto extension) on AArch64 NEON, and a software
sequence on wasm (no instruction).
# 0b0000_0011 == 3
# 0b0000_0101 == 5
expect U64x2.splat(0b0000_0011).carryless_times_lo(U64x2.splat(0b0000_0011)).get_lane(0) == 0b0000_0101The carryless (XOR-accumulate, no carries) 128-bit product of lane 1 of each input. The result vector's 128 bits are that product: result lane 0 is its low 64 bits and result lane 1 its high 64 bits. This is the engine of CRC-32/CRC-64 folding and GHASH.
Lowers to pclmulqdq (immediate 0x11) on x86-64, pmull2
(polynomial, crypto extension) on AArch64 NEON, and a software
sequence on wasm (no instruction).
# 0b0000_0011 == 3
# 0b0000_0101 == 5
expect U64x2.splat(0b0000_0011).carryless_times_hi(U64x2.splat(0b0000_0011)).get_lane(0) == 0b0000_0101Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.
Builtin.Num.I64x2 :: # (opaque)
A 128-bit SIMD vector of 2 signed 64-bit lanes.
Lane i occupies bits [i * 64, (i + 1) * 64) of the vector, and
the byte-serialized form (used by I64x2.load, I64x2.store, and
I64x2.append_to) is little-endian with lane 0 first. Every operation
has one pinned meaning that is bit-identical on every target; the
compiler lowers each operation to the best instruction sequence for
the target CPU (SSE/AVX on x86-64, NEON on AArch64, simd128 on wasm).
Returns the I64x2 with every lane 0.
expect I64x2.default() == I64x2.splat(0)Build an I64x2 from exactly 2 lane values, lane 0 first.
Returns Err(WrongLength) if the list's length is not 2.
The 2 lane values as a list, lane 0 first.
expect I64x2.splat(7).to_list() == List.repeat(7.I64, 2)Returns Bool.True if all 128 bits of the two vectors are equal.
(For a per-lane comparison producing a mask, see I64x2.eq_lanes.)
Lowers to pxor + ptest on x86-64, cmeq + uminv on AArch64
NEON, and v128.xor + v128.any_true on wasm.
Render the lanes for debugging, e.g. I64x2(-1, 2).
The vector's 128 bits as a U128. Lane i occupies bits
[i * 64, (i + 1) * 64). Free at runtime—no instructions.
Build an I64x2 from 128 raw bits. Free at runtime—no
instructions.
Reinterpret the same 128 bits as a U8x16. Free at runtime.
Reinterpret the same 128 bits as an I8x16. Free at runtime.
Reinterpret the same 128 bits as a U16x8. Free at runtime.
Reinterpret the same 128 bits as an I16x8. Free at runtime.
Reinterpret the same 128 bits as a U32x4. Free at runtime.
Reinterpret the same 128 bits as an I32x4. Free at runtime.
Reinterpret the same 128 bits as a U64x2. Free at runtime.
Add lane-wise, each lane wrapping mod 2^64 (two's complement). Each
lane widens to a U128 for the add so the intermediate cannot
overflow, then wraps back to 64 bits.
Lowers to paddq on x86-64, add (2×64-bit) on AArch64 NEON, and
i64x2.add on wasm.
Subtract lane-wise, each lane wrapping mod 2^64 (two's complement).
Each lane widens to a U128 and borrows 2^64 before subtracting so
the intermediate stays non-negative, then wraps back to 64 bits.
Lowers to psubq on x86-64, sub (2×64-bit) on AArch64 NEON, and
i64x2.sub on wasm.
Negate each lane, wrapping mod 2^64 (two's complement). Negating 0
yields 0, and negating I64.lowest yields itself (its magnitude is
not representable), matching the scalar wrapping negation.
Lowers to psubq from a zero register on x86-64, neg on AArch64
NEON, and i64x2.neg on wasm.
expect I64x2.splat(5).negate_wrap().get_lane(0) == -5Returns the bitwise AND of the two vectors' 128 bits.
Lowers to pand on x86-64, and on AArch64 NEON, and
v128.and on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1000 == 8
expect I64x2.splat(0b0000_1100).bitwise_and(I64x2.splat(0b0000_1010)) == I64x2.splat(0b0000_1000)
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
# 0b0001_1111 == 31
# 0b0001_1000 == 24
expect I64x2.splat(-8).bitwise_and(I64x2.splat(0b0001_1111)) == I64x2.splat(0b0001_1000)Returns the bitwise OR of the two vectors' 128 bits.
Lowers to por on x86-64, orr on AArch64 NEON, and v128.or
on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_1110 == 14
expect I64x2.splat(0b0000_1100).bitwise_or(I64x2.splat(0b0000_1010)) == I64x2.splat(0b0000_1110)
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
# 0b0000_0101 == 5
# -3 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1101
expect I64x2.splat(-8).bitwise_or(I64x2.splat(0b0000_0101)) == I64x2.splat(-3)Returns the bitwise XOR of the two vectors' 128 bits.
Lowers to pxor on x86-64, eor on AArch64 NEON, and
v128.xor on wasm.
# 0b0000_1100 == 12
# 0b0000_1010 == 10
# 0b0000_0110 == 6
expect I64x2.splat(0b0000_1100).bitwise_xor(I64x2.splat(0b0000_1010)) == I64x2.splat(0b0000_0110)
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010
expect I64x2.splat(-1).bitwise_xor(I64x2.splat(0b0000_0101)) == I64x2.splat(-6)Flips every one of the vector's 128 bits.
Lowers to pxor with all-ones on x86-64, mvn on AArch64 NEON,
and v128.not on wasm.
# 0b0000_0101 == 5
# -6 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1010
expect I64x2.splat(0b0000_0101).bitwise_not() == I64x2.splat(-6)Bitwise select: for each of the 128 bits, take the bit from
if_set where this mask vector has a 1, and from if_clear
where it has a 0. Combined with the _lanes comparisons, this
is the branchless lane-wise if.
Lowers to pand/pandn/por on x86-64, bsl on AArch64 NEON,
and v128.bitselect on wasm.
# 0b0011_1100 == 60
# 0b0101_0101 == 85
# 0b0110_0110 == 102
# 0b0101_0110 == 86
expect I64x2.splat(0b0011_1100).bit_select(I64x2.splat(0b0101_0101), I64x2.splat(0b0110_0110)) == I64x2.splat(0b0101_0110)Compare lane-wise for equality: each result lane is all-ones where the lanes are equal and 0 where they differ.
Lowers to pcmpeqq (SSE4.1) on x86-64, cmeq on AArch64 NEON, and
i64x2.eq on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is greater than b's (signed), else 0.
Lowers to pcmpgtq (SSE4.2) on x86-64, cmgt on AArch64 NEON, and
i64x2.gt_s on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is
less than b's (signed), else 0. See I64x2.gt_lanes for the
per-target lowerings.
Compare lane-wise: each result lane is all-ones where a's lane is greater than or equal to b's (signed), else 0.
Lowers to pcmpgtq + pcmpeqq + por on x86-64, cmge on AArch64
NEON, and i64x2.ge_s on wasm.
Compare lane-wise: each result lane is all-ones where a's lane is
less than or equal to b's (signed), else 0. See I64x2.gte_lanes
for the per-target lowerings.
One bit per lane (lane 0 in bit 0): 1 where the lane's most
significant (sign) bit is set. On the all-0/all-1 masks produced
by the _lanes comparisons, this packs the results into a U8 for
scalar decision-making.
Lowers to movmskpd on x86-64, a short emulated sequence on AArch64
NEON (no single instruction), and i64x2.bitmask on wasm.
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0010 == 2
expect I64x2.splat(0).with_lane(1, -1).to_bitmask() == 0b0000_0010
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_0011 == 3
expect I64x2.splat(-1).to_bitmask() == 0b0000_0011Returns Bool.True if any lane's most significant bit is set.
On comparison masks: "did any lane match?"
Returns Bool.True if every lane's most significant bit is set.
On comparison masks: "did all lanes match?"
Shift every lane's bits left by the same count. The count is
taken modulo 64: shifting by 64 leaves every lane unchanged and
shifting by 65 shifts by 1, matching I64.shl_wrap.
Lowers to psllq on x86-64 with the count masked to the lane
width first, shl on AArch64 NEON taking the pre-masked count,
and i64x2.shl on wasm, which masks the count natively.
# 0b0000_0101 == 5
# 0b0001_0100 == 20
expect I64x2.splat(0b0000_0101).shl_wrap(2) == I64x2.splat(0b0001_0100)
# 0b0000_0001 == 1
expect I64x2.splat(0b0000_0001).shl_wrap(64) == I64x2.splat(0b0000_0001)Shift every lane's bits right by the same count, replicating the
sign bit into the vacated high bits (arithmetic shift). The count
is taken modulo 64: shifting by 64 leaves every lane unchanged and
shifting by 65 shifts by 1, matching I64.shr_wrap.
x86-64 has no signed 64-bit lane shift below AVX-512, so this lowers
to a psrlq + sign-fixup sequence, with the count masked to the
lane width first; AArch64 NEON sshr takes the pre-masked count;
wasm i64x2.shr_s masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I64x2.splat(0b0101_0000).shr_wrap(3) == I64x2.splat(0b0000_1010)
# -32 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1110_0000
# -8 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1000
expect I64x2.splat(-32).shr_wrap(2) == I64x2.splat(-8)
# 0b0010_0000 == 32
expect I64x2.splat(0b0010_0000).shr_wrap(64) == I64x2.splat(0b0010_0000)Shift every lane's bits right by the same count, filling the
vacated high bits with zeros. The count is taken modulo 64:
shifting by 64 leaves every lane unchanged and shifting by 65
shifts by 1, matching I64.shr_zf_wrap.
Lowers to psrlq on x86-64 with the count masked to the lane
width first, ushr on AArch64 NEON taking the pre-masked count,
and i64x2.shr_u on wasm, which masks the count natively.
# 0b0101_0000 == 80
# 0b0000_1010 == 10
expect I64x2.splat(0b0101_0000).shr_zf_wrap(3) == I64x2.splat(0b0000_1010)
# -1 == 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111
# 0b0000_1111 == 15
expect I64x2.splat(-1).shr_zf_wrap(60) == I64x2.splat(0b0000_1111)
# 0b0010_0000 == 32
expect I64x2.splat(0b0010_0000).shr_zf_wrap(64) == I64x2.splat(0b0010_0000)The value of the lane at the given index. Crashes if the index is 2 or greater. (Lane indices are expected to be compile-time constants in practice.)
Lowers to pextrq (SSE4.1) on x86-64, smov on AArch64 NEON, and
i64x2.extract_lane on wasm.
Returns the vector with the lane at the given index replaced by the given value. Crashes if the index is 2 or greater.
Lowers to pinsrq (SSE4.1) on x86-64, ins on AArch64 NEON, and
i64x2.replace_lane on wasm.
Returns a vector with every lane set to the lane of this vector at the given index. Crashes if the index is 2 or greater.
Lowers to pshufd with a constant pattern on x86-64, dup (lane
form) on AArch64 NEON, and a constant i8x16.shuffle on wasm.
Interleave the low lanes of the two vectors: result lanes are
a0, b0. With I64x2.interleave_hi, this is the building block of
matrix transposes and of widening data.
Lowers to punpcklqdq on x86-64, zip1 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Interleave the high lanes of the two vectors: result lanes are
a1, b1.
Lowers to punpckhqdq on x86-64, zip2 on AArch64 NEON, and a
constant i8x16.shuffle on wasm.
Returns the vector with its 2 lanes in reverse order.
Lowers to pshufd with a constant pattern on x86-64, ext on
AArch64 NEON, and a constant i8x16.shuffle on wasm.
The wrapping sum of both lanes (mod 2^64, two's complement). Both
lanes widen to a U128 for the add so the intermediate cannot
overflow, then wrap back to 64 signed bits.
Lowers to paddq + a shuffle on x86-64, addp (scalar d-form)
on AArch64 NEON, and an emulated sequence on wasm.
expect I64x2.splat(-3).sum_lanes_wrap() == -6Read 16 bytes starting at the given byte index, as lanes in
little-endian order. Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes). Any alignment is fine.
Lowers to movdqu on x86-64, ldr (Q register) on AArch64,
and v128.load on wasm.
Write these 16 bytes into the list starting at the given byte
index (in place when the list is unique), little-endian.
Returns Err(OutOfBounds) unless
index + 16 <= List.len(bytes).
Lowers to movdqu (store form) on x86-64, str (Q register)
on AArch64, and v128.store on wasm.
Append these 16 bytes (little-endian) to the end of the list.