aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deep_test/deep_test.cpp25
-rw-r--r--lanes-4.0.0-0.rockspec1
-rw-r--r--src/Makefile2
-rw-r--r--src/deep.h16
-rw-r--r--src/lanesconf.h6
-rw-r--r--src/linda.cpp164
-rw-r--r--src/linda.h5
-rw-r--r--src/lindafactory.cpp136
-rw-r--r--src/lindafactory.h28
9 files changed, 220 insertions, 163 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp
index 3a58d81..1931e6d 100644
--- a/deep_test/deep_test.cpp
+++ b/deep_test/deep_test.cpp
@@ -7,18 +7,21 @@
7 7
8class MyDeepFactory : public DeepFactory 8class MyDeepFactory : public DeepFactory
9{ 9{
10 public:
11
12 static MyDeepFactory Instance;
13
10 private: 14 private:
11 15
12 DeepPrelude* newDeepObjectInternal(lua_State* L) const override; 16 DeepPrelude* newDeepObjectInternal(lua_State* L) const override;
13 void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override; 17 void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override;
14 void createMetatable(lua_State* L) const override 18 void createMetatable(lua_State* L_) const override
15 { 19 {
16 luaL_getmetatable(L, "deep"); 20 luaL_getmetatable(L_, "deep");
17 } 21 }
18 char const* moduleName() const override { return "deep_test"; } 22 char const* moduleName() const override { return "deep_test"; }
19}; 23};
20 24/*static*/ MyDeepFactory MyDeepFactory::Instance{};
21static MyDeepFactory g_MyDeepFactory;
22 25
23// ################################################################################################# 26// #################################################################################################
24 27
@@ -32,7 +35,7 @@ struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a De
32 35
33DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const 36DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const
34{ 37{
35 MyDeepUserdata* deep_test = new MyDeepUserdata{ g_MyDeepFactory }; 38 MyDeepUserdata* deep_test = new MyDeepUserdata{ MyDeepFactory::Instance };
36 return deep_test; 39 return deep_test;
37} 40}
38 41
@@ -48,7 +51,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons
48 51
49[[nodiscard]] static int deep_set(lua_State* L) 52[[nodiscard]] static int deep_set(lua_State* L)
50{ 53{
51 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(g_MyDeepFactory.toDeep(L, 1)) }; 54 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
52 lua_Integer i = lua_tointeger( L, 2); 55 lua_Integer i = lua_tointeger( L, 2);
53 self->val = i; 56 self->val = i;
54 return 0; 57 return 0;
@@ -58,7 +61,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons
58 61
59[[nodiscard]] static int deep_setuv(lua_State* L) 62[[nodiscard]] static int deep_setuv(lua_State* L)
60{ 63{
61 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(g_MyDeepFactory.toDeep(L, 1)) }; 64 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
62 int uv = (int) luaL_optinteger(L, 2, 1); 65 int uv = (int) luaL_optinteger(L, 2, 1);
63 lua_settop( L, 3); 66 lua_settop( L, 3);
64 lua_pushboolean( L, lua_setiuservalue( L, 1, uv) != 0); 67 lua_pushboolean( L, lua_setiuservalue( L, 1, uv) != 0);
@@ -70,7 +73,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons
70// won't actually do anything as deep userdata don't have uservalue slots 73// won't actually do anything as deep userdata don't have uservalue slots
71[[nodiscard]] static int deep_getuv(lua_State* L) 74[[nodiscard]] static int deep_getuv(lua_State* L)
72{ 75{
73 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(g_MyDeepFactory.toDeep(L, 1)) }; 76 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
74 int uv = (int) luaL_optinteger(L, 2, 1); 77 int uv = (int) luaL_optinteger(L, 2, 1);
75 lua_getiuservalue( L, 1, uv); 78 lua_getiuservalue( L, 1, uv);
76 return 1; 79 return 1;
@@ -80,7 +83,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons
80 83
81[[nodiscard]] static int deep_tostring(lua_State* L) 84[[nodiscard]] static int deep_tostring(lua_State* L)
82{ 85{
83 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(g_MyDeepFactory.toDeep(L, 1)) }; 86 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
84 lua_pushfstring(L, "%p:deep(%d)", lua_topointer(L, 1), self->val); 87 lua_pushfstring(L, "%p:deep(%d)", lua_topointer(L, 1), self->val);
85 return 1; 88 return 1;
86} 89}
@@ -89,7 +92,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons
89 92
90[[nodiscard]] static int deep_gc(lua_State* L) 93[[nodiscard]] static int deep_gc(lua_State* L)
91{ 94{
92 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(g_MyDeepFactory.toDeep(L, 1)) }; 95 MyDeepUserdata* const self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
93 return 0; 96 return 0;
94} 97}
95 98
@@ -111,7 +114,7 @@ int luaD_new_deep( lua_State* L)
111{ 114{
112 int const nuv{ static_cast<int>(luaL_optinteger(L, 1, 0)) }; 115 int const nuv{ static_cast<int>(luaL_optinteger(L, 1, 0)) };
113 lua_settop(L, 0); 116 lua_settop(L, 0);
114 return g_MyDeepFactory.pushDeepUserdata(Dest{ L }, nuv); 117 return MyDeepFactory::Instance.pushDeepUserdata(DestState{ L }, nuv);
115} 118}
116 119
117// ################################################################################################# 120// #################################################################################################
diff --git a/lanes-4.0.0-0.rockspec b/lanes-4.0.0-0.rockspec
index 4e1b370..76982f1 100644
--- a/lanes-4.0.0-0.rockspec
+++ b/lanes-4.0.0-0.rockspec
@@ -66,6 +66,7 @@ build = {
66 "src/keeper.cpp", 66 "src/keeper.cpp",
67 "src/lanes.cpp", 67 "src/lanes.cpp",
68 "src/linda.cpp", 68 "src/linda.cpp",
69 "src/lindafactory.cpp",
69 "src/tools.cpp", 70 "src/tools.cpp",
70 "src/state.cpp", 71 "src/state.cpp",
71 "src/threading.cpp", 72 "src/threading.cpp",
diff --git a/src/Makefile b/src/Makefile
index d6bdfd7..06bbcd0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,7 @@
7 7
8MODULE=lanes 8MODULE=lanes
9 9
10SRC=lanes.c cancel.cpp compat.cpp threading.cpp tools.cpp state.cpp linda.cpp deep.cpp keeper.cpp universe.cpp 10SRC=lanes.c cancel.cpp compat.cpp threading.cpp tools.cpp state.cpp linda.cpp lindafactory.cpp deep.cpp keeper.cpp universe.cpp
11 11
12OBJ=$(SRC:.c=.o) 12OBJ=$(SRC:.c=.o)
13 13
diff --git a/src/deep.h b/src/deep.h
index 673e93a..45f7841 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -2,7 +2,7 @@
2 2
3/* 3/*
4 * public 'deep' API to be used by external modules if they want to implement Lanes-aware userdata 4 * public 'deep' API to be used by external modules if they want to implement Lanes-aware userdata
5 * said modules will have to link against lanes (it is not really possible to separate the 'deep userdata' implementation from the rest of Lanes) 5 * said modules can either link against lanes, or embed compat.cpp/h deep.cpp/h tools.cpp/h universe.cpp/h
6 */ 6 */
7 7
8#ifdef __cplusplus 8#ifdef __cplusplus
@@ -69,16 +69,16 @@ class DeepFactory
69 private: 69 private:
70 70
71 // NVI: private overrides 71 // NVI: private overrides
72 virtual DeepPrelude* newDeepObjectInternal(lua_State* L) const = 0; 72 virtual DeepPrelude* newDeepObjectInternal(lua_State* L_) const = 0;
73 virtual void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const = 0; 73 virtual void deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const = 0;
74 virtual void createMetatable(lua_State* L) const = 0; 74 virtual void createMetatable(lua_State* L_) const = 0;
75 virtual char const* moduleName() const = 0; 75 virtual char const* moduleName() const = 0;
76 76
77 public: 77 public:
78 78
79 // NVI: public interface 79 // NVI: public interface
80 int pushDeepUserdata(DestState L, int nuv_) const; 80 int pushDeepUserdata(DestState L_, int nuv_) const;
81 DeepPrelude* toDeep(lua_State* L, int index) const; 81 DeepPrelude* toDeep(lua_State* L_, int index_) const;
82 static void DeleteDeepObject(lua_State* L, DeepPrelude* o_); 82 static void DeleteDeepObject(lua_State* L_, DeepPrelude* o_);
83 static char const* PushDeepProxy(DestState L, DeepPrelude* prelude, int nuv_, LookupMode mode_); 83 static char const* PushDeepProxy(DestState L_, DeepPrelude* o_, int nuv_, LookupMode mode_);
84}; 84};
diff --git a/src/lanesconf.h b/src/lanesconf.h
index 8c66bd1..7b4ff93 100644
--- a/src/lanesconf.h
+++ b/src/lanesconf.h
@@ -19,10 +19,8 @@
19// file-level static variable: in 'global' namespace, prefix s, followed by an uppercase letter 19// file-level static variable: in 'global' namespace, prefix s, followed by an uppercase letter
20// file-level function (static or not): no prefix, start with an uppercase letter 20// file-level function (static or not): no prefix, start with an uppercase letter
21// class/struct/enum type: no prefix, start with an uppercase letter 21// class/struct/enum type: no prefix, start with an uppercase letter
22// static class member: prefix s, followed by an uppercase letter 22// static class member/method: no prefix, start with an uppercase letter
23// regular class member: no prefix, start with a lowercase letter 23// regular class member/method: no prefix, start with a lowercase letter
24// static class method: no prefix, start with an uppercase letter
25// regular class method: no prefix, start with a lowercase letter
26// function argument: suffix _ 24// function argument: suffix _
27// static function variable: prefix s, followed by an uppercase letter 25// static function variable: prefix s, followed by an uppercase letter
28// function local variable: prefix l, followed by an uppercase letter 26// function local variable: prefix l, followed by an uppercase letter
diff --git a/src/linda.cpp b/src/linda.cpp
index 590b487..bc931ac 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -7,7 +7,7 @@
7/* 7/*
8=============================================================================== 8===============================================================================
9 9
10Copyright (C) 2018 benoit Germain <bnt.germain@gmail.com> 10Copyright (C) 2018-2024 benoit Germain <bnt.germain@gmail.com>
11 11
12Permission is hereby granted, free of charge, to any person obtaining a copy 12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal 13of this software and associated documentation files (the "Software"), to deal
@@ -35,29 +35,13 @@ THE SOFTWARE.
35#include "compat.h" 35#include "compat.h"
36#include "keeper.h" 36#include "keeper.h"
37#include "lanes_private.h" 37#include "lanes_private.h"
38#include "lindafactory.h"
38#include "threading.h" 39#include "threading.h"
39#include "tools.h" 40#include "tools.h"
40#include "universe.h" 41#include "universe.h"
41 42
42#include <functional> 43#include <functional>
43 44
44// xxh64 of string "kLindaBatched" generated at https://www.pelock.com/products/hash-calculator
45static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" };
46
47// #################################################################################################
48
49class LindaFactory : public DeepFactory
50{
51 private:
52
53 DeepPrelude* newDeepObjectInternal(lua_State* L) const override;
54 void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override;
55 void createMetatable(lua_State* L) const override;
56 char const* moduleName() const override;
57};
58// I'm not totally happy with having a global variable. But since it's stateless, it will do for the time being.
59static LindaFactory g_LindaFactory;
60
61// ################################################################################################# 45// #################################################################################################
62// ################################################################################################# 46// #################################################################################################
63 47
@@ -67,7 +51,7 @@ static LindaFactory g_LindaFactory;
67static constexpr uintptr_t kPointerMagicShift{ 3 }; 51static constexpr uintptr_t kPointerMagicShift{ 3 };
68 52
69Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_) 53Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_)
70: DeepPrelude{ g_LindaFactory } 54: DeepPrelude{ LindaFactory::Instance }
71, U{ U_ } 55, U{ U_ }
72, m_keeper_index{ (group_ ? group_ : static_cast<int>(std::bit_cast<uintptr_t>(this) >> kPointerMagicShift)) % U_->keepers->nb_keepers } 56, m_keeper_index{ (group_ ? group_ : static_cast<int>(std::bit_cast<uintptr_t>(this) >> kPointerMagicShift)) % U_->keepers->nb_keepers }
73{ 57{
@@ -132,7 +116,7 @@ char const* Linda::getName() const
132template <bool OPT> 116template <bool OPT>
133[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_) 117[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_)
134{ 118{
135 Linda* const linda{ static_cast<Linda*>(g_LindaFactory.toDeep(L_, idx_)) }; 119 Linda* const linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) };
136 if constexpr (!OPT) 120 if constexpr (!OPT)
137 { 121 {
138 luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr 122 luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr
@@ -856,124 +840,26 @@ LUAG_FUNC(linda_towatch)
856 840
857// ################################################################################################# 841// #################################################################################################
858 842
859DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L) const 843namespace global {
860{ 844 static luaL_Reg const sLindaMT[] = {
861 size_t name_len = 0; 845 { "__concat", LG_linda_concat },
862 char const* linda_name = nullptr; 846 { "__tostring", LG_linda_tostring },
863 LindaGroup linda_group{ 0 }; 847 { "__towatch", LG_linda_towatch }, // Decoda __towatch support
864 // should have a string and/or a number of the stack as parameters (name and group) 848 { "cancel", LG_linda_cancel },
865 switch (lua_gettop(L)) 849 { "count", LG_linda_count },
866 { 850 { "deep", LG_linda_deep },
867 default: // 0 851 { "dump", LG_linda_dump },
868 break; 852 { "get", LG_linda_get },
869 853 { "limit", LG_linda_limit },
870 case 1: // 1 parameter, either a name or a group 854 { "receive", LG_linda_receive },
871 if (lua_type(L, -1) == LUA_TSTRING) 855 { "send", LG_linda_send },
872 { 856 { "set", LG_linda_set },
873 linda_name = lua_tolstring(L, -1, &name_len); 857 { nullptr, nullptr }
874 } 858 };
875 else 859} // namespace global
876 { 860// it's somewhat awkward to instanciate the LindaFactory here instead of lindafactory.cpp,
877 linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L, -1)) }; 861// but that's necessary to provide s_LindaMT without exposing it outside linda.cpp.
878 } 862/*static*/ LindaFactory LindaFactory::Instance{ global::sLindaMT };
879 break;
880
881 case 2: // 2 parameters, a name and group, in that order
882 linda_name = lua_tolstring(L, -2, &name_len);
883 linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L, -1)) };
884 break;
885 }
886
887 /* The deep data is allocated separately of Lua stack; we might no
888 * longer be around when last reference to it is being released.
889 * One can use any memory allocation scheme.
890 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
891 */
892 Universe* const U{ universe_get(L) };
893 Linda* linda{ new (U) Linda{ U, linda_group, linda_name, name_len } };
894 return linda;
895}
896
897// #################################################################################################
898
899void LindaFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const
900{
901 Linda* const linda{ static_cast<Linda*>(o_) };
902 LUA_ASSERT(L, linda);
903 Keeper* const myK{ linda->whichKeeper() };
904 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
905 if (myK)
906 {
907 // if collected from my own keeper, we can't acquire/release it
908 // because we are already inside a protected area, and trying to do so would deadlock!
909 bool const need_acquire_release{ myK->L != L };
910 // Clean associated structures in the keeper state.
911 Keeper* const K{ need_acquire_release ? linda->acquireKeeper() : myK };
912 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
913 [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0) };
914 LUA_ASSERT(L, result.has_value() && result.value() == 0);
915 if (need_acquire_release)
916 {
917 linda->releaseKeeper(K);
918 }
919 }
920
921 delete linda; // operator delete overload ensures things go as expected
922}
923
924// #################################################################################################
925
926static luaL_Reg const s_LindaMT[] =
927{
928 { "__concat", LG_linda_concat },
929 { "__tostring", LG_linda_tostring },
930 { "__towatch", LG_linda_towatch }, // Decoda __towatch support
931 { "cancel", LG_linda_cancel },
932 { "count", LG_linda_count },
933 { "deep", LG_linda_deep },
934 { "dump", LG_linda_dump },
935 { "get", LG_linda_get },
936 { "limit", LG_linda_limit },
937 { "receive", LG_linda_receive },
938 { "send", LG_linda_send },
939 { "set", LG_linda_set },
940 { nullptr, nullptr }
941};
942
943void LindaFactory::createMetatable(lua_State* L) const
944{
945 STACK_CHECK_START_REL(L, 0);
946 lua_newtable(L);
947 // metatable is its own index
948 lua_pushvalue(L, -1);
949 lua_setfield(L, -2, "__index");
950
951 // protect metatable from external access
952 lua_pushliteral(L, "Linda");
953 lua_setfield(L, -2, "__metatable");
954
955 // the linda functions
956 luaL_setfuncs(L, s_LindaMT, 0);
957
958 // some constants
959 kLindaBatched.pushKey(L);
960 lua_setfield(L, -2, "batched");
961
962 kNilSentinel.pushKey(L);
963 lua_setfield(L, -2, "null");
964
965 STACK_CHECK(L, 1);
966}
967
968// #################################################################################################
969
970char const* LindaFactory::moduleName() const
971{
972 // linda is a special case because we know lanes must be loaded from the main lua state
973 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
974 // in other words, forever.
975 return nullptr;
976}
977 863
978// ################################################################################################# 864// #################################################################################################
979 865
@@ -996,5 +882,5 @@ LUAG_FUNC(linda)
996 luaL_checktype(L, 1, LUA_TSTRING); 882 luaL_checktype(L, 1, LUA_TSTRING);
997 luaL_checktype(L, 2, LUA_TNUMBER); 883 luaL_checktype(L, 2, LUA_TNUMBER);
998 } 884 }
999 return g_LindaFactory.pushDeepUserdata(DestState{ L }, 0); 885 return LindaFactory::Instance.pushDeepUserdata(DestState{ L }, 0);
1000} 886}
diff --git a/src/linda.h b/src/linda.h
index f3b1844..21b6ecc 100644
--- a/src/linda.h
+++ b/src/linda.h
@@ -13,6 +13,11 @@ struct Keeper;
13 13
14// ################################################################################################# 14// #################################################################################################
15 15
16// xxh64 of string "kLindaBatched" generated at https://www.pelock.com/products/hash-calculator
17static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" };
18
19// #################################################################################################
20
16using LindaGroup = Unique<int>; 21using LindaGroup = Unique<int>;
17 22
18class Linda : public DeepPrelude // Deep userdata MUST start with this header 23class Linda : public DeepPrelude // Deep userdata MUST start with this header
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
10Copyright (C) 2024- benoit Germain <bnt.germain@gmail.com>
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in
20all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28THE SOFTWARE.
29
30===============================================================================
31*/
32
33#include "lindafactory.h"
34
35#include "linda.h"
36
37// #################################################################################################
38
39void 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
66void 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
93char 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
103DeepPrelude* 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}
diff --git a/src/lindafactory.h b/src/lindafactory.h
new file mode 100644
index 0000000..d31af1f
--- /dev/null
+++ b/src/lindafactory.h
@@ -0,0 +1,28 @@
1#pragma once
2
3#include "deep.h"
4
5// #################################################################################################
6
7class LindaFactory
8: public DeepFactory
9{
10 public:
11
12 // I'm not totally happy with having a 'global' variable. Maybe it should be dynamically created and stored somewhere in the universe?
13 static LindaFactory Instance;
14
15 LindaFactory(luaL_Reg const lindaMT_[])
16 : mLindaMT{ lindaMT_ }
17 {
18 }
19
20 private:
21
22 luaL_Reg const* const mLindaMT{ nullptr };
23
24 void createMetatable(lua_State* L_) const override;
25 void deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const override;
26 char const* moduleName() const override;
27 DeepPrelude* newDeepObjectInternal(lua_State* L_) const override;
28};