aboutsummaryrefslogtreecommitdiff
path: root/src/universe.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/universe.h86
1 files changed, 80 insertions, 6 deletions
diff --git a/src/universe.h b/src/universe.h
index a6beb68..3aac20d 100644
--- a/src/universe.h
+++ b/src/universe.h
@@ -27,17 +27,91 @@ struct Lane;
27// ################################################################################################ 27// ################################################################################################
28 28
29// everything we need to provide to lua_newstate() 29// everything we need to provide to lua_newstate()
30struct AllocatorDefinition 30class AllocatorDefinition
31{ 31{
32 lua_Alloc allocF{ nullptr }; 32 public:
33 void* allocUD{ nullptr }; 33
34 lua_Alloc m_allocF{ nullptr };
35 void* m_allocUD{ nullptr };
36
37 static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 0); }
38 // always embedded somewhere else or "in-place constructed" as a full userdata
39 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
40 static void operator delete(void* p_, lua_State* L) { ASSERT_L(!"should never be called") };
41
42 AllocatorDefinition(lua_Alloc allocF_, void* allocUD_) noexcept
43 : m_allocF{ allocF_ }
44 , m_allocUD{ allocUD_ }
45 {
46 }
47 AllocatorDefinition() = default;
48 AllocatorDefinition(AllocatorDefinition const& rhs_) = default;
49 AllocatorDefinition(AllocatorDefinition&& rhs_) = default;
50 AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default;
51 AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default;
52
53 void initFrom(lua_State* L)
54 {
55 m_allocF = lua_getallocf(L, &m_allocUD);
56 }
57
58 void* lua_alloc(void* ptr_, size_t osize_, size_t nsize_)
59 {
60 m_allocF(m_allocUD, ptr_, osize_, nsize_);
61 }
62
63 void* alloc(size_t nsize_)
64 {
65 return m_allocF(m_allocUD, nullptr, 0, nsize_);
66 }
67
68 void free(void* ptr_, size_t osize_)
69 {
70 std::ignore = m_allocF(m_allocUD, ptr_, osize_, 0);
71 }
34}; 72};
35 73
74// ################################################################################################
75
36// mutex-protected allocator for use with Lua states that share a non-threadsafe allocator 76// mutex-protected allocator for use with Lua states that share a non-threadsafe allocator
37struct ProtectedAllocator 77class ProtectedAllocator : public AllocatorDefinition
38{ 78{
39 AllocatorDefinition definition; 79 private:
40 std::mutex lock; 80
81 std::mutex m_lock;
82
83 static void* protected_lua_Alloc(void* ud_, void* ptr_, size_t osize_, size_t nsize_)
84 {
85 ProtectedAllocator* const s{ static_cast<ProtectedAllocator*>(ud_) };
86 std::lock_guard<std::mutex> guard{ s->m_lock };
87 return s->m_allocF(s->m_allocUD, ptr_, osize_, nsize_);
88 }
89
90 public:
91
92 // we are not like our base class: we can't be created inside a full userdata (or we would have to install a metatable and __gc handler to destroy ourselves properly)
93 static void* operator new(size_t size_, lua_State* L) noexcept = delete;
94 static void operator delete(void* p_, lua_State* L) = delete;
95
96 AllocatorDefinition makeDefinition()
97 {
98 return AllocatorDefinition{ protected_lua_Alloc, this};
99 }
100
101 void installIn(lua_State* L)
102 {
103 lua_setallocf(L, protected_lua_Alloc, this);
104 }
105
106 void removeFrom(lua_State* L)
107 {
108 // remove the protected allocator, if any
109 if (m_allocF != nullptr)
110 {
111 // install the non-protected allocator
112 lua_setallocf(L, m_allocF, m_allocUD);
113 }
114 }
41}; 115};
42 116
43// ################################################################################################ 117// ################################################################################################