1 module zua.vm.std.bit32;
2 import zua.vm.engine;
3 import zua.vm.reflection;
4 import std.typecons;
5 
6 private uint lbit32_arshift(uint x, long disp) {
7 	if (disp < 0) return x << -disp;
8 	return cast(uint)(cast(int)x >> disp);
9 }
10 
11 private uint lbit32_band(uint[] op...) {
12 	uint res = 0xFFFFFFFF;
13 	foreach (i; op) {
14 		res &= i;
15 	}
16 	return res;
17 }
18 
19 private uint lbit32_bnot(uint x) {
20 	return ~x;
21 }
22 
23 private uint lbit32_bor(uint[] op...) {
24 	uint res = 0;
25 	foreach (i; op) {
26 		res |= i;
27 	}
28 	return res;
29 }
30 
31 private bool lbit32_btest(uint[] op...) {
32 	uint res = 0xFFFFFFFF;
33 	foreach (i; op) {
34 		res &= i;
35 	}
36 	return res != 0;
37 }
38 
39 private uint lbit32_bxor(uint[] op...) {
40 	uint res = 0;
41 	foreach (i; op) {
42 		res ^= i;
43 	}
44 	return res;
45 }
46 
47 private uint lbit32_extract(uint x, long start, long width = 1) {
48 	if (start < 0) {
49 		throw new Exception("bad argument #2 to 'extract' (field cannot be negative)");
50 	}
51 	else if (width < 1) {
52 		throw new Exception("bad argument #3 to 'extract' (width must be positive)");
53 	}
54 	else if (start + width > 32) {
55 		throw new Exception("trying to access non-existent bits");
56 	}
57 	else if (width == 32) {
58 		return x;
59 	}
60 
61 	return (x >> start) & (1 << width) - 1;
62 }
63 
64 private uint lbit32_replace(uint x, uint v, long start, long width = 1) {
65 	if (start < 0) {
66 		throw new Exception("bad argument #2 to 'replace' (field cannot be negative)");
67 	}
68 	else if (width < 1) {
69 		throw new Exception("bad argument #3 to 'replace' (width must be positive)");
70 	}
71 	else if (start + width > 32) {
72 		throw new Exception("trying to access non-existent bits");
73 	}
74 	else if (width == 32) {
75 		return v;
76 	}
77 
78 	uint zeroed = x & ~((1 << width) - 1 << start);
79 	return zeroed | ((v & (1 << width) - 1) << start);
80 }
81 
82 private uint lbit32_lrotate(uint x, long disp) {
83 	disp %= 32;
84 	if (disp < 0) disp += 32;
85 	return (x << disp) | (x >> (32 - disp));
86 }
87 
88 private uint lbit32_lshift(uint x, long disp) {
89 	if (disp >= 32 || disp <= -32) return 0;
90 	if (disp < 0) return x >> -disp;
91 	return x << disp;
92 }
93 
94 private uint lbit32_rrotate(uint x, long disp) {
95 	disp %= 32;
96 	if (disp < 0) disp += 32;
97 	return (x >> disp) | (x << (32 - disp));
98 }
99 
100 private uint lbit32_rshift(uint x, long disp) {
101 	if (disp >= 32 || disp <= -32) return 0;
102 	if (disp < 0) return x << -disp;
103 	return x >> disp;
104 }
105 
106 /** Get bit32 library */
107 Value bit32lib() {
108 	TableValue res = new TableValue;
109 	res.set(Value("arshift"), exposeFunction!(lbit32_arshift, "arshift"));
110 	res.set(Value("band"), exposeFunction!(lbit32_band, "band"));
111 	res.set(Value("bnot"), exposeFunction!(lbit32_bnot, "bnot"));
112 	res.set(Value("bor"), exposeFunction!(lbit32_bor, "bor"));
113 	res.set(Value("btest"), exposeFunction!(lbit32_btest, "btest"));
114 	res.set(Value("bxor"), exposeFunction!(lbit32_bxor, "bxor"));
115 	res.set(Value("extract"), exposeFunction!(lbit32_extract, "extract"));
116 	res.set(Value("replace"), exposeFunction!(lbit32_replace, "replace"));
117 	res.set(Value("lrotate"), exposeFunction!(lbit32_lrotate, "lrotate"));
118 	res.set(Value("lshift"), exposeFunction!(lbit32_lshift, "lshift"));
119 	res.set(Value("rrotate"), exposeFunction!(lbit32_rrotate, "rrotate"));
120 	res.set(Value("rshift"), exposeFunction!(lbit32_rshift, "rshift"));
121 	return Value(res);
122 }