diff options
Diffstat (limited to '')
-rw-r--r-- | src/lindafactory.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp new file mode 100644 index 0000000..81e472d --- /dev/null +++ b/src/lindafactory.cpp | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * LINDAFACTORY.CPP Copyright (c) 2024-, Benoit Germain | ||
3 | * | ||
4 | * Linda deep userdata factory | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | =============================================================================== | ||
9 | |||
10 | Copyright (C) 2024- benoit Germain <bnt.germain@gmail.com> | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE SOFTWARE. | ||
29 | |||
30 | =============================================================================== | ||
31 | */ | ||
32 | |||
33 | #include "lindafactory.h" | ||
34 | |||
35 | #include "linda.h" | ||
36 | |||
37 | // ################################################################################################# | ||
38 | |||
39 | void LindaFactory::createMetatable(lua_State* L_) const | ||
40 | { | ||
41 | STACK_CHECK_START_REL(L_, 0); | ||
42 | lua_newtable(L_); | ||
43 | // metatable is its own index | ||
44 | lua_pushvalue(L_, -1); | ||
45 | lua_setfield(L_, -2, "__index"); | ||
46 | |||
47 | // protect metatable from external access | ||
48 | lua_pushliteral(L_, "Linda"); | ||
49 | lua_setfield(L_, -2, "__metatable"); | ||
50 | |||
51 | // the linda functions | ||
52 | luaL_setfuncs(L_, mLindaMT, 0); | ||
53 | |||
54 | // some constants | ||
55 | kLindaBatched.pushKey(L_); | ||
56 | lua_setfield(L_, -2, "batched"); | ||
57 | |||
58 | kNilSentinel.pushKey(L_); | ||
59 | lua_setfield(L_, -2, "null"); | ||
60 | |||
61 | STACK_CHECK(L_, 1); | ||
62 | } | ||
63 | |||
64 | // ################################################################################################# | ||
65 | |||
66 | void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const | ||
67 | { | ||
68 | Linda* const linda{ static_cast<Linda*>(o_) }; | ||
69 | LUA_ASSERT(L_, linda); | ||
70 | Keeper* const myK{ linda->whichKeeper() }; | ||
71 | // if collected after the universe, keepers are already destroyed, and there is nothing to clear | ||
72 | if (myK) | ||
73 | { | ||
74 | // if collected from my own keeper, we can't acquire/release it | ||
75 | // because we are already inside a protected area, and trying to do so would deadlock! | ||
76 | bool const need_acquire_release{ myK->L != L_ }; | ||
77 | // Clean associated structures in the keeper state. | ||
78 | Keeper* const K{ need_acquire_release ? linda->acquireKeeper() : myK }; | ||
79 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | ||
80 | [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L_, linda, 0) }; | ||
81 | LUA_ASSERT(L_, result.has_value() && result.value() == 0); | ||
82 | if (need_acquire_release) | ||
83 | { | ||
84 | linda->releaseKeeper(K); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | delete linda; // operator delete overload ensures things go as expected | ||
89 | } | ||
90 | |||
91 | // ################################################################################################# | ||
92 | |||
93 | char const* LindaFactory::moduleName() const | ||
94 | { | ||
95 | // linda is a special case because we know lanes must be loaded from the main lua state | ||
96 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around | ||
97 | // in other words, forever. | ||
98 | return nullptr; | ||
99 | } | ||
100 | |||
101 | // ################################################################################################# | ||
102 | |||
103 | DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const | ||
104 | { | ||
105 | size_t name_len{ 0 }; | ||
106 | char const* linda_name{ nullptr }; | ||
107 | LindaGroup linda_group{ 0 }; | ||
108 | // should have a string and/or a number of the stack as parameters (name and group) | ||
109 | switch (lua_gettop(L_)) | ||
110 | { | ||
111 | default: // 0 | ||
112 | break; | ||
113 | |||
114 | case 1: // 1 parameter, either a name or a group | ||
115 | if (lua_type(L_, -1) == LUA_TSTRING) | ||
116 | { | ||
117 | linda_name = lua_tolstring(L_, -1, &name_len); | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; | ||
122 | } | ||
123 | break; | ||
124 | |||
125 | case 2: // 2 parameters, a name and group, in that order | ||
126 | linda_name = lua_tolstring(L_, -2, &name_len); | ||
127 | linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | // The deep data is allocated separately of Lua stack; we might no longer be around when last reference to it is being released. | ||
132 | // One can use any memory allocation scheme. Just don't use L's allocF because we don't know which state will get the honor of GCing the linda | ||
133 | Universe* const U{ universe_get(L_) }; | ||
134 | Linda* const linda{ new (U) Linda{ U, linda_group, linda_name, name_len } }; | ||
135 | return linda; | ||
136 | } | ||