nngn
Loading...
Searching...
No Matches
table.h
Go to the documentation of this file.
1
96#ifndef NNGN_LUA_TABLE_H
97#define NNGN_LUA_TABLE_H
98
99#include <functional>
100#include <optional>
101
102#include "utils/concepts.h"
103#include "utils/tuple.h"
104
105#include "get.h"
106#include "push.h"
107#include "state.h"
108#include "value.h"
109
110namespace nngn::lua {
111
112template<typename T, typename ...Ks> class table_proxy;
113
114namespace detail {
115
117template<typename CRTP>
119public:
120 template<typename K>
123 lua_Integer size(void) const;
125 table_iter<const CRTP> begin(void) const;
127 table_iter<const CRTP> end(void) const;
133 template<typename T> T raw_get(auto &&k, T &&def = T{}) const;
135 template<typename T> T get_field(auto &&k, T &&def = T{}) const;
137 void raw_set(auto &&k, auto &&v) const;
139 void set(auto &&k, auto &&v) const;
144 template<typename ...Ts> void set(std::tuple<Ts...> &&t) const;
145protected:
146 template<op_mode mode, typename T>
147 T get_common(auto &&k, T &&def = T{}) const;
148 template<op_mode mode>
149 void set_common(auto &&k, auto &&v) const;
150private:
151 const CRTP &crtp(void) const { return static_cast<const CRTP&>(*this); }
152 int begin_op(void) const { return this->crtp().index(); }
153 void end_op(int) const {}
154};
155
159 int begin_op(void) const { return this->state().top(); }
160 void end_op(int i) const { lua_remove(this->state(), i); }
161};
162
163}
164
169};
170
174 using value::value;
175 ~table(void) = default;
178};
179
181class global_table : public detail::table_base<global_table> {
182public:
184 explicit global_table(state_view lua) : m_state{lua} {}
185 ~global_table(void) = default;
186 state_view state(void) const { return this->m_state; }
187 int push(void) const { lua_pushglobaltable(this->state()); return 1; }
188private:
190 int begin_op(void) const { this->push(); return this->state().top(); }
191 void end_op(int i) const { lua_remove(this->state(), i); }
193};
194
196template<typename T, typename ...Ks>
198public:
199 // Constructors
200 table_proxy(const T &t, auto &&k) : m_table{t}, m_keys(FWD(k)) {}
201 // Operators
202 template<typename V>
203 table_proxy &operator=(V &&v) { this->set(FWD(v)); return *this; }
204 template<typename V>
205 operator V(void) const { return this->get<V>(); }
206 template<typename K>
207 table_proxy<T, Ks..., std::decay_t<K>> operator[](K &&k) const;
208 // Accessors
209 const T &table(void) const { return this->m_table; }
210 const std::tuple<Ks...> &keys(void) const { return this->m_keys; }
211 state_view state(void) const { return this->table().state(); }
212 // Operations
213 template<typename V> V get(V &&def = V{}) const;
214 void set(auto &&v) const;
215 int push(void) const { value{*this}.release(); return 1; }
216private:
217 auto key(void) const { return std::get<0>(this->keys()); }
218 auto push_sub(void) const;
219 auto make_sub(const auto &t) const;
220 const T &m_table;
221 std::tuple<Ks...> m_keys;
222};
223
224namespace detail {
225
226template<typename CRTP>
227template<typename K>
229 return {static_cast<const CRTP&>(*this), FWD(k)};
230}
231
232template<typename CRTP>
233lua_Integer table_base<CRTP>::size(void) const {
234 return this->crtp().state().len(this->crtp().index());
235}
236
237template<typename CRTP>
238template<typename T>
239T table_base<CRTP>::raw_get(auto &&k, T &&def) const {
240 return this->get_common<op_mode::raw>(FWD(k), FWD(def));
241}
242
243template<typename CRTP>
244template<typename T>
245T table_base<CRTP>::get_field(auto &&k, T &&def) const {
246 return this->get_common<op_mode::normal>(FWD(k), FWD(def));
247}
248
249template<typename CRTP>
250void table_base<CRTP>::raw_set(auto &&k, auto &&v) const {
251 return this->set_common<op_mode::raw>(FWD(k), FWD(v));
252}
253
254template<typename CRTP>
255void table_base<CRTP>::set(auto &&k, auto &&v) const {
256 return this->set_common<op_mode::normal>(FWD(k), FWD(v));
257}
258
259template<typename CRTP>
260template<typename ...Ts>
261void table_base<CRTP>::set(std::tuple<Ts...> &&t) const {
262 constexpr auto n = sizeof...(Ts);
263 static_assert(!(n % 2));
264 [this, &t]<std::size_t ...I>(std::index_sequence<I...>) {
265 (..., static_cast<const CRTP*>(this)->set(
266 std::get<2 * I>(FWD(t)),
267 std::get<2 * I + 1>(FWD(t))));
268 }(std::make_index_sequence<n / 2>{});
269}
270
271template<typename CRTP>
272template<op_mode mode, typename T>
273T table_base<CRTP>::get_common(auto &&k, T &&def) const {
274 const auto &crtp = static_cast<const CRTP&>(*this);
275 const auto lua = crtp.state();
276 const int i = crtp.begin_op();
277 lua.push(FWD(k));
278 constexpr auto get = mode == op_mode::raw ? lua_rawget : lua_gettable;
279 const auto type = type_from_lua(get(lua, i));
280 crtp.end_op(i);
282 if(type != type::nil)
283 return lua.template get<T>(lua.top());
284 if constexpr(is_optional<T>)
285 return {};
286 return FWD(def);
287}
288
289template<typename CRTP>
290template<op_mode mode>
291void table_base<CRTP>::set_common(auto &&k, auto &&v) const {
292 const auto &crtp = static_cast<const CRTP&>(*this);
293 const auto lua = crtp.state();
294 const int i = crtp.begin_op();
295 lua.push(FWD(k));
296 lua.push(FWD(v));
297 if constexpr(mode == op_mode::raw)
298 lua_rawset(lua, i);
299 else
300 lua_settable(lua, i);
301 crtp.end_op(i);
302}
303
304}
305
306template<typename T, typename ...Ks>
307template<typename K>
309 -> table_proxy<T, Ks..., std::decay_t<K>>
310{
311 return {this->m_table, std::tuple_cat(this->m_keys, std::tuple{FWD(k)})};
312}
313
314template<typename T, typename ...Ks>
316 return this->table()
317 .template get_field<detail::table_accessor>(this->key());
318}
319
320template<typename T, typename ...Ks>
321template<typename T1>
322auto table_proxy<T, Ks...>::make_sub(const T1 &t) const {
323 return [&t]<typename ...Ks1>(std::tuple<Ks1...> &&k) {
324 return table_proxy<T1, Ks1...>{t, FWD(k)};
325 }(tuple_tail(this->keys()));
326}
327
328template<typename T, typename ...Ks>
329template<typename V>
331 if constexpr(sizeof...(Ks) == 1)
332 return this->table().template get_field<V>(this->key(), FWD(def));
333 else
334 return this->make_sub(this->push_sub()).template get<V>(FWD(def));
335}
336
337template<typename T, typename ...Ks>
338void table_proxy<T, Ks...>::set(auto &&v) const {
339 if constexpr(sizeof...(Ks) == 1)
340 return this->table().template set(this->key(), FWD(v));
341 else
342 return this->make_sub(this->push_sub()).template set(FWD(v));
343}
344
345template<typename T, typename PT, typename ...Ks>
346decltype(auto) operator==(T &&lhs, const table_proxy<PT, Ks...> &rhs) {
347 return FWD(lhs) == rhs.template get<std::decay_t<T>>();
348}
349
350template<typename T, typename PT, typename ...Ks>
351decltype(auto) operator==(const table_proxy<PT, Ks...> &lhs, T &&rhs) {
352 return lhs.template get<std::decay_t<T>>() == FWD(rhs);
353}
354
355template<typename T>
357 constexpr std::string_view meta = metatable_name<T>;
358 table t = this->create_table();
359 global_table{*this}.set(meta, t);
360 t["__name"] = meta;
361 t["__index"] = t;
362 t["__gc"] = &user_data<T>::gc;
363 t["__eq"] = &user_data<T>::eq;
364 return t;
365}
366
368 return global_table{*this};
369}
370
371inline table state_view::create_table(void) const {
372 return this->create_table(0, 0);
373}
374
375inline table state_view::create_table(int narr, int nrec) const {
376 lua_createtable(*this, narr, nrec);
377 return {this->L, lua_gettop(*this)};
378}
379
381table table_array(state_view lua, auto &&...args) {
382 using LI = lua_Integer;
383 static_assert(sizeof...(args) <= std::numeric_limits<LI>::max());
384 constexpr auto n = static_cast<LI>(sizeof...(args));
385 auto ret = lua.create_table(n, 0);
386 [&ret]<LI ...I>(std::integer_sequence<LI, I...>, auto &&...args_) {
387 (..., ret.raw_set(I + 1, args_));
388 }(std::make_integer_sequence<LI, n>{}, FWD(args)...);
389 return ret;
390}
391
393template<std::ranges::range T>
395 int n = 0;
396 if constexpr(std::ranges::sized_range<T>)
397 n = static_cast<int>(std::ranges::size(FWD(r)));
398 auto ret = lua.create_table(n, 0);
399 // TODO enumerate
400 lua_Integer i = 1;
401 for(auto &&x : FWD(r))
402 ret.raw_set(i++, FWD(x));
403 return ret;
404}
405
410table table_map(state_view lua, auto &&...args) {
411 constexpr auto n = sizeof...(args);
412 auto ret = lua.create_table(0, n / 2);
413 [&ret]<std::size_t ...I>(std::index_sequence<I...>, auto &&t) {
414 (..., ret.raw_set(
415 FWD(std::get<2 * I>(t)),
416 FWD(std::get<2 * I + 1>(t)))
417 );
418 }(std::make_index_sequence<n / 2>{}, std::forward_as_tuple(FWD(args)...));
419 return ret;
420}
421
423template<typename T>
424requires(detail::can_get<T>)
425struct stack_get<std::vector<T>> {
426 static std::vector<T> get(lua_State *L, int i) {
427 table_view t = {L, i};
428 const auto n = t.size();
429 std::vector<T> ret = {};
430 ret.reserve(static_cast<std::size_t>(n));
431 for(lua_Integer ti = 1; ti <= n; ++ti)
432 ret.push_back(t[ti]);
433 return ret;
434 }
435};
436
437template<typename T, typename ...Ks>
438struct stack_push<table_proxy<T, Ks...>> {
439 static int push(
440 [[maybe_unused]] lua_State *L, const table_proxy<T, Ks...> &t)
441 {
442 assert(t.state() == L);
443 return t.push();
444 }
445};
446
447template<typename T>
448requires(
449 std::derived_from<T, detail::table_base_tag>
450 && !std::derived_from<T, value>
451 && !std::same_as<T, global_table>)
452inline constexpr bool is_stack_ref<T> = true;
453
454static_assert(detail::stack_type<table_view>);
455static_assert(detail::stack_type<table>);
456static_assert(stack_ref<table_view>);
457static_assert(stack_ref<table>);
458static_assert(!stack_ref<global_table>);
459
460}
461
462#endif
Pops n values from the Lua stack at scope exit.
Definition: utils.h:24
CRTP base for stack table types.
Definition: table.h:118
T raw_get(auto &&k, T &&def=T{}) const
Gets field without meta methods.
Definition: table.h:239
T get_field(auto &&k, T &&def=T{}) const
Gets field, with optional default value.
Definition: table.h:245
table_seq_iter< const CRTP > iend(void) const
Sentinel for ibegin.
Definition: iter.h:196
void raw_set(auto &&k, auto &&v) const
Sets a table field without meta methods.
Definition: table.h:250
table_iter< const CRTP > begin(void) const
lua_next-based iteration.
Definition: iter.h:181
table_seq_iter< const CRTP > ibegin(void) const
ipairs-style iteration.
Definition: iter.h:186
int begin_op(void) const
Definition: table.h:152
lua_Integer size(void) const
Definition: table.h:233
void set(std::tuple< Ts... > &&t) const
Sets multiple table fields.
Definition: table.h:261
const CRTP & crtp(void) const
Definition: table.h:151
void set_common(auto &&k, auto &&v) const
Definition: table.h:291
T get_common(auto &&k, T &&def=T{}) const
Definition: table.h:273
void end_op(int) const
Definition: table.h:153
table_proxy< CRTP, std::decay_t< K > > operator[](K &&k) const
Definition: table.h:228
void set(auto &&k, auto &&v) const
Sets a table field.
Definition: table.h:255
table_iter< const CRTP > end(void) const
Sentinel for begin.
Definition: iter.h:191
lua_next-based table iterator.
Definition: iter.h:77
ipairs-style table iterator.
Definition: iter.h:94
Table interface to the global environment.
Definition: table.h:181
~global_table(void)=default
int begin_op(void) const
Definition: table.h:190
void end_op(int i) const
Definition: table.h:191
int push(void) const
Definition: table.h:187
state_view state(void) const
Definition: table.h:186
state_view m_state
Definition: table.h:192
Definition: state.h:88
lua_State * L
Definition: state.h:162
table new_user_type(void) const
Registers a new user type and returns its meta table.
Definition: table.h:356
global_table globals(void) const
Definition: table.h:367
int top(void) const
Definition: state.h:109
table create_table(void) const
Creates a table and pushes it on the stack.
Definition: table.h:371
Expression template for table assignemnts.
Definition: table.h:197
table_proxy< T, Ks..., std::decay_t< K > > operator[](K &&k) const
auto make_sub(const auto &t) const
Definition: table.h:322
void set(auto &&v) const
Definition: table.h:338
const T & table(void) const
Definition: table.h:209
std::tuple< Ks... > m_keys
Definition: table.h:221
auto push_sub(void) const
Definition: table.h:315
table_proxy & operator=(V &&v)
Definition: table.h:203
const T & m_table
Definition: table.h:220
auto key(void) const
Definition: table.h:217
state_view state(void) const
Definition: table.h:211
V get(V &&def=V{}) const
Definition: table.h:330
table_proxy(const T &t, auto &&k)
Definition: table.h:200
int push(void) const
Definition: table.h:215
const std::tuple< Ks... > & keys(void) const
Definition: table.h:210
Data block allocated for user data objects.
Definition: user.h:73
Base, non-owning generic stack value reference.
Definition: value.h:18
value_view(lua_State *L, int i)
Definition: value.h:21
state_view state(void) const
Definition: value.h:24
A built-in type from this library with stack manipulation operations.
Definition: lua.h:198
Definition: lua.h:228
assert
Definition: debug.lua:3
Functions for retrieving values from the stack.
user_type T
Definition: register_test.cpp:22
@ raw
Definition: lua.h:172
Definition: alloc.cpp:100
constexpr type type_from_lua(int t)
Maps LUA_T* values to type.
Definition: lua.h:108
table table_from_range(state_view lua, T &&r)
Creates a table array from a range.
Definition: table.h:394
constexpr bool is_stack_ref< T >
Definition: table.h:452
type
LUA_T* constants as a scoped enumeration.
Definition: lua.h:77
table table_map(state_view lua, auto &&...args)
Creates a table with each successive argument pair as key/value.
Definition: table.h:410
table table_array(state_view lua, auto &&...args)
Creates a table array with each argument in succession.
Definition: table.h:381
auto tuple_tail(T &&t)
Definition: tuple.h:11
Functions for pushing values onto the stack.
set
Definition: camera.lua:37
get
Definition: camera.lua:36
v[1]
Definition: math.lua:19
lua_State wrappers.
Internal type used in nested table accesses.
Definition: table.h:157
void end_op(int i) const
Definition: table.h:160
int begin_op(void) const
Definition: table.h:159
Tag to relate all table_base instantiations via inheritance.
Definition: lua.h:175
Tag to relate all table_proxy instantiations via inheritance.
Definition: lua.h:178
static std::vector< T > get(lua_State *L, int i)
Definition: table.h:426
Reads a value from the Lua stack.
Definition: lua.h:117
static int push(lua_State *L, const table_proxy< T, Ks... > &t)
Definition: table.h:439
Pushes a value onto the Lua stack.
Definition: lua.h:119
Non-owning reference to a table on the stack.
Definition: table.h:166
table_view(value_view v)
Definition: table.h:168
Owning reference to a table on the stack, popped when destroyed.
Definition: table.h:172
~table(void)=default
table_view release(void)
Disowns the current reference and returns a non-owning view to it.
Definition: table.h:177
Owning stack value reference.
Definition: value.h:48
value_view release(void)
Definition: value.h:56
value(value_view v)
Definition: value.h:51
#define NNGN_DEFAULT_CONSTRUCT(x)
Definition: utils.h:20
#define FWD(...)
Definition: utils.h:18
#define NNGN_MOVE_ONLY(x)
Definition: utils.h:39
#define NNGN_ANON_DECL(...)
Definition: utils.h:53
Operations on generic stack values.