|  | // | 
|  | // 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); | 
|  |  | 
|  | #if LUA_VERSION_NUM >= 502 | 
|  | lua_newtable(L); | 
|  | luaL_setfuncs(L, funcs, 0); | 
|  | #else | 
|  | luaL_register(L, "liblualongnumber", funcs); | 
|  | #endif | 
|  | return 1; | 
|  | } |