diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-29 16:16:05 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-29 16:16:05 +0200 |
| commit | d47758d58d532a9716ad4fd85cc806704df13735 (patch) | |
| tree | 0d5a58ee870b5ecea789cbef17400f4489d30b73 | |
| parent | a2be64b72e7ef8efc0fd457d4f50a6d796533401 (diff) | |
| download | lanes-d47758d58d532a9716ad4fd85cc806704df13735.tar.gz lanes-d47758d58d532a9716ad4fd85cc806704df13735.tar.bz2 lanes-d47758d58d532a9716ad4fd85cc806704df13735.zip | |
Boyscouting deep.cpp|h
| -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 | } |
