diff options
-rw-r--r-- | deep_test/deep_test.cpp | 26 | ||||
-rw-r--r-- | docs/index.html | 10 | ||||
-rw-r--r-- | src/deep.cpp | 182 | ||||
-rw-r--r-- | src/deep.h | 21 | ||||
-rw-r--r-- | src/intercopycontext.cpp | 2 |
5 files changed, 128 insertions, 113 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp index 9ca88df..0a09921 100644 --- a/deep_test/deep_test.cpp +++ b/deep_test/deep_test.cpp | |||
@@ -13,12 +13,12 @@ class MyDeepFactory : public DeepFactory | |||
13 | 13 | ||
14 | private: | 14 | private: |
15 | 15 | ||
16 | [[nodiscard]] DeepPrelude* newDeepObjectInternal(lua_State* L) const override; | 16 | void createMetatable(lua_State* const L_) const override |
17 | void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override; | ||
18 | void createMetatable(lua_State* L_) const override | ||
19 | { | 17 | { |
20 | luaL_getmetatable(L_, "deep"); | 18 | luaL_getmetatable(L_, "deep"); |
21 | } | 19 | } |
20 | void deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* o_) const override; | ||
21 | [[nodiscard]] DeepPrelude* newDeepObjectInternal(lua_State* const L_) const override; | ||
22 | [[nodiscard]] std::string_view moduleName() const override { return std::string_view{ "deep_test" }; } | 22 | [[nodiscard]] std::string_view moduleName() const override { return std::string_view{ "deep_test" }; } |
23 | }; | 23 | }; |
24 | /*static*/ MyDeepFactory MyDeepFactory::Instance{}; | 24 | /*static*/ MyDeepFactory MyDeepFactory::Instance{}; |
@@ -33,27 +33,27 @@ struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a De | |||
33 | 33 | ||
34 | // ################################################################################################# | 34 | // ################################################################################################# |
35 | 35 | ||
36 | DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const | 36 | DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* const L_) const |
37 | { | 37 | { |
38 | MyDeepUserdata* deep_test = new MyDeepUserdata{ MyDeepFactory::Instance }; | 38 | MyDeepUserdata* const _deep_test{ new MyDeepUserdata{ MyDeepFactory::Instance } }; |
39 | return deep_test; | 39 | return _deep_test; |
40 | } | 40 | } |
41 | 41 | ||
42 | // ################################################################################################# | 42 | // ################################################################################################# |
43 | 43 | ||
44 | void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const | 44 | void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* const o_) const |
45 | { | 45 | { |
46 | MyDeepUserdata* deep_test = static_cast<MyDeepUserdata*>(o_); | 46 | MyDeepUserdata* const _deep_test{ static_cast<MyDeepUserdata*>(o_) }; |
47 | delete deep_test; | 47 | delete _deep_test; |
48 | } | 48 | } |
49 | 49 | ||
50 | // ################################################################################################# | 50 | // ################################################################################################# |
51 | 51 | ||
52 | [[nodiscard]] static int deep_set(lua_State* L) | 52 | [[nodiscard]] static int deep_set(lua_State* const L_) |
53 | { | 53 | { |
54 | MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; | 54 | MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, 1)) }; |
55 | lua_Integer i = lua_tointeger( L, 2); | 55 | lua_Integer i = lua_tointeger(L_, 2); |
56 | self->val = i; | 56 | _self->val = i; |
57 | return 0; | 57 | return 0; |
58 | } | 58 | } |
59 | 59 | ||
diff --git a/docs/index.html b/docs/index.html index 8385480..19cc442 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -958,7 +958,7 @@ | |||
958 | </table> | 958 | </table> |
959 | 959 | ||
960 | <p> | 960 | <p> |
961 | Only available if lane tracking feature is compiled (see <tt>HAVE_LANE_TRACKING</tt> in <tt>lanes.cpp</tt>) and <a href="#track_lanes"><tt>track_lanes</tt></a> is set. | 961 | Only available if lane tracking is enabled by setting <a href="#track_lanes"><tt>track_lanes</tt></a>. |
962 | <br/> | 962 | <br/> |
963 | Returns an array table where each entry is a table containing a lane's name and status. Returns <tt>nil</tt> if no lane is running. | 963 | Returns an array table where each entry is a table containing a lane's name and status. Returns <tt>nil</tt> if no lane is running. |
964 | </p> | 964 | </p> |
@@ -1743,9 +1743,9 @@ class MyDeepFactory : public DeepFactory | |||
1743 | { | 1743 | { |
1744 | private: | 1744 | private: |
1745 | 1745 | ||
1746 | DeepPrelude* newDeepObjectInternal(lua_State* L) const override; | 1746 | void createMetatable(lua_State* const L_) const override; |
1747 | void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override; | 1747 | void deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* o_) const override; |
1748 | void createMetatable(lua_State* L) const override; | 1748 | DeepPrelude* newDeepObjectInternal(lua_State* const L_) const override; |
1749 | std::string_view moduleName() const override; | 1749 | std::string_view moduleName() const override; |
1750 | }; | 1750 | }; |
1751 | 1751 | ||
@@ -1757,7 +1757,7 @@ static MyDeepFactory g_MyDeepFactory; | |||
1757 | <li><tt>createMetatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>createMetatable</tt> should only be invoked once per state). Just push the metatable on the stack.</li> | 1757 | <li><tt>createMetatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>createMetatable</tt> should only be invoked once per state). Just push the metatable on the stack.</li> |
1758 | <li><tt>moduleName</tt>: requests the name of the module that exports the factory, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the factory pointer is still held.</li> | 1758 | <li><tt>moduleName</tt>: requests the name of the module that exports the factory, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the factory pointer is still held.</li> |
1759 | </ul> | 1759 | </ul> |
1760 | Take a look at <tt>LindaFactory</tt> in <tt>linda.cpp</tt> or <tt>MyDeepFactory</tt> in <tt>deep_test.cpp</tt>. | 1760 | Take a look at <tt>LindaFactory</tt> in <tt>lindafactory.cpp</tt> or <tt>MyDeepFactory</tt> in <tt>deep_test.cpp</tt>. |
1761 | </li> | 1761 | </li> |
1762 | <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile <tt>compat.cpp deep.cpp</tt> into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. | 1762 | <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile <tt>compat.cpp deep.cpp</tt> into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. |
1763 | <li>Instanciate your userdata using <tt>yourFactoryObject.pushDeepUserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given a <tt>factory</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> | 1763 | <li>Instanciate your userdata using <tt>yourFactoryObject.pushDeepUserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given a <tt>factory</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> |
diff --git a/src/deep.cpp b/src/deep.cpp index dfa3579..f5716bf 100644 --- a/src/deep.cpp +++ b/src/deep.cpp | |||
@@ -60,51 +60,80 @@ static constexpr RegistryUniqueKey kDeepLookupRegKey{ 0xC6788345703C6059ull }; | |||
60 | static constexpr RegistryUniqueKey kDeepProxyCacheRegKey{ 0xEBCD49AE1A3DD35Eull }; | 60 | static constexpr RegistryUniqueKey kDeepProxyCacheRegKey{ 0xEBCD49AE1A3DD35Eull }; |
61 | 61 | ||
62 | // ################################################################################################# | 62 | // ################################################################################################# |
63 | // ################################################################################################# | ||
64 | namespace { | ||
65 | // ############################################################################################# | ||
66 | // ############################################################################################# | ||
67 | |||
68 | /* | ||
69 | * void= mt.__gc( proxy_ud ) | ||
70 | * | ||
71 | * End of life for a proxy object; reduce the deep reference count and clean it up if reaches 0. | ||
72 | * | ||
73 | */ | ||
74 | [[nodiscard]] static int DeepGC(lua_State* const L_) | ||
75 | { | ||
76 | DeepPrelude* const* const _proxy{ lua_tofulluserdata<DeepPrelude*>(L_, 1) }; | ||
77 | DeepPrelude* const _p{ *_proxy }; | ||
78 | |||
79 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | ||
80 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
81 | bool const isLastRef{ _p->refcount.fetch_sub(1, std::memory_order_relaxed) == 1 }; | ||
82 | |||
83 | if (isLastRef) { | ||
84 | // retrieve wrapped __gc, if any | ||
85 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: self __gc? | ||
86 | if (!lua_isnil(L_, -1)) { | ||
87 | lua_insert(L_, -2); // L_: __gc self | ||
88 | lua_call(L_, 1, 0); // L_: | ||
89 | } else { | ||
90 | // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered | ||
91 | lua_pop(L_, 2); // L_: | ||
92 | } | ||
93 | DeepFactory::DeleteDeepObject(L_, _p); | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
63 | 97 | ||
64 | /* | 98 | // ############################################################################################# |
65 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | ||
66 | * Pops the both values off the stack. | ||
67 | */ | ||
68 | void DeepFactory::storeDeepLookup(lua_State* L_) const | ||
69 | { | ||
70 | // the deep metatable is at the top of the stack // L_: mt | ||
71 | STACK_GROW(L_, 3); | ||
72 | STACK_CHECK_START_REL(L_, 0); // L_: mt | ||
73 | std::ignore = kDeepLookupRegKey.getSubTable(L_, 0, 0); // L_: mt {} | ||
74 | lua_pushvalue(L_, -2); // L_: mt {} mt | ||
75 | lua_pushlightuserdata(L_, std::bit_cast<void*>(this)); // L_: mt {} mt factory | ||
76 | lua_rawset(L_, -3); // L_: mt {} | ||
77 | STACK_CHECK(L_, 1); | ||
78 | 99 | ||
79 | lua_pushlightuserdata(L_, std::bit_cast<void*>(this)); // L_: mt {} factory | 100 | // Pops the key (metatable or factory) off the stack, and replaces with the deep lookup value (factory/metatable/nil). |
80 | lua_pushvalue(L_, -3); // L_: mt {} factory mt | 101 | static void LookupDeep(lua_State* const L_) |
81 | lua_rawset(L_, -3); // L_: mt {} | 102 | { |
82 | STACK_CHECK(L_, 1); | 103 | STACK_GROW(L_, 1); |
104 | STACK_CHECK_START_REL(L_, 1); // L_: a | ||
105 | kDeepLookupRegKey.pushValue(L_); // L_: a {} | ||
106 | if (!lua_isnil(L_, -1)) { | ||
107 | lua_insert(L_, -2); // L_: {} a | ||
108 | lua_rawget(L_, -2); // L_: {} b | ||
109 | } | ||
110 | lua_remove(L_, -2); // L_: a|b | ||
111 | STACK_CHECK(L_, 1); | ||
112 | } | ||
83 | 113 | ||
84 | lua_pop(L_, 1); // L_: mt | 114 | // ############################################################################################# |
85 | STACK_CHECK(L_, 0); | 115 | // ############################################################################################# |
86 | } | 116 | } // namespace |
117 | // ################################################################################################# | ||
118 | // ################################################################################################# | ||
87 | 119 | ||
88 | // ################################################################################################# | 120 | // ################################################################################################# |
121 | // ################################################################################################# | ||
122 | // ####################################### DeepFactory ############################################# | ||
123 | // ################################################################################################# | ||
124 | // ################################################################################################# | ||
89 | 125 | ||
90 | // Pops the key (metatable or factory) off the stack, and replaces with the deep lookup value (factory/metatable/nil). | 126 | void DeepFactory::DeleteDeepObject(lua_State* const L_, DeepPrelude* const o_) |
91 | static void LookupDeep(lua_State* L_) | ||
92 | { | 127 | { |
93 | STACK_GROW(L_, 1); | 128 | STACK_CHECK_START_REL(L_, 0); |
94 | STACK_CHECK_START_REL(L_, 1); // L_: a | 129 | o_->factory.deleteDeepObjectInternal(L_, o_); |
95 | kDeepLookupRegKey.pushValue(L_); // L_: a {} | 130 | STACK_CHECK(L_, 0); |
96 | if (!lua_isnil(L_, -1)) { | ||
97 | lua_insert(L_, -2); // L_: {} a | ||
98 | lua_rawget(L_, -2); // L_: {} b | ||
99 | } | ||
100 | lua_remove(L_, -2); // L_: a|b | ||
101 | STACK_CHECK(L_, 1); | ||
102 | } | 131 | } |
103 | 132 | ||
104 | // ################################################################################################# | 133 | // ################################################################################################# |
105 | 134 | ||
106 | // Return the registered factory for 'index' (deep userdata proxy), or nullptr if 'index' is not a deep userdata proxy. | 135 | // Return the registered factory for 'index' (deep userdata proxy), or nullptr if 'index' is not a deep userdata proxy. |
107 | [[nodiscard]] DeepFactory* LookupFactory(lua_State* L_, int index_, LookupMode mode_) | 136 | [[nodiscard]] DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, int const index_, LookupMode const mode_) |
108 | { | 137 | { |
109 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | 138 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
110 | if (mode_ == LookupMode::FromKeeper) { | 139 | if (mode_ == LookupMode::FromKeeper) { |
@@ -134,47 +163,6 @@ static void LookupDeep(lua_State* L_) | |||
134 | 163 | ||
135 | // ################################################################################################# | 164 | // ################################################################################################# |
136 | 165 | ||
137 | void DeepFactory::DeleteDeepObject(lua_State* L_, DeepPrelude* o_) | ||
138 | { | ||
139 | STACK_CHECK_START_REL(L_, 0); | ||
140 | o_->factory.deleteDeepObjectInternal(L_, o_); | ||
141 | STACK_CHECK(L_, 0); | ||
142 | } | ||
143 | |||
144 | // ################################################################################################# | ||
145 | |||
146 | /* | ||
147 | * void= mt.__gc( proxy_ud ) | ||
148 | * | ||
149 | * End of life for a proxy object; reduce the deep reference count and clean it up if reaches 0. | ||
150 | * | ||
151 | */ | ||
152 | [[nodiscard]] static int deep_userdata_gc(lua_State* L_) | ||
153 | { | ||
154 | DeepPrelude* const* const _proxy{ lua_tofulluserdata<DeepPrelude*>(L_, 1) }; | ||
155 | DeepPrelude* const _p{ *_proxy }; | ||
156 | |||
157 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | ||
158 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
159 | bool const isLastRef{ _p->refcount.fetch_sub(1, std::memory_order_relaxed) == 1 }; | ||
160 | |||
161 | if (isLastRef) { | ||
162 | // retrieve wrapped __gc, if any | ||
163 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: self __gc? | ||
164 | if (!lua_isnil(L_, -1)) { | ||
165 | lua_insert(L_, -2); // L_: __gc self | ||
166 | lua_call(L_, 1, 0); // L_: | ||
167 | } else { | ||
168 | // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered | ||
169 | lua_pop(L_, 2); // L_: | ||
170 | } | ||
171 | DeepFactory::DeleteDeepObject(L_, _p); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | // ################################################################################################# | ||
177 | |||
178 | /* | 166 | /* |
179 | * Push a proxy userdata on the stack. | 167 | * Push a proxy userdata on the stack. |
180 | * raises an error in case of problem (error cannot happen with mode_ == LookupMode::ToKeeper) | 168 | * raises an error in case of problem (error cannot happen with mode_ == LookupMode::ToKeeper) |
@@ -182,7 +170,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L_, DeepPrelude* o_) | |||
182 | * Initializes necessary structures if it's the first time 'factory' is being used in | 170 | * Initializes necessary structures if it's the first time 'factory' is being used in |
183 | * this Lua state (metatable, registring it). Otherwise, increments the reference count. | 171 | * this Lua state (metatable, registring it). Otherwise, increments the reference count. |
184 | */ | 172 | */ |
185 | void DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, LookupMode mode_, lua_State* errL_) | 173 | void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, int const nuv_, LookupMode const mode_, lua_State* const errL_) |
186 | { | 174 | { |
187 | STACK_CHECK_START_REL(L_, 0); | 175 | STACK_CHECK_START_REL(L_, 0); |
188 | kDeepProxyCacheRegKey.getSubTableMode(L_, "v"); // L_: DPC | 176 | kDeepProxyCacheRegKey.getSubTableMode(L_, "v"); // L_: DPC |
@@ -208,8 +196,8 @@ void DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, L | |||
208 | prelude_->refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data | 196 | prelude_->refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data |
209 | 197 | ||
210 | // Get/create metatable for 'factory' (in this state) | 198 | // Get/create metatable for 'factory' (in this state) |
211 | DeepFactory& factory = prelude_->factory; | 199 | DeepFactory& _factory = prelude_->factory; |
212 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&factory)); // L_: DPC proxy factory | 200 | lua_pushlightuserdata(L_, std::bit_cast<void*>(&_factory)); // L_: DPC proxy _factory |
213 | LookupDeep(L_); // L_: DPC proxy metatable|nil | 201 | LookupDeep(L_); // L_: DPC proxy metatable|nil |
214 | 202 | ||
215 | if (lua_isnil(L_, -1)) { // No metatable yet. | 203 | if (lua_isnil(L_, -1)) { // No metatable yet. |
@@ -217,7 +205,7 @@ void DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, L | |||
217 | int const _oldtop{ lua_gettop(L_) }; | 205 | int const _oldtop{ lua_gettop(L_) }; |
218 | // 1 - make one and register it | 206 | // 1 - make one and register it |
219 | if (mode_ != LookupMode::ToKeeper) { | 207 | if (mode_ != LookupMode::ToKeeper) { |
220 | factory.createMetatable(L_); // L_: DPC proxy metatable | 208 | _factory.createMetatable(L_); // L_: DPC proxy metatable |
221 | if (lua_gettop(L_) - _oldtop != 1 || !lua_istable(L_, -1)) { | 209 | if (lua_gettop(L_) - _oldtop != 1 || !lua_istable(L_, -1)) { |
222 | // factory didn't push exactly 1 value, or the value it pushed is not a table: ERROR! | 210 | // factory didn't push exactly 1 value, or the value it pushed is not a table: ERROR! |
223 | raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value"); | 211 | raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value"); |
@@ -232,18 +220,18 @@ void DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, L | |||
232 | if (lua_isnil(L_, -1)) { | 220 | if (lua_isnil(L_, -1)) { |
233 | // Add our own '__gc' method | 221 | // Add our own '__gc' method |
234 | lua_pop(L_, 1); // L_: DPC proxy metatable | 222 | lua_pop(L_, 1); // L_: DPC proxy metatable |
235 | lua_pushcfunction(L_, deep_userdata_gc); // L_: DPC proxy metatable deep_userdata_gc | 223 | lua_pushcfunction(L_, DeepGC); // L_: DPC proxy metatable DeepGC |
236 | } else { | 224 | } else { |
237 | // Add our own '__gc' method wrapping the original | 225 | // Add our own '__gc' method wrapping the original |
238 | lua_pushcclosure(L_, deep_userdata_gc, 1); // L_: DPC proxy metatable deep_userdata_gc | 226 | lua_pushcclosure(L_, DeepGC, 1); // L_: DPC proxy metatable DeepGC |
239 | } | 227 | } |
240 | lua_setfield(L_, -2, "__gc"); // L_: DPC proxy metatable | 228 | lua_setfield(L_, -2, "__gc"); // L_: DPC proxy metatable |
241 | 229 | ||
242 | // Memorize for later rounds | 230 | // Memorize for later rounds |
243 | factory.storeDeepLookup(L_); | 231 | _factory.storeDeepLookup(L_); |
244 | 232 | ||
245 | // 2 - cause the target state to require the module that exported the factory | 233 | // 2 - cause the target state to require the module that exported the factory |
246 | if (std::string_view const _modname{ factory.moduleName() }; !_modname.empty()) { // we actually got a module name | 234 | if (std::string_view const _modname{ _factory.moduleName() }; !_modname.empty()) { // we actually got a module name |
247 | // L.registry._LOADED exists without having registered the 'package' library. | 235 | // L.registry._LOADED exists without having registered the 'package' library. |
248 | lua_getglobal(L_, "require"); // L_: DPC proxy metatable require() | 236 | lua_getglobal(L_, "require"); // L_: DPC proxy metatable require() |
249 | // check that the module is already loaded (or being loaded, we are happy either way) | 237 | // check that the module is already loaded (or being loaded, we are happy either way) |
@@ -310,7 +298,7 @@ void DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_, int nuv_, L | |||
310 | * | 298 | * |
311 | * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()' | 299 | * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()' |
312 | */ | 300 | */ |
313 | int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const | 301 | int DeepFactory::pushDeepUserdata(DestState const L_, int const nuv_) const |
314 | { | 302 | { |
315 | STACK_GROW(L_, 1); | 303 | STACK_GROW(L_, 1); |
316 | STACK_CHECK_START_REL(L_, 0); | 304 | STACK_CHECK_START_REL(L_, 0); |
@@ -343,12 +331,38 @@ int DeepFactory::pushDeepUserdata(DestState L_, int nuv_) const | |||
343 | // ################################################################################################# | 331 | // ################################################################################################# |
344 | 332 | ||
345 | /* | 333 | /* |
334 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | ||
335 | * Pops the both values off the stack. | ||
336 | */ | ||
337 | void DeepFactory::storeDeepLookup(lua_State* const L_) const | ||
338 | { | ||
339 | // the deep metatable is at the top of the stack // L_: mt | ||
340 | STACK_GROW(L_, 3); | ||
341 | STACK_CHECK_START_REL(L_, 0); // L_: mt | ||
342 | std::ignore = kDeepLookupRegKey.getSubTable(L_, 0, 0); // L_: mt {} | ||
343 | lua_pushvalue(L_, -2); // L_: mt {} mt | ||
344 | lua_pushlightuserdata(L_, std::bit_cast<void*>(this)); // L_: mt {} mt factory | ||
345 | lua_rawset(L_, -3); // L_: mt {} | ||
346 | STACK_CHECK(L_, 1); | ||
347 | |||
348 | lua_pushlightuserdata(L_, std::bit_cast<void*>(this)); // L_: mt {} factory | ||
349 | lua_pushvalue(L_, -3); // L_: mt {} factory mt | ||
350 | lua_rawset(L_, -3); // L_: mt {} | ||
351 | STACK_CHECK(L_, 1); | ||
352 | |||
353 | lua_pop(L_, 1); // L_: mt | ||
354 | STACK_CHECK(L_, 0); | ||
355 | } | ||
356 | |||
357 | // ################################################################################################# | ||
358 | |||
359 | /* | ||
346 | * Access deep userdata through a proxy. | 360 | * Access deep userdata through a proxy. |
347 | * | 361 | * |
348 | * Reference count is not changed, and access to the deep userdata is not | 362 | * Reference count is not changed, and access to the deep userdata is not |
349 | * serialized. It is the module's responsibility to prevent conflicting usage. | 363 | * serialized. It is the module's responsibility to prevent conflicting usage. |
350 | */ | 364 | */ |
351 | DeepPrelude* DeepFactory::toDeep(lua_State* L_, int index_) const | 365 | DeepPrelude* DeepFactory::toDeep(lua_State* const L_, int const index_) const |
352 | { | 366 | { |
353 | STACK_CHECK_START_REL(L_, 0); | 367 | STACK_CHECK_START_REL(L_, 0); |
354 | // ensure it is actually a deep userdata we created | 368 | // ensure it is actually a deep userdata we created |
@@ -63,21 +63,22 @@ class DeepFactory | |||
63 | DeepFactory& operator=(DeepFactory const&&) = delete; | 63 | DeepFactory& operator=(DeepFactory const&&) = delete; |
64 | 64 | ||
65 | private: | 65 | private: |
66 | void storeDeepLookup(lua_State* L_) const; | ||
67 | // NVI: private overrides | 66 | // NVI: private overrides |
68 | [[nodiscard]] virtual DeepPrelude* newDeepObjectInternal(lua_State* L_) const = 0; | 67 | virtual void createMetatable(lua_State* const L_) const = 0; |
69 | virtual void deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const = 0; | 68 | virtual void deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* const o_) const = 0; |
70 | virtual void createMetatable(lua_State* L_) const = 0; | 69 | [[nodiscard]] virtual DeepPrelude* newDeepObjectInternal(lua_State* const L_) const = 0; |
71 | [[nodiscard]] virtual std::string_view moduleName() const = 0; | 70 | [[nodiscard]] virtual std::string_view moduleName() const = 0; |
72 | 71 | ||
72 | private: | ||
73 | void storeDeepLookup(lua_State* const L_) const; | ||
74 | |||
73 | public: | 75 | public: |
74 | // NVI: public interface | 76 | // NVI: public interface |
75 | [[nodiscard]] int pushDeepUserdata(DestState L_, int nuv_) const; | 77 | static void DeleteDeepObject(lua_State* const L_, DeepPrelude* const o_); |
76 | [[nodiscard]] DeepPrelude* toDeep(lua_State* L_, int index_) const; | 78 | [[nodiscard]] static DeepFactory* LookupFactory(lua_State* const L_, int const index_, LookupMode const mode_); |
77 | static void DeleteDeepObject(lua_State* L_, DeepPrelude* o_); | 79 | static void PushDeepProxy(DestState const L_, DeepPrelude* const o_, int const nuv_, LookupMode const mode_, lua_State* const errL_); |
78 | static void PushDeepProxy(DestState L_, DeepPrelude* o_, int nuv_, LookupMode mode_, lua_State* errL_); | 80 | [[nodiscard]] int pushDeepUserdata(DestState const L_, int const nuv_) const; |
81 | [[nodiscard]] DeepPrelude* toDeep(lua_State* const L_, int const index_) const; | ||
79 | }; | 82 | }; |
80 | 83 | ||
81 | // ################################################################################################# | 84 | // ################################################################################################# |
82 | |||
83 | [[nodiscard]] DeepFactory* LookupFactory(lua_State* L_, int index_, LookupMode mode_); | ||
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 044b197..eddb309 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
@@ -723,7 +723,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
723 | // Returns false if not a deep userdata, else true (unless an error occured) | 723 | // Returns false if not a deep userdata, else true (unless an error occured) |
724 | [[nodiscard]] bool InterCopyContext::tryCopyDeep() const | 724 | [[nodiscard]] bool InterCopyContext::tryCopyDeep() const |
725 | { | 725 | { |
726 | DeepFactory* const _factory{ LookupFactory(L1, L1_i, mode) }; | 726 | DeepFactory* const _factory{ DeepFactory::LookupFactory(L1, L1_i, mode) }; |
727 | if (_factory == nullptr) { | 727 | if (_factory == nullptr) { |
728 | return false; // not a deep userdata | 728 | return false; // not a deep userdata |
729 | } | 729 | } |