tables.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* Luwra
  2. * Minimal-overhead Lua wrapper for C++
  3. *
  4. * Copyright (C) 2016, Ole Krüger <ole@vprsm.de>
  5. */
  6. #ifndef LUWRA_TABLES_H_
  7. #define LUWRA_TABLES_H_
  8. #include "common.hpp"
  9. #include "types.hpp"
  10. #include "auxiliary.hpp"
  11. LUWRA_NS_BEGIN
  12. namespace internal {
  13. // This represents a "path" which will be resolved lazily. It is useful for chained table
  14. // access. An access like 'table.field1.field2' would be represented similiar to
  15. // `Path<Path<Table, std::string>, std::string> table {{table, "field1"}, "field"}`.
  16. template <typename P, typename K>
  17. struct Path {
  18. P parent;
  19. K key;
  20. // Read the value to which this path points to.
  21. template <typename V> inline
  22. V read(State* state) const {
  23. luwra::push(state, *this);
  24. V value = luwra::read<V>(state, -1);
  25. lua_pop(state, 1);
  26. return value;
  27. }
  28. // Change the value to which this path points to.
  29. template <typename V> inline
  30. void write(State* state, V&& value) const {
  31. size_t pushedParents = luwra::push(state, parent);
  32. if (pushedParents > 1)
  33. lua_pop(state, static_cast<int>(pushedParents - 1));
  34. size_t pushedKeys = luwra::push(state, key);
  35. if (pushedKeys > 1)
  36. lua_pop(state, static_cast<int>(pushedKeys - 1));
  37. size_t pushedValues = luwra::push(state, std::forward<V>(value));
  38. if (pushedValues > 1)
  39. lua_pop(state, static_cast<int>(pushedValues - 1));
  40. lua_rawset(state, -3);
  41. lua_pop(state, 1);
  42. }
  43. };
  44. }
  45. template <typename P, typename K>
  46. struct Value<internal::Path<P, K>> {
  47. // Push the value to which the path points onto the stack.
  48. static inline
  49. size_t push(State* state, const internal::Path<P, K>& accessor) {
  50. size_t pushedParents = luwra::push(state, accessor.parent);
  51. if (pushedParents > 1)
  52. lua_pop(state, static_cast<int>(pushedParents - 1));
  53. size_t pushedKeys = luwra::push(state, accessor.key);
  54. if (pushedKeys > 1)
  55. lua_pop(state, static_cast<int>(pushedKeys - 1));
  56. lua_rawget(state, -2);
  57. lua_remove(state, -2);
  58. return 1;
  59. }
  60. };
  61. namespace internal {
  62. template <typename A>
  63. struct TableAccessor {
  64. State* state;
  65. A accessor;
  66. TableAccessor(const TableAccessor&) = delete;
  67. TableAccessor(TableAccessor&&) = delete;
  68. TableAccessor& operator =(const TableAccessor&) = delete;
  69. TableAccessor& operator =(TableAccessor&&) = delete;
  70. template <typename V> inline
  71. V read() const && {
  72. return accessor.template read<V>(state);
  73. }
  74. template <typename V> inline
  75. operator V() const && {
  76. return accessor.template read<V>(state);
  77. }
  78. template <typename V> inline
  79. const TableAccessor&& write(V&& value) const && {
  80. accessor.write(state, std::forward<V>(value));
  81. return std::move(*this);
  82. }
  83. template <typename V> inline
  84. const TableAccessor&& operator =(V&& value) const && {
  85. accessor.write(state, std::forward<V>(value));
  86. return std::move(*this);
  87. }
  88. template <typename K> inline
  89. TableAccessor<Path<A, K>> access(K&& subkey) const && {
  90. return {state, {accessor, std::forward<K>(subkey)}};
  91. }
  92. template <typename K> inline
  93. TableAccessor<Path<A, K>> operator [](K&& subkey) const && {
  94. return {state, {accessor, std::forward<K>(subkey)}};
  95. }
  96. };
  97. }
  98. struct Table {
  99. Reference ref;
  100. Table(const Reference& ref):
  101. ref(ref)
  102. {}
  103. Table(State* state, int index):
  104. ref(state, index, true)
  105. {
  106. luaL_checktype(state, index, LUA_TTABLE);
  107. }
  108. Table(State* state):
  109. Table(state, (lua_newtable(state), -1))
  110. {}
  111. Table(State* state, const MemberMap& fields):
  112. Table(state, (luwra::push(state, fields), -1))
  113. {}
  114. template <typename K> inline
  115. internal::TableAccessor<internal::Path<const Reference&, K>> access(K&& key) const {
  116. return {ref.impl->state, {ref, std::forward<K>(key)}};
  117. }
  118. template <typename K> inline
  119. internal::TableAccessor<internal::Path<const Reference&, K>> operator [](K&& key) const {
  120. return {ref.impl->state, {ref, std::forward<K>(key)}};
  121. }
  122. inline
  123. void update(const MemberMap& fields) const {
  124. State* state = ref.impl->state;
  125. push(state, ref);
  126. setFields(state, -1, fields);
  127. lua_pop(state, 1);
  128. }
  129. template <typename K> inline
  130. bool has(K&& key) const {
  131. State* state = ref.impl->state;
  132. push(state, ref);
  133. size_t pushedKeys = push(state, std::forward<K>(key));
  134. if (pushedKeys > 1)
  135. lua_pop(state, static_cast<int>(pushedKeys - 1));
  136. lua_rawget(state, -2);
  137. bool isNil = lua_isnil(state, -1);
  138. lua_pop(state, 2);
  139. return !isNil;
  140. }
  141. template <typename V, typename K> inline
  142. void set(K&& key, V&& value) const {
  143. State* state = ref.impl->state;
  144. push(state, ref);
  145. size_t pushedKeys = push(state, std::forward<K>(key));
  146. if (pushedKeys > 1)
  147. lua_pop(state, static_cast<int>(pushedKeys - 1));
  148. size_t pushedValues = push(state, std::forward<V>(value));
  149. if (pushedValues > 1)
  150. lua_pop(state, static_cast<int>(pushedValues - 1));
  151. lua_rawset(state, -3);
  152. lua_pop(state, 1);
  153. }
  154. template <typename V, typename K> inline
  155. V get(K&& key) const {
  156. State* state = ref.impl->state;
  157. push(state, ref);
  158. size_t pushedKeys = push(state, std::forward<K>(key));
  159. if (pushedKeys > 1)
  160. lua_pop(state, static_cast<int>(pushedKeys - 1));
  161. lua_rawget(state, -2);
  162. V ret = read<V>(state, -1);
  163. lua_pop(state, 2);
  164. return ret;
  165. }
  166. };
  167. /**
  168. * See [Table](@ref Table).
  169. */
  170. template <>
  171. struct Value<Table> {
  172. static inline
  173. Table read(State* state, int index) {
  174. return {state, index};
  175. }
  176. static inline
  177. size_t push(State* state, const Table& value) {
  178. return value.ref.impl->push(state);
  179. }
  180. };
  181. /**
  182. * Retrieve the table containing all global values.
  183. * \param state Lua state
  184. * \returns Reference to the globals table.
  185. */
  186. static inline
  187. Table getGlobalsTable(State* state) {
  188. #if LUA_VERSION_NUM <= 501
  189. return {{state, internal::referenceValue(state, LUA_GLOBALSINDEX), false}};
  190. #else
  191. return {{state, LUA_RIDX_GLOBALS, false}};
  192. #endif
  193. }
  194. LUWRA_NS_END
  195. #endif