tables.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. template <typename K> inline
  109. internal::TableAccessor<internal::Path<const Reference&, K>> access(K&& key) const {
  110. return {ref.impl->state, {ref, std::forward<K>(key)}};
  111. }
  112. template <typename K> inline
  113. internal::TableAccessor<internal::Path<const Reference&, K>> operator [](K&& key) const {
  114. return {ref.impl->state, {ref, std::forward<K>(key)}};
  115. }
  116. inline
  117. void update(const FieldVector& fields) const {
  118. State* state = ref.impl->state;
  119. push(state, ref);
  120. setFields(state, -1, fields);
  121. lua_pop(state, 1);
  122. }
  123. template <typename K> inline
  124. bool has(K&& key) const {
  125. State* state = ref.impl->state;
  126. push(state, ref);
  127. size_t pushedKeys = push(state, std::forward<K>(key));
  128. if (pushedKeys > 1)
  129. lua_pop(state, static_cast<int>(pushedKeys - 1));
  130. lua_rawget(state, -2);
  131. bool isNil = lua_isnil(state, -1);
  132. lua_pop(state, 2);
  133. return !isNil;
  134. }
  135. template <typename V, typename K> inline
  136. void set(K&& key, V&& value) const {
  137. State* state = ref.impl->state;
  138. push(state, ref);
  139. size_t pushedKeys = push(state, std::forward<K>(key));
  140. if (pushedKeys > 1)
  141. lua_pop(state, static_cast<int>(pushedKeys - 1));
  142. size_t pushedValues = push(state, std::forward<V>(value));
  143. if (pushedValues > 1)
  144. lua_pop(state, static_cast<int>(pushedValues - 1));
  145. lua_rawset(state, -3);
  146. lua_pop(state, 1);
  147. }
  148. template <typename V, typename K> inline
  149. V get(K&& key) const {
  150. State* state = ref.impl->state;
  151. push(state, ref);
  152. size_t pushedKeys = push(state, std::forward<K>(key));
  153. if (pushedKeys > 1)
  154. lua_pop(state, static_cast<int>(pushedKeys - 1));
  155. lua_rawget(state, -2);
  156. V ret = read<V>(state, -1);
  157. lua_pop(state, 2);
  158. return ret;
  159. }
  160. };
  161. /**
  162. * See [Table](@ref Table).
  163. */
  164. template <>
  165. struct Value<Table> {
  166. static inline
  167. Table read(State* state, int index) {
  168. return {state, index};
  169. }
  170. static inline
  171. size_t push(State* state, const Table& value) {
  172. return value.ref.impl->push(state);
  173. }
  174. };
  175. /**
  176. * Retrieve the table containing all global values.
  177. * \param state Lua state
  178. * \returns Reference to the globals table.
  179. */
  180. static inline
  181. Table getGlobalsTable(State* state) {
  182. #if LUA_VERSION_NUM <= 501
  183. return {{state, internal::referenceValue(state, LUA_GLOBALSINDEX), false}};
  184. #else
  185. return {{state, LUA_RIDX_GLOBALS, false}};
  186. #endif
  187. }
  188. LUWRA_NS_END
  189. #endif