hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

bits.ha (5052B)


      1 // License: MPL-2.0
      2 // (c) 2021-2022 Armin Preiml <apreiml@strohwolke.at>
      3 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      4 // (c) 2021 Thomas Bracht Laumann Jespersen <t@laumann.xyz>
      5 
      6 // Rotates a 32-bit unsigned integer left by k bits. k may be negative to rotate
      7 // right instead, or see [[rotr32]].
      8 export fn rotl32(x: u32, k: int) u32 = {
      9 	const n = 32u32;
     10 	const s = k: u32 & (n - 1);
     11 	return x << s | x >> (n - s);
     12 };
     13 
     14 // Rotates a 32-bit unsigned integer right by k bits. k may be negative to
     15 // rotate left instead, or see [[rotl32]].
     16 export fn rotr32(x: u32, k: int) u32 = rotl32(x, -k);
     17 
     18 @test fn lrot32() void = {
     19 	let a = 0b11110000111100001111000011110000u32;
     20 	assert(rotl32(a, 2) == 0b11000011110000111100001111000011u32);
     21 	assert(rotl32(a, -2) == 0b00111100001111000011110000111100u32);
     22 	assert(rotl32(a, 32) == 0b11110000111100001111000011110000u32);
     23 	assert(rotl32(a, 64) == 0b11110000111100001111000011110000u32);
     24 };
     25 
     26 // Rotates a 64-bit unsigned integer left by k bits. k may be negative to rotate
     27 // right instead, or see [[rotr64]].
     28 export fn rotl64(x: u64, k: int) u64 = {
     29 	const n = 64u64;
     30 	const s = k: u64 & (n - 1);
     31 	return x << s | x >> (n - s);
     32 };
     33 
     34 // Rotates a 64-bit unsigned integer right by k bits. k may be negative to rotate
     35 // left instead, or see [[rotl64]].
     36 export fn rotr64(x: u64, k: int) u64 = rotl64(x, -k);
     37 
     38 @test fn lrot64() void = {
     39 	let a = 1u64;
     40 	assert(rotl64(a, 1) == 0b10);
     41 	assert(rotl64(a, -1) == 0b1000000000000000000000000000000000000000000000000000000000000000);
     42 	assert(rotl64(a, 39) == (1u64 << 39));
     43 
     44 	let a = 0b1111000011110000111100001111000011110000111100001111000011110000u64;
     45 	assert(rotl64(a, 64) == a);
     46 	assert(rotl64(a, 0) == a);
     47 	assert(rotl64(a, 2) == 0b1100001111000011110000111100001111000011110000111100001111000011u64);
     48 	assert(rotl64(a, -2) == 0b0011110000111100001111000011110000111100001111000011110000111100u64);
     49 
     50 };
     51 
     52 // Stores the xor of 'a' and 'b' into 'dest'. All parameters must have the same
     53 // length. 'dest' may be the same slice as 'a' and/or 'b'.
     54 export fn xor(dest: []u8, a: []u8, b: []u8) void = {
     55 	assert(len(dest) == len(a) && len(dest) == len(b),
     56 		"dest, a and b must have the same length");
     57 
     58 	for (let i = 0z; i < len(dest); i += 1) {
     59 		dest[i] = a[i] ^ b[i];
     60 	};
     61 };
     62 
     63 // Compare two byte slices in constant time.
     64 //
     65 // Returns 1 if the two slices have the same contents, 0 otherwise.
     66 export fn eqslice(x: []u8, y: []u8) int = {
     67 	assert(len(x) == len(y), "slices must have the same length");
     68 	let v: u8 = 0;
     69 	for (let i = 0z; i < len(x); i += 1) {
     70 		v |= x[i] ^ y[i];
     71 	};
     72 	return equ8(v, 0);
     73 };
     74 
     75 @test fn eqslice() void = {
     76 	assert(eqslice([], []) == 1);
     77 	assert(eqslice([0], [0]) == 1);
     78 	assert(eqslice([1], [0]) == 0);
     79 	assert(eqslice([1, 0], [0, 0]) == 0);
     80 	assert(eqslice([0, 0], [0, 0]) == 1);
     81 
     82 	assert(eqslice([0x12, 0xAB], [0x12, 0xAB]) == 1);
     83 	assert(eqslice([0x12, 0xAB], [0x12, 0xAC]) == 0);
     84 	assert(eqslice([0x12, 0xAB], [0x11, 0xAB]) == 0);
     85 };
     86 
     87 // Compare two bytes in constant time. Returns 1 if the bytes are the same
     88 // value, 0 otherwise.
     89 export fn equ8(x: u8, y: u8) int = ((((x ^ y) : u32) - 1) >> 31) : int;
     90 
     91 // Returns x if ctl == 1 and y if ctl == 0.
     92 export fn muxu32(ctl: u32, x: u32, y: u32) u32 = y ^ ((-(ctl: i32)): u32 & (x ^ y));
     93 
     94 @test fn muxu32() void = {
     95 	assert(muxu32(1, 0x4, 0xff) == 0x4);
     96 	assert(muxu32(0, 0x4, 0xff) == 0xff);
     97 };
     98 
     99 // Negates first bit.
    100 export fn notu32(x: u32) u32 = x ^ 1;
    101 
    102 // Compares 'x' and 'y'. Returns 1 if they are equal or 0 otherwise.
    103 export fn equ32(x: u32, y: u32) u32 = {
    104 	let q = x ^ y;
    105 	return ((q | -(q: i32): u32) >> 31) ^ 1;
    106 };
    107 
    108 @test fn equ32() void = {
    109 	assert(equ32(0x4f, 0x4f) == 1);
    110 	assert(equ32(0x4f, 0x0) == 0);
    111 	assert(equ32(0x2, 0x6) == 0);
    112 };
    113 
    114 // Returns 1 if 'x' is zero or 0 if not.
    115 export fn eq0u32(x: i32) u32 = {
    116 	const q: u32 = x: u32;
    117 	return ~(q | -q) >> 31;
    118 };
    119 
    120 @test fn eq0u32() void = {
    121 	assert(eq0u32(0) == 1);
    122 	assert(eq0u32(1) == 0);
    123 	assert(eq0u32(0x1234) == 0);
    124 };
    125 
    126 
    127 // Returns 1 if x != y and 0 otherwise.
    128 export fn nequ32(x: u32, y: u32) u32 = {
    129 	let q = x ^ y;
    130 	return (q | -(q: i32): u32) >> 31;
    131 };
    132 
    133 // Returns 1 if x > y and 0 otherwise.
    134 export fn gtu32(x: u32, y: u32) u32 = {
    135 	let z: u32 = y - x;
    136 	return (z ^ ((x ^ y) & (x ^ z))) >> 31;
    137 };
    138 
    139 @test fn gtu32() void = {
    140 	assert(gtu32(1, 0) == 1);
    141 	assert(gtu32(0, 1) == 0);
    142 	assert(gtu32(0, 0) == 0);
    143 
    144 	assert(gtu32(0xf3, 0xf2) == 1);
    145 	assert(gtu32(0x20, 0xff) == 0);
    146 	assert(gtu32(0x23, 0x23) == 0);
    147 };
    148 
    149 // Returns 1 if x >= y and 0 otherwise.
    150 export fn geu32(x: u32, y: u32) u32 = notu32(gtu32(y, x));
    151 //
    152 // Returns 1 if x < y and 0 otherwise.
    153 export fn ltu32(x: u32, y: u32) u32 = gtu32(y, x);
    154 //
    155 // Returns 1 if x <= y and 0 otherwise.
    156 export fn leu32(x: u32, y: u32) u32 = notu32(gtu32(x, y));
    157 
    158 // Compares 'x' with 'y'. Returns -1 if x < y, 0 if x == y and 1 if x > x.
    159 export fn cmpu32(x: u32, y: u32) i32 = gtu32(x, y): i32 | -(gtu32(y, x): i32);
    160 
    161 @test fn cmpu32() void = {
    162 	assert(cmpu32(0, 0) == 0);
    163 	assert(cmpu32(0x34, 0x34) == 0);
    164 
    165 	assert(cmpu32(0x12, 0x34) == -1);
    166 	assert(cmpu32(0x87, 0x34) == 1);
    167 };
    168