*** empty log message ***
[luabind.git] / src / ref.cpp
blobec5b88c015d38c7c05aefe1ecbf2d768ab6c5443
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/detail/ref.hpp>
25 #include <luabind/lua_include.hpp>
27 namespace luabind { namespace detail
30 // most of the code in this file comes from
31 // lauxlib.c in lua distribution
33 /******************************************************************************
34 * Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved.
36 * Permission is hereby granted, free of charge, to any person obtaining
37 * a copy of this software and associated documentation files (the
38 * "Software"), to deal in the Software without restriction, including
39 * without limitation the rights to use, copy, modify, merge, publish,
40 * distribute, sublicense, and/or sell copies of the Software, and to
41 * permit persons to whom the Software is furnished to do so, subject to
42 * the following conditions:
44 * The above copyright notice and this permission notice shall be
45 * included in all copies or substantial portions of the Software.
47 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
50 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
51 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
52 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
53 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54 ******************************************************************************/
56 enum
58 // the number of reserved references
59 RESERVED_REFS = 2,
61 // free list of references
62 FREELIST_REF = 1,
64 // array sizes (not used here)
65 ARRAYSIZE_REF = 2
68 int checkint (lua_State *L, int topop)
70 int n = (int)lua_tonumber(L, -1);
71 if (n == 0 && !lua_isnumber(L, -1)) n = -1;
72 lua_pop(L, topop);
73 return n;
77 void getsizes (lua_State *L)
79 lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);
80 if (lua_isnil(L, -1)) { /* no `size' table? */
81 lua_pop(L, 1); /* remove nil */
82 lua_newtable(L); /* create it */
83 lua_pushvalue(L, -1); /* `size' will be its own metatable */
84 lua_setmetatable(L, -2);
85 lua_pushliteral(L, "__mode");
86 lua_pushliteral(L, "k");
87 lua_rawset(L, -3); /* metatable(N).__mode = "k" */
88 lua_pushvalue(L, -1);
89 lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */
93 void luaL_setn (lua_State *L, int t, int n)
95 lua_pushliteral(L, "n");
96 lua_rawget(L, t);
97 if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
98 lua_pushliteral(L, "n"); /* use it */
99 lua_pushnumber(L, n);
100 lua_rawset(L, t);
102 else { /* use `sizes' */
103 getsizes(L);
104 lua_pushvalue(L, t);
105 lua_pushnumber(L, n);
106 lua_rawset(L, -3); /* sizes[t] = n */
107 lua_pop(L, 1); /* remove `sizes' */
111 int luaL_getn (lua_State *L, int t)
113 int n;
114 lua_pushliteral(L, "n"); /* try t.n */
115 lua_rawget(L, t);
116 if ((n = checkint(L, 1)) >= 0) return n;
117 getsizes(L); /* else try sizes[t] */
118 lua_pushvalue(L, t);
119 lua_rawget(L, -2);
120 if ((n = checkint(L, 2)) >= 0) return n;
121 for (n = 1; ; n++) { /* else must count elements */
122 lua_rawgeti(L, t, n);
123 if (lua_isnil(L, -1)) break;
124 lua_pop(L, 1);
126 lua_pop(L, 1);
127 return n - 1;
131 // based on luaL_ref
132 int ref(lua_State *L)
134 int t = LUA_REGISTRYINDEX;
136 int ref;
137 if (lua_isnil(L, -1))
139 lua_pop(L, 1); /* remove from stack */
140 return LUA_REFNIL; /* `nil' has a unique fixed reference */
143 lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
144 ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */
145 lua_pop(L, 1); /* remove it from stack */
146 if (ref != 0) { /* any free element? */
147 lua_rawgeti(L, t, ref); /* remove it from list */
148 lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
150 else { /* no free elements */
151 ref = ::luabind::detail::luaL_getn(L, t);
152 if (ref < RESERVED_REFS)
153 ref = RESERVED_REFS; /* skip reserved references */
154 ref++; /* create new reference */
155 ::luabind::detail::luaL_setn(L, t, ref);
157 lua_rawseti(L, t, ref);
158 return ref;
161 void unref(lua_State *L, int ref)
163 int t = LUA_REGISTRYINDEX;
164 if (ref >= 0) {
165 lua_rawgeti(L, t, FREELIST_REF);
166 lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
167 lua_pushnumber(L, ref);
168 lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */