BitwiseLibrary.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. using Lua.Standard.Internal;
  2. namespace Lua.Standard;
  3. public static class BitwiseLibrary
  4. {
  5. public static void OpenBitwiseLibrary(this LuaState state)
  6. {
  7. var bit32 = new LuaTable(0, Functions.Length);
  8. foreach (var func in Functions)
  9. {
  10. bit32[func.Name] = func;
  11. }
  12. state.Environment["bit32"] = bit32;
  13. state.LoadedModules["bit32"] = bit32;
  14. }
  15. static readonly LuaFunction[] Functions = [
  16. new ("arshift", ArShift),
  17. new ("band", BAnd),
  18. new ("bnot", BNot),
  19. new ("bor", BOr),
  20. new ("btest", BTest),
  21. new ("bxor", BXor),
  22. new ("extract", Extract),
  23. new ("lrotate", LRotate),
  24. new ("lshift", LShift),
  25. new ("replace", Replace),
  26. new ("rrotate", RRotate),
  27. new ("rshift", RShift),
  28. ];
  29. public static ValueTask<int> ArShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  30. {
  31. var x = context.GetArgument<double>(0);
  32. var disp = context.GetArgument<double>(1);
  33. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "arshift", 1, x);
  34. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "arshift", 2, disp);
  35. var v = Bit32Helper.ToInt32(x);
  36. var a = (int)disp;
  37. if (a < 0)
  38. {
  39. v <<= -a;
  40. }
  41. else
  42. {
  43. v >>= a;
  44. }
  45. buffer.Span[0] = (uint)v;
  46. return new(1);
  47. }
  48. public static ValueTask<int> BAnd(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  49. {
  50. if (context.ArgumentCount == 0)
  51. {
  52. buffer.Span[0] = uint.MaxValue;
  53. return new(1);
  54. }
  55. var arg0 = context.GetArgument<double>(0);
  56. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "band", 1, arg0);
  57. var value = Bit32Helper.ToUInt32(arg0);
  58. for (int i = 1; i < context.ArgumentCount; i++)
  59. {
  60. var arg = context.GetArgument<double>(i);
  61. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "band", 1 + i, arg);
  62. var v = Bit32Helper.ToUInt32(arg);
  63. value &= v;
  64. }
  65. buffer.Span[0] = value;
  66. return new(1);
  67. }
  68. public static ValueTask<int> BNot(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  69. {
  70. var arg0 = context.GetArgument<double>(0);
  71. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bnot", 1, arg0);
  72. var value = Bit32Helper.ToUInt32(arg0);
  73. buffer.Span[0] = ~value;
  74. return new(1);
  75. }
  76. public static ValueTask<int> BOr(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  77. {
  78. if (context.ArgumentCount == 0)
  79. {
  80. buffer.Span[0] = 0;
  81. return new(1);
  82. }
  83. var arg0 = context.GetArgument<double>(0);
  84. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bor", 1, arg0);
  85. var value = Bit32Helper.ToUInt32(arg0);
  86. for (int i = 1; i < context.ArgumentCount; i++)
  87. {
  88. var arg = context.GetArgument<double>(i);
  89. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bor", 1 + i, arg);
  90. var v = Bit32Helper.ToUInt32(arg);
  91. value |= v;
  92. }
  93. buffer.Span[0] = value;
  94. return new(1);
  95. }
  96. public static ValueTask<int> BTest(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  97. {
  98. if (context.ArgumentCount == 0)
  99. {
  100. buffer.Span[0] = true;
  101. return new(1);
  102. }
  103. var arg0 = context.GetArgument<double>(0);
  104. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "btest", 1, arg0);
  105. var value = Bit32Helper.ToUInt32(arg0);
  106. for (int i = 1; i < context.ArgumentCount; i++)
  107. {
  108. var arg = context.GetArgument<double>(i);
  109. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "btest", 1 + i, arg);
  110. var v = Bit32Helper.ToUInt32(arg);
  111. value &= v;
  112. }
  113. buffer.Span[0] = value != 0;
  114. return new(1);
  115. }
  116. public static ValueTask<int> BXor(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  117. {
  118. if (context.ArgumentCount == 0)
  119. {
  120. buffer.Span[0] = 0;
  121. return new(1);
  122. }
  123. var arg0 = context.GetArgument<double>(0);
  124. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bxor", 1, arg0);
  125. var value = Bit32Helper.ToUInt32(arg0);
  126. for (int i = 1; i < context.ArgumentCount; i++)
  127. {
  128. var arg = context.GetArgument<double>(i);
  129. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bxor", 1 + i, arg);
  130. var v = Bit32Helper.ToUInt32(arg);
  131. value ^= v;
  132. }
  133. buffer.Span[0] = value;
  134. return new(1);
  135. }
  136. public static ValueTask<int> Extract(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  137. {
  138. var arg0 = context.GetArgument<double>(0);
  139. var arg1 = context.GetArgument<double>(1);
  140. var arg2 = context.HasArgument(2)
  141. ? context.GetArgument<double>(2)
  142. : 1;
  143. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "extract", 1, arg0);
  144. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "extract", 2, arg1);
  145. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "extract", 3, arg2);
  146. var n = Bit32Helper.ToUInt32(arg0);
  147. var field = (int)arg1;
  148. var width = (int)arg2;
  149. Bit32Helper.ValidateFieldAndWidth(context.State, "extract", 2, field, width);
  150. if (field == 0 && width == 32)
  151. {
  152. buffer.Span[0] = n;
  153. }
  154. else
  155. {
  156. var mask = (uint)((1 << width) - 1);
  157. buffer.Span[0] = (n >> field) & mask;
  158. }
  159. return new(1);
  160. }
  161. public static ValueTask<int> LRotate(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  162. {
  163. var x = context.GetArgument<double>(0);
  164. var disp = context.GetArgument<double>(1);
  165. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "lrotate", 1, x);
  166. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "lrotate", 2, disp);
  167. var v = Bit32Helper.ToUInt32(x);
  168. var a = ((int)disp) % 32;
  169. if (a < 0)
  170. {
  171. v = (v >> (-a)) | (v << (32 + a));
  172. }
  173. else
  174. {
  175. v = (v << a) | (v >> (32 - a));
  176. }
  177. buffer.Span[0] = v;
  178. return new(1);
  179. }
  180. public static ValueTask<int> LShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  181. {
  182. var x = context.GetArgument<double>(0);
  183. var disp = context.GetArgument<double>(1);
  184. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "lshift", 1, x);
  185. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "lshift", 2, disp);
  186. var v = Bit32Helper.ToUInt32(x);
  187. var a = (int)disp;
  188. if (Math.Abs(a) >= 32)
  189. {
  190. v = 0;
  191. }
  192. else if (a < 0)
  193. {
  194. v >>= -a;
  195. }
  196. else
  197. {
  198. v <<= a;
  199. }
  200. buffer.Span[0] = v;
  201. return new(1);
  202. }
  203. public static ValueTask<int> Replace(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  204. {
  205. var arg0 = context.GetArgument<double>(0);
  206. var arg1 = context.GetArgument<double>(1);
  207. var arg2 = context.GetArgument<double>(2);
  208. var arg3 = context.HasArgument(3)
  209. ? context.GetArgument<double>(3)
  210. : 1;
  211. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "replace", 1, arg0);
  212. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "replace", 2, arg1);
  213. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "replace", 3, arg2);
  214. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "replace", 4, arg3);
  215. var n = Bit32Helper.ToUInt32(arg0);
  216. var v = Bit32Helper.ToUInt32(arg1);
  217. var field = (int)arg2;
  218. var width = (int)arg3;
  219. Bit32Helper.ValidateFieldAndWidth(context.State, "replace", 2, field, width);
  220. uint mask;
  221. if (width == 32)
  222. {
  223. mask = 0xFFFFFFFF;
  224. }
  225. else
  226. {
  227. mask = (uint)((1 << width) - 1);
  228. }
  229. v = v & mask;
  230. n = (n & ~(mask << field)) | (v << field);
  231. buffer.Span[0] = n;
  232. return new(1);
  233. }
  234. public static ValueTask<int> RRotate(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  235. {
  236. var x = context.GetArgument<double>(0);
  237. var disp = context.GetArgument<double>(1);
  238. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "rrotate", 1, x);
  239. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "rrotate", 2, disp);
  240. var v = Bit32Helper.ToUInt32(x);
  241. var a = ((int)disp) % 32;
  242. if (a < 0)
  243. {
  244. v = (v << (-a)) | (v >> (32 + a));
  245. }
  246. else
  247. {
  248. v = (v >> a) | (v << (32 - a));
  249. }
  250. buffer.Span[0] = v;
  251. return new(1);
  252. }
  253. public static ValueTask<int> RShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  254. {
  255. var x = context.GetArgument<double>(0);
  256. var disp = context.GetArgument<double>(1);
  257. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "rshift", 1, x);
  258. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "rshift", 2, disp);
  259. var v = Bit32Helper.ToUInt32(x);
  260. var a = (int)disp;
  261. if (Math.Abs(a) >= 32)
  262. {
  263. v = 0;
  264. }
  265. else if (a < 0)
  266. {
  267. v <<= -a;
  268. }
  269. else
  270. {
  271. v >>= a;
  272. }
  273. buffer.Span[0] = v;
  274. return new(1);
  275. }
  276. }