test_free_functions failed to keep the stack clean.
[luabind.git] / src / ref.cpp
blobf227fe2d0aea406a1438d8a05f8c491bc23f10ca
1 // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
23 #include <algorithm>
24 #include <luabind/config.hpp>
25 #include <luabind/detail/ref.hpp>
26 #include <luabind/lua_include.hpp>
27 #include <luabind/detail/debug.hpp>
29 namespace luabind { namespace detail
32 // most of the code in this file comes from
33 // lauxlib.c in lua distribution
35 /******************************************************************************
36 * Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved.
38 * Permission is hereby granted, free of charge, to any person obtaining
39 * a copy of this software and associated documentation files (the
40 * "Software"), to deal in the Software without restriction, including
41 * without limitation the rights to use, copy, modify, merge, publish,
42 * distribute, sublicense, and/or sell copies of the Software, and to
43 * permit persons to whom the Software is furnished to do so, subject to
44 * the following conditions:
46 * The above copyright notice and this permission notice shall be
47 * included in all copies or substantial portions of the Software.
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
50 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56 ******************************************************************************/
58 enum
60 // the number of reserved references
61 RESERVED_REFS = 2,
63 // free list of references
64 FREELIST_REF = 1,
66 // array sizes (not used here)
67 ARRAYSIZE_REF = 2
70 int checkint (lua_State *L, int topop)
72 int n = (int)lua_tonumber(L, -1);
73 if (n == 0 && !lua_isnumber(L, -1)) n = -1;
74 lua_pop(L, topop);
75 return n;
79 void getsizes (lua_State *L)
81 lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);
82 if (lua_isnil(L, -1)) { /* no `size' table? */
83 lua_pop(L, 1); /* remove nil */
84 lua_newtable(L); /* create it */
85 lua_pushvalue(L, -1); /* `size' will be its own metatable */
86 lua_setmetatable(L, -2);
87 lua_pushliteral(L, "__mode");
88 lua_pushliteral(L, "k");
89 lua_rawset(L, -3); /* metatable(N).__mode = "k" */
90 lua_pushvalue(L, -1);
91 lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */
95 void luaL_setn (lua_State *L, int t, int n)
97 lua_pushliteral(L, "n");
98 lua_rawget(L, t);
99 if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
100 lua_pushliteral(L, "n"); /* use it */
101 lua_pushnumber(L, n);
102 lua_rawset(L, t);
104 else { /* use `sizes' */
105 getsizes(L);
106 lua_pushvalue(L, t);
107 lua_pushnumber(L, n);
108 lua_rawset(L, -3); /* sizes[t] = n */
109 lua_pop(L, 1); /* remove `sizes' */
113 int luaL_getn (lua_State *L, int t)
115 int n;
116 lua_pushliteral(L, "n"); /* try t.n */
117 lua_rawget(L, t);
118 if ((n = checkint(L, 1)) >= 0) return n;
119 getsizes(L); /* else try sizes[t] */
120 lua_pushvalue(L, t);
121 lua_rawget(L, -2);
122 if ((n = checkint(L, 2)) >= 0) return n;
123 for (n = 1; ; n++) { /* else must count elements */
124 lua_rawgeti(L, t, n);
125 if (lua_isnil(L, -1)) break;
126 lua_pop(L, 1);
128 lua_pop(L, 1);
129 return n - 1;
133 // based on luaL_ref
134 int LUABIND_API ref(lua_State *L)
136 int t = LUA_REGISTRYINDEX;
138 int ref;
139 if (lua_isnil(L, -1))
141 lua_pop(L, 1); /* remove from stack */
142 return LUA_REFNIL; /* `nil' has a unique fixed reference */
145 lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
146 ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */
147 lua_pop(L, 1); /* remove it from stack */
148 if (ref != 0) { /* any free element? */
149 lua_rawgeti(L, t, ref); /* remove it from list */
150 lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
152 else { /* no free elements */
153 ref = ::luabind::detail::luaL_getn(L, t);
154 if (ref < RESERVED_REFS)
155 ref = RESERVED_REFS; /* skip reserved references */
156 ref++; /* create new reference */
157 ::luabind::detail::luaL_setn(L, t, ref);
159 lua_rawseti(L, t, ref);
160 return ref;
163 void LUABIND_API unref(lua_State *L, int ref)
165 LUABIND_CHECK_STACK(L);
167 int t = LUA_REGISTRYINDEX;
168 if (ref >= 0) {
169 lua_rawgeti(L, t, FREELIST_REF);
170 lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
171 lua_pushnumber(L, ref);
172 lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */