| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| #include <lua.h> |
| #include <lauxlib.h> |
| #include <stdlib.h> |
| #include <math.h> |
| #include <inttypes.h> |
| #include <string.h> |
| |
| extern const char * LONG_NUM_TYPE; |
| extern int64_t lualongnumber_checklong(lua_State *L, int index); |
| extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void l_serialize(char *buf, int len, int64_t val) { |
| snprintf(buf, len, "%"PRId64, val); |
| } |
| |
| static int64_t l_deserialize(const char *buf) { |
| int64_t data; |
| int rv; |
| // Support hex prefixed with '0x' |
| if (strstr(buf, "0x") == buf) { |
| rv = sscanf(buf, "%"PRIx64, &data); |
| } else { |
| rv = sscanf(buf, "%"PRId64, &data); |
| } |
| if (rv == 1) { |
| return data; |
| } |
| return 0; // Failed |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static int l_new(lua_State *L) { |
| int64_t val; |
| const char *str = NULL; |
| if (lua_type(L, 1) == LUA_TSTRING) { |
| str = lua_tostring(L, 1); |
| val = l_deserialize(str); |
| } else if (lua_type(L, 1) == LUA_TNUMBER) { |
| val = (int64_t)lua_tonumber(L, 1); |
| str = (const char *)1; |
| } |
| lualongnumber_pushlong(L, (str ? &val : NULL)); |
| return 1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // a + b |
| static int l_add(lua_State *L) { |
| int64_t a, b, c; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| c = a + b; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // a / b |
| static int l_div(lua_State *L) { |
| int64_t a, b, c; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| c = a / b; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // a == b (both a and b are lualongnumber's) |
| static int l_eq(lua_State *L) { |
| int64_t a, b; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| lua_pushboolean(L, (a == b ? 1 : 0)); |
| return 1; |
| } |
| |
| // garbage collection |
| static int l_gc(lua_State *L) { |
| lua_pushnil(L); |
| lua_setmetatable(L, 1); |
| return 0; |
| } |
| |
| // a < b |
| static int l_lt(lua_State *L) { |
| int64_t a, b; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| lua_pushboolean(L, (a < b ? 1 : 0)); |
| return 1; |
| } |
| |
| // a <= b |
| static int l_le(lua_State *L) { |
| int64_t a, b; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| lua_pushboolean(L, (a <= b ? 1 : 0)); |
| return 1; |
| } |
| |
| // a % b |
| static int l_mod(lua_State *L) { |
| int64_t a, b, c; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| c = a % b; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // a * b |
| static int l_mul(lua_State *L) { |
| int64_t a, b, c; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| c = a * b; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // a ^ b |
| static int l_pow(lua_State *L) { |
| long double a, b; |
| int64_t c; |
| a = (long double)lualongnumber_checklong(L, 1); |
| b = (long double)lualongnumber_checklong(L, 2); |
| c = (int64_t)pow(a, b); |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // a - b |
| static int l_sub(lua_State *L) { |
| int64_t a, b, c; |
| a = lualongnumber_checklong(L, 1); |
| b = lualongnumber_checklong(L, 2); |
| c = a - b; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| // tostring() |
| static int l_tostring(lua_State *L) { |
| int64_t a; |
| char str[256]; |
| l_serialize(str, 256, lualongnumber_checklong(L, 1)); |
| lua_pushstring(L, str); |
| return 1; |
| } |
| |
| // -a |
| static int l_unm(lua_State *L) { |
| int64_t a, c; |
| a = lualongnumber_checklong(L, 1); |
| c = -a; |
| lualongnumber_pushlong(L, &c); |
| return 1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static const luaL_Reg methods[] = { |
| {"__add", l_add}, |
| {"__div", l_div}, |
| {"__eq", l_eq}, |
| {"__gc", l_gc}, |
| {"__lt", l_lt}, |
| {"__le", l_le}, |
| {"__mod", l_mod}, |
| {"__mul", l_mul}, |
| {"__pow", l_pow}, |
| {"__sub", l_sub}, |
| {"__tostring", l_tostring}, |
| {"__unm", l_unm}, |
| {NULL, NULL}, |
| }; |
| |
| static const luaL_Reg funcs[] = { |
| {"new", l_new}, |
| {NULL, NULL} |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void set_methods(lua_State *L, |
| const char *metatablename, |
| const struct luaL_Reg *methods) { |
| luaL_getmetatable(L, metatablename); // mt |
| // No need for a __index table since everything is __* |
| for (; methods->name; methods++) { |
| lua_pushstring(L, methods->name); // mt, "name" |
| lua_pushcfunction(L, methods->func); // mt, "name", func |
| lua_rawset(L, -3); // mt |
| } |
| lua_pop(L, 1); |
| } |
| |
| LUALIB_API int luaopen_liblualongnumber(lua_State *L) { |
| luaL_newmetatable(L, LONG_NUM_TYPE); |
| lua_pop(L, 1); |
| set_methods(L, LONG_NUM_TYPE, methods); |
| |
| luaL_register(L, "liblualongnumber", funcs); |
| return 1; |
| } |