Преглед изворни кода

metamethods for 'removekey'/'keyin'

Roberto Ierusalimschy пре 7 година
родитељ
комит
b7edf5d2d8
4 измењених фајлова са 46 додато и 18 уклоњено
  1. 8 11
      lapi.c
  2. 3 5
      lbaselib.c
  3. 30 1
      ltm.c
  4. 5 1
      ltm.h

+ 8 - 11
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.287 2018/02/25 12:48:16 roberto Exp roberto $
+** $Id: lapi.c,v 2.288 2018/02/26 14:16:05 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -679,6 +679,7 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
   Table *t;
   const TValue *val;
   lua_lock(L);
+  api_checknelems(L, 1);
   t = gettable(L, idx);
   val = luaH_get(t, s2v(L->top - 1));
   L->top--;  /* remove key */
@@ -704,29 +705,24 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
 }
 
 
-static int auxkeyman (lua_State *L, int idx, int remove) {
-  Table *t;
-  const TValue *val;
+static int auxkeydef (lua_State *L, int idx, int remove) {
   int res;
   lua_lock(L);
-  t = gettable(L, idx);
-  val = luaH_get(t, s2v(L->top - 1));
+  api_checknelems(L, 1);
+  res = luaT_keydef(L, index2value(L, idx), s2v(L->top - 1), remove);
   L->top--;  /* remove key */
-  res = !isempty(val);
-  if (remove && res)  /* key is present and should be removed? */
-    setempty(cast(TValue*, val));
   lua_unlock(L);
   return res;
 }
 
 
 LUA_API void lua_removekey (lua_State *L, int idx) {
-  auxkeyman(L, idx, 1);
+  auxkeydef(L, idx, 1);
 }
 
 
 LUA_API int lua_keyin (lua_State *L, int idx) {
-  return auxkeyman(L, idx, 0);
+  return auxkeydef(L, idx, 0);
 }
 
 
@@ -1223,6 +1219,7 @@ LUA_API int lua_next (lua_State *L, int idx) {
   Table *t;
   int more;
   lua_lock(L);
+  api_checknelems(L, 1);
   t = gettable(L, idx);
   more = luaH_next(L, t, L->top - 1);
   if (more) {

+ 3 - 5
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.319 2018/02/05 17:10:52 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.320 2018/02/25 12:48:16 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -171,8 +171,7 @@ static int luaB_rawset (lua_State *L) {
 
 
 static int luaB_keyin (lua_State *L) {
-  luaL_checktype(L, 1, LUA_TTABLE);
-  luaL_checkany(L, 2);
+  luaL_checkany(L, 2);  /* ensures a first argument too */
   lua_settop(L, 2);
   lua_pushboolean(L, lua_keyin(L, 1));
   return 1;
@@ -180,8 +179,7 @@ static int luaB_keyin (lua_State *L) {
 
 
 static int luaB_removekey (lua_State *L) {
-  luaL_checktype(L, 1, LUA_TTABLE);
-  luaL_checkany(L, 2);
+  luaL_checkany(L, 2);  /* ensures a first argument too */
   lua_settop(L, 2);
   lua_removekey(L, 1);
   return 0;

+ 30 - 1
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 2.64 2018/02/23 13:13:31 roberto Exp roberto $
+** $Id: ltm.c,v 2.65 2018/02/26 14:16:05 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -38,6 +38,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
 void luaT_init (lua_State *L) {
   static const char *const luaT_eventname[] = {  /* ORDER TM */
     "__index", "__newindex",
+    "__undef", "__isdef",
     "__gc", "__mode", "__len", "__eq",
     "__add", "__sub", "__mul", "__mod", "__pow",
     "__div", "__idiv",
@@ -248,3 +249,31 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
   for (; i < wanted; i++)   /* complete required results with nil */
     setnilvalue(s2v(where + i));
 }
+
+
+int luaT_keydef (lua_State *L, TValue *obj, TValue *key, int remove) {
+  const TValue *tm;
+  TMS event = remove ? TM_UNDEF : TM_ISDEF;
+  if (!ttistable(obj)) {  /* not a table? */
+    tm = luaT_gettmbyobj(L, obj, event);  /* get its metamethod */
+    if (notm(tm)) {  /* no metamethod? */
+      const char *msg = remove ? "remove key from" : "check key from";
+      luaG_typeerror(L, obj, msg);  /* error */
+    }
+    /* else will call metamethod 'tm' */
+  }
+  else {  /* 'obj' is a table */
+    Table *t = hvalue(obj);
+    tm = fasttm(L, t->metatable, event);
+    if (tm == NULL) {  /* no metamethod? */
+      const TValue *val = luaH_get(t, key);  /* get entry */
+      int res = !isempty(val);  /* true if entry is not empty */
+      if (remove && res)  /* key is present and should be removed? */
+        setempty(cast(TValue*, val));  /* remove it */
+      return res;
+    }
+    /* else will call metamethod 'tm' */
+  }
+  luaT_callTMres(L, tm, obj, key, L->top);
+  return !l_isfalse(s2v(L->top));
+}

+ 5 - 1
ltm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.h,v 2.32 2018/02/17 19:20:00 roberto Exp roberto $
+** $Id: ltm.h,v 2.33 2018/02/23 13:13:31 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -19,6 +19,8 @@
 typedef enum {
   TM_INDEX,
   TM_NEWINDEX,
+  TM_UNDEF,
+  TM_ISDEF,
   TM_GC,
   TM_MODE,
   TM_LEN,
@@ -89,5 +91,7 @@ LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
 LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
                                               StkId where, int wanted);
 
+LUAI_FUNC int luaT_keydef (lua_State *L, TValue *obj, TValue *key, int remove);
+
 
 #endif