nngn
Loading...
Searching...
No Matches
user.h
Go to the documentation of this file.
1
8#ifndef NNGN_LUA_USER_DATA_H
9#define NNGN_LUA_USER_DATA_H
10
11#include <string_view>
12
13#include "os/platform.h"
14#include "utils/alloc/block.h"
16#include "utils/def.h"
17#include "utils/fixed_string.h"
18#include "utils/log.h"
19#include "utils/utils.h"
20
21#include "lua.h"
22#include "state.h"
23#include "value.h"
24
25namespace nngn::lua {
26
27namespace detail {
28
34protected:
36 static table push_metatable(state_view lua, std::string_view meta);
37 static bool check_type(
38 state_view lua, int i, std::string_view meta);
39 static bool check_pointer_type(
40 state_view lua, int i, std::string_view meta);
41};
42
47template<typename T>
48using stored_type = std::conditional_t<std::is_abstract_v<T>, empty, T>;
49
50}
51
52template<typename T>
53inline constexpr auto user_data_header_align =
54 std::max(alignof(T), alignof(T*));
55
57template<typename T>
58struct alignas(user_data_header_align<T>) user_data_header {
60 T *p = nullptr;
61};
62
69template<typename T>
70class user_data :
72 alloc_block<user_data_header<T>, detail::stored_type<T>>::storage
73{
76 static constexpr auto meta =
78 std::remove_const_t<std::remove_pointer_t<T>>>;
79 friend class user_data<T*>;
80public:
81 using get_type = std::remove_pointer_t<T>*;
83 static get_type get(state_view lua, int i);
91 static get_type from_light(const void *p);
93 static bool check_type(state_view lua, int i);
103 static int gc(lua_State *L);
110 static int eq(lua_State *L);
118 template<typename R> static int push(state_view lua, R &&r);
120 explicit user_data(const T &x);
122 explicit user_data(T &&x);
124 get_type get(void) const { return this->header.p; }
131 void destroy(void);
132private:
133 static get_type get_pointer(state_view lua, int i);
134};
135
136template<typename T>
137requires(std::same_as<void, std::decay_t<T>>)
139 static void *from_light(const void *p);
140};
141
142template<typename T>
143auto user_data<T>::get_pointer(state_view lua, int i) -> get_type {
144 if constexpr(std::is_pointer_v<T>)
145 return user_data<std::remove_pointer_t<T>>::get_pointer(lua, i);
146 else {
147 auto *const p = Math::align_ptr<user_data>(lua.get<void*>(i));
148 return p ? p->header.p : nullptr;
149 }
150}
151
152template<typename T>
153auto user_data<T>::get(state_view lua, int i) -> get_type {
155 return user_data::get_pointer(lua, i);
156}
157
158template<typename T>
159auto user_data<T>::from_light(const void *p) -> get_type {
160 return p ? static_cast<const user_data*>(p)->get() : nullptr;
161}
162
163template<typename T>
164bool user_data<T>::check_type(state_view lua, int i) {
165 if constexpr(std::is_pointer_v<T>)
166 return user_data_base::check_pointer_type(lua, i, user_data::meta);
167 else
168 return user_data_base::check_type(lua, i, user_data::meta);
169}
170
171template<typename T>
172template<typename R>
173int user_data<T>::push(state_view lua, R &&r) {
174 NNGN_LOG_CONTEXT_CF(user_data);
175 constexpr auto is_pointer = pointer<std::decay_t<R>>;
176 if constexpr(is_pointer)
177 if(!r)
178 return stack_push<>::push(lua, nil);
179 using UT = std::conditional_t<
180 is_pointer, user_data::header_type, user_data>;
181 new (lua.new_user_data<UT>()) UT{FWD(r)};
182 static_assert(
183 !std::same_as<decltype(meta), const empty>,
184 "meta table_name not defined for type");
185 auto mt = user_data_base::push_metatable(lua, meta);
186 lua_setmetatable(lua, -2);
187 mt.release();
188 return 1;
189}
190
191template<typename T>
192int user_data<T>::gc(lua_State *L) {
193 const state_view lua = {L};
195 Math::align_ptr<user_data>(lua.get<void*>(1))->destroy();
196 return 0;
197}
198
199template<typename T>
200int user_data<T>::eq(lua_State *L) {
201 const auto [p0, p1] = state_view{L}.get<std::tuple<T*, T*>>(1);
202 return stack_push<>::push(L, p0 == p1);
203}
204
205template<typename T>
206user_data<T>::user_data(const T &x)
207 : base_type{.header = {.p = &x}, .data = x} {}
208
209template<typename T>
210user_data<T>::user_data(T &&x)
211 : base_type{.header = {.p = &this->data}, .data = FWD(x)} {}
212
213template<typename T>
214void user_data<T>::destroy(void) {
215 auto *const p = this->header.p;
216 auto *const d = &this->data;
217 if constexpr(std::same_as<empty, detail::stored_type<T>>)
218 assert(static_cast<void*>(p) != static_cast<void*>(d));
219 else if(p == d) // XXX technically undefined behavior when false
220 std::destroy_at(d);
221}
222
223}
224
225#endif
Non-owning handle to an aggregate header and data block.
Definition: block.h:31
Definition: state.h:88
Data block allocated for user data objects.
Definition: user.h:73
static table push_metatable(state_view lua)
Pushes the type's meta table onto the stack.
user_data(const T &x)
Creates a non-owning (reference) object.
static get_type from_light(const void *p)
Retrieves a user data of type T from a light user data value.
void destroy(void)
Destroys the T value if this is an owning user data value.
get_type get(void) const
Pointer to the contained/referenced object.
Definition: user.h:124
static get_type get_pointer(state_view lua, int i)
static int gc(lua_State *L)
Function to be used as a user data's __gc meta-method.
static constexpr auto meta
Definition: user.h:76
user_data(T &&x)
Creates an owning (copy) object.
static int eq(lua_State *L)
Function to be used as a user data's __eq meta-method.
static int push(state_view lua, R &&r)
Pushes a value on the stack as a user data of type T.
static get_type get(state_view lua, int i)
Retrieves a user data of type T from the stack.
typename alloc_block< header_type, T >::storage base_type
Definition: user.h:75
static bool check_type(state_view lua, int i)
Verifies that the value on the stack is a user data of type T.
std::remove_pointer_t< T > * get_type
Definition: user.h:81
user_data_header< T > header_type
Definition: user.h:74
Definition: fundamental.h:41
assert
Definition: debug.lua:3
#define NNGN_LOG_CONTEXT_CF(c)
Definition: log.h:11
std::conditional_t< std::is_abstract_v< T >, empty, T > stored_type
Prevents forming a type with an abstract type as a member.
Definition: user.h:48
Definition: alloc.cpp:100
constexpr auto user_data_header_align
Definition: user.h:53
constexpr struct nngn::lua::nil_type nil
constexpr empty metatable_name
Key in the global table where the meta-table for T is stored.
Definition: lua.h:155
empty
Definition: utils.h:89
get
Definition: camera.lua:36
lua_State wrappers.
mt
Definition: strict.lua:4
Underlying storage type.
Definition: block.h:37
header_type header
Definition: block.h:41
value_type data
Definition: block.h:42
Base operations which do not depend on the template type.
Definition: user.h:33
static bool check_pointer_type(state_view lua, int i, std::string_view meta)
Definition: user.cpp:71
static bool check_type(state_view lua, int i, std::string_view meta)
Definition: user.cpp:64
static table push_metatable(state_view lua, std::string_view meta)
Pushes the table stored as meta in the global table.
Definition: user.cpp:59
Owning reference to a table on the stack, popped when destroyed.
Definition: table.h:172
Header placed before a user data allocation.
Definition: user.h:58
T * p
Pointer to the user data object.
Definition: user.h:60
#define FWD(...)
Definition: utils.h:18
Operations on generic stack values.