dungeon/libs/kaguya-1.3.2/include/kaguya/detail/lua_table_def.hpp
Adrian Hedqvist ec131d8bda Too much stuff
* Implemented lua using kaguya, only for config files for now
* Moved color struct to its own header
* statically link glew instead of including the source in the project
* Other stuff that I don't remember
2017-10-18 12:25:25 +02:00

467 lines
14 KiB
C++

// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <algorithm>
#include "kaguya/config.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
namespace kaguya {
class LuaRef;
class LuaStackRef;
class LuaTable;
template <typename KEY> class TableKeyReferenceProxy;
class MemberFunctionBinder;
namespace detail {
struct table_proxy {
#if KAGUYA_USE_CPP11
template <typename V, typename KEY>
static void set(lua_State *state, int table_index, KEY &&key, V &&value) {
util::one_push(state, std::forward<KEY>(key));
util::one_push(state, std::forward<V>(value));
lua_settable(state, table_index);
}
template <typename V>
static void set(lua_State *state, int table_index, const char *key,
V &&value) {
util::one_push(state, std::forward<V>(value));
lua_setfield(state, table_index, key);
}
template <typename V>
static void set(lua_State *state, int table_index, const std::string &key,
V &&value) {
set(state, table_index, key.c_str(), std::forward<V>(value));
}
template <typename V>
static void set(lua_State *state, int table_index, luaInt key, V &&value) {
util::one_push(state, std::forward<V>(value));
lua_seti(state, table_index, key);
}
template <typename V, typename KEY>
static void rawset(lua_State *state, int table_index, KEY &&key, V &&value) {
util::one_push(state, std::forward<KEY>(key));
util::one_push(state, std::forward<V>(value));
lua_rawset(state, table_index);
}
template <typename V>
static void rawset(lua_State *state, int table_index, luaInt key, V &&value) {
util::one_push(state, std::forward<V>(value));
lua_rawseti(state, table_index, key);
}
#else
template <typename V, typename KEY>
static void set(lua_State *state, int table_index, const KEY &key,
const V &value) {
util::one_push(state, key);
util::one_push(state, value);
lua_settable(state, table_index);
}
template <typename V>
static void set(lua_State *state, int table_index, const char *key,
const V &value) {
util::one_push(state, value);
lua_setfield(state, table_index, key);
}
template <typename V>
static void set(lua_State *state, int table_index, const std::string &key,
const V &value) {
util::one_push(state, value);
lua_setfield(state, table_index, key.c_str());
}
template <typename V>
static void set(lua_State *state, int table_index, luaInt key,
const V &value) {
util::one_push(state, value);
lua_seti(state, table_index, key);
}
template <typename V, typename KEY>
static void rawset(lua_State *state, int table_index, const KEY &key,
const V &value) {
util::one_push(state, key);
util::one_push(state, value);
lua_rawset(state, table_index);
}
template <typename V>
static void rawset(lua_State *state, int table_index, luaInt key,
const V &value) {
util::one_push(state, value);
lua_rawseti(state, table_index, key);
}
#endif
#if KAGUYA_USE_CPP11
template <typename KEY>
static void get(lua_State *state, int table_index, KEY &&key) {
util::one_push(state, std::forward<KEY>(key));
lua_gettable(state, table_index);
}
#endif
template <typename KEY>
static void get(lua_State *state, int table_index, const KEY &key) {
util::one_push(state, key);
lua_gettable(state, table_index);
}
static void get(lua_State *state, int table_index, const char *key) {
lua_getfield(state, table_index, key);
}
static void get(lua_State *state, int table_index, const std::string &key) {
lua_getfield(state, table_index, key.c_str());
}
static void get(lua_State *state, int table_index, luaInt key) {
lua_geti(state, table_index, key);
}
#if KAGUYA_USE_CPP11
template <typename KEY>
static void rawget(lua_State *state, int table_index, KEY &&key) {
util::one_push(state, std::forward<KEY>(key));
lua_rawget(state, table_index);
}
#endif
template <typename KEY>
static void rawget(lua_State *state, int table_index, const KEY &key) {
util::one_push(state, key);
lua_rawget(state, table_index);
}
static void rawget(lua_State *state, int table_index, luaInt key) {
lua_rawgeti(state, table_index, key);
}
};
template <typename Derived> class LuaTableOrUserDataImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
public:
/// @brief set metatable
/// @param table metatable
bool setMetatable(const LuaTable &table);
/// @brief get metatable
LuaTable getMetatable() const;
/// @brief table->*"function_name"() in c++ and table:function_name(); in lua
/// is same
/// @param function_name function_name in table
MemberFunctionBinder operator->*(const char *function_name);
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename T, typename KEY>
typename lua_type_traits<T>::get_type getField(const KEY &key) const {
lua_State *state = state_();
typedef typename lua_type_traits<T>::get_type get_type;
if (!state) {
except::typeMismatchError(state, "is nil");
return get_type();
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::get(state, stackIndex, key);
return lua_type_traits<T>::get(state, -1);
}
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename KEY> LuaStackRef getField(const KEY &key) const;
#if KAGUYA_USE_CPP11
/// @brief table[key] = value;
template <typename K, typename V> bool setField(K &&key, V &&value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::set(state, stackIndex, std::forward<K>(key),
std::forward<V>(value));
return true;
}
#else
/// @brief table[key] = value;
template <typename K, typename V>
bool setField(const K &key, const V &value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::set(state, stackIndex, key, value);
return true;
}
#endif
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename K> LuaStackRef operator[](K key) const;
/// @brief value = table[key];or table[key] = value;
/// @param key key of table
/// @return reference of field value
template <typename K> TableKeyReferenceProxy<K> operator[](K key);
};
template <typename Derived> class LuaTableImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
template <typename K, typename A> struct gettablekey {
typedef K key_type;
typedef void value_type;
std::vector<K, A> &v_;
gettablekey(std::vector<K, A> &v) : v_(v) {}
void operator()(K key, const void *) { v_.push_back(key); }
};
template <typename V, typename A> struct gettablevalue {
typedef void key_type;
typedef V value_type;
std::vector<V, A> &v_;
gettablevalue(std::vector<V, A> &v) : v_(v) {}
void operator()(const void *, V value) { v_.push_back(value); }
};
template <typename K, typename V, typename C, typename A> struct gettablemap {
typedef K key_type;
typedef V value_type;
std::map<K, V, C, A> &m_;
gettablemap(std::map<K, V, C, A> &m) : m_(m) {}
void operator()(K key, V value) { m_[key] = value; }
};
public:
#if KAGUYA_USE_CPP11
/// @brief rawset(table,key,value)
template <typename K, typename V> bool setRawField(K &&key, V &&value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawset(state, stackIndex, std::forward<K>(key),
std::forward<V>(value));
return true;
}
#else
/// @brief rawset(table,key,value)
template <typename K, typename V>
bool setRawField(const K &key, const V &value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawset(state, stackIndex, key, value);
return true;
}
#endif
/// @brief value = rawget(table,key);
/// @param key key of table
/// @return reference of field value
template <typename T, typename KEY>
typename lua_type_traits<T>::get_type getRawField(const KEY &key) const {
lua_State *state = state_();
typedef typename lua_type_traits<T>::get_type get_type;
if (!state) {
except::typeMismatchError(state, "is nil");
return get_type();
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawget(state, stackIndex, key);
return lua_type_traits<T>::get(state, -1);
}
/// @brief value = rawget(table,key);
/// @param key key of table
/// @return reference of field value
template <typename KEY> LuaStackRef getRawField(const KEY &key) const;
/// @brief foreach table fields
template <class K, class V, class Fun> void foreach_table(Fun f) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
lua_pushnil(state);
while (lua_next(state, stackIndex) != 0) {
// backup key
lua_pushvalue(state, -2);
f(lua_type_traits<K>::get(state, -1), lua_type_traits<V>::get(state, -2));
lua_pop(state, 2); // pop key and value
}
}
/// @brief foreach table fields
template <class K, class V, class Fun>
void foreach_table_breakable(Fun f) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
lua_pushnil(state);
while (lua_next(state, stackIndex) != 0) {
lua_pushvalue(state, -2); // backup key
bool cont = f(lua_type_traits<K>::get(state, -1),
lua_type_traits<V>::get(state, -2));
lua_pop(state, 2); // pop key and value
if (!cont) {
break;
}
}
}
/// @brief If type is table or userdata, return keys.
/// @return field keys
template <typename K, typename A> std::vector<K, A> keys() const {
std::vector<K, A> res;
util::ScopedSavedStack save(state_());
int stackIndex = pushStackIndex_(state_());
size_t size = lua_rawlen(state_(), stackIndex);
res.reserve(size);
foreach_table<K, void>(gettablekey<K, A>(res));
return res;
}
/// @brief If type is table or userdata, return keys.
/// @return field keys
template <typename K> std::vector<K> keys() const {
return keys<K, std::allocator<K> >();
}
std::vector<LuaRef> keys() const;
/// @brief If type is table or userdata, return values.
/// @return field value
template <typename V, typename A> std::vector<V, A> values() const {
std::vector<V, A> res;
util::ScopedSavedStack save(state_());
int stackIndex = pushStackIndex_(state_());
size_t size = lua_rawlen(state_(), stackIndex);
res.reserve(size);
foreach_table<void, V>(gettablevalue<V, A>(res));
return res;
}
/// @brief If type is table or userdata, return values.
/// @return field value
template <typename V> std::vector<V> values() const {
return values<V, std::allocator<V> >();
}
std::vector<LuaRef> values() const;
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V, typename C, typename A>
std::map<K, V, C, A> map() const {
std::map<K, V, C, A> res;
foreach_table<K, V>(gettablemap<K, V, C, A>(res));
return res;
}
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V, typename C> std::map<K, V, C> map() const {
return map<K, V, C, std::allocator<std::pair<const K, V> > >();
}
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V> std::map<K, V> map() const {
return map<K, V, std::less<K> >();
}
std::map<LuaRef, LuaRef> map() const;
};
template <typename Derived> class LuaUserDataImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
public:
/// @brief is type test
template <typename T> bool isType() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::strictCheckType(state, pushStackIndex_(state));
}
template <typename T> bool isConvertible() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::checkType(state, pushStackIndex_(state));
}
template <typename T> bool typeTest() const { return isType<T>(); }
template <typename T> bool weakTypeTest() const { return isConvertible<T>(); }
template <typename T> typename lua_type_traits<T>::get_type get() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::get(state, state ? pushStackIndex_(state) : 0);
}
template <typename T> operator T() const { return get<T>(); }
};
}
}