1
0

cLuaState: Added support for optional params and AStringMap values.

This commit is contained in:
Mattes D 2016-08-16 11:55:12 +02:00
parent e9d1a942d1
commit 89c9c6fe46
2 changed files with 111 additions and 4 deletions

View File

@ -341,6 +341,33 @@ void cLuaState::cStackTable::ForEachArrayElement(std::function<bool(cLuaState &
void cLuaState::cStackTable::ForEachElement(std::function<bool(cLuaState & a_LuaState)> a_ElementCallback) const
{
#ifdef _DEBUG
auto stackTop = lua_gettop(m_LuaState);
#endif
lua_pushvalue(m_LuaState, m_StackPos); // Stk: <table>
lua_pushnil(m_LuaState); // Stk: <table> nil
while (lua_next(m_LuaState, -2)) // Stk: <table> <key> <val>
{
auto shouldAbort = a_ElementCallback(m_LuaState);
ASSERT(lua_gettop(m_LuaState) == stackTop + 3); // The element callback must not change the Lua stack below the value
lua_pop(m_LuaState, 1); // Stk: <table> <key>
if (shouldAbort)
{
// The callback wants to abort
lua_pop(m_LuaState, 2); // Stk: empty
return;
}
}
// Stk: <table>
lua_pop(m_LuaState, 1); // Stk: empty
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cLuaState: // cLuaState:
@ -748,6 +775,24 @@ void cLuaState::Push(const AString & a_String)
void cLuaState::Push(const AStringMap & a_Dictionary)
{
ASSERT(IsValid());
lua_createtable(m_LuaState, 0, static_cast<int>(a_Dictionary.size()));
int newTable = lua_gettop(m_LuaState);
for (const auto & item: a_Dictionary)
{
Push(item.first); // key
Push(item.second); // value
lua_rawset(m_LuaState, newTable);
}
}
void cLuaState::Push(const AStringVector & a_Vector) void cLuaState::Push(const AStringVector & a_Vector)
{ {
ASSERT(IsValid()); ASSERT(IsValid());
@ -1113,6 +1158,37 @@ bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
bool cLuaState::GetStackValue(int a_StackPos, AStringMap & a_Value)
{
// Retrieve all values in a string => string dictionary table:
if (!lua_istable(m_LuaState, a_StackPos))
{
return false;
}
cStackTable tbl(*this, a_StackPos);
bool isValid = true;
tbl.ForEachElement([&isValid, &a_Value](cLuaState & a_LuaState)
{
AString key, val;
if (a_LuaState.GetStackValues(-2, key, val))
{
a_Value[key] = val;
}
else
{
isValid = false;
return true;
}
return false;
}
);
return isValid;
}
bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
{ {
a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);

View File

@ -309,6 +309,24 @@ public:
typedef UniquePtr<cTableRef> cTableRefPtr; typedef UniquePtr<cTableRef> cTableRefPtr;
/** Represents a parameter that is optional - calling a GetStackValue() with this object will not fail if the value on the Lua stack is nil.
Note that the GetStackValue() will still fail if the param is present but of a different type.
The class itself is just a marker so that the template magic will select the correct GetStackValue() overload. */
template <typename T>
class cOptionalParam
{
public:
explicit cOptionalParam(T & a_Dest):
m_Dest(a_Dest)
{
}
T & GetDest(void) { return m_Dest; }
protected:
T & m_Dest;
};
/** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */ /** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */
class cRet class cRet
{ {
@ -475,6 +493,7 @@ public:
// Push a const value onto the stack (keep alpha-sorted): // Push a const value onto the stack (keep alpha-sorted):
void Push(const AString & a_String); void Push(const AString & a_String);
void Push(const AStringMap & a_Dictionary);
void Push(const AStringVector & a_Vector); void Push(const AStringVector & a_Vector);
void Push(const cCraftingGrid * a_Grid); void Push(const cCraftingGrid * a_Grid);
void Push(const cCraftingRecipe * a_Recipe); void Push(const cCraftingRecipe * a_Recipe);
@ -508,6 +527,7 @@ public:
// Returns whether value was changed // Returns whether value was changed
// Enum values are checked for their allowed values and fail if the value is not assigned. // Enum values are checked for their allowed values and fail if the value is not assigned.
bool GetStackValue(int a_StackPos, AString & a_Value); bool GetStackValue(int a_StackPos, AString & a_Value);
bool GetStackValue(int a_StackPos, AStringMap & a_Value);
bool GetStackValue(int a_StackPos, bool & a_Value); bool GetStackValue(int a_StackPos, bool & a_Value);
bool GetStackValue(int a_StackPos, cCallback & a_Callback); bool GetStackValue(int a_StackPos, cCallback & a_Callback);
bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback); bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback);
@ -549,6 +569,17 @@ public:
return true; return true;
} }
/** Retrieves an optional value on the stack - doesn't fail if the stack contains nil instead of the value. */
template <typename T>
bool GetStackValue(int a_StackPos, cOptionalParam<T> && a_ReturnedVal)
{
if (lua_isnoneornil(m_LuaState, a_StackPos))
{
return true;
}
return GetStackValue(a_StackPos, a_ReturnedVal.GetDest());
}
/** Pushes the named value in the table at the top of the stack. /** Pushes the named value in the table at the top of the stack.
a_Name may be a path containing multiple table levels, such as "cChatColor.Blue". a_Name may be a path containing multiple table levels, such as "cChatColor.Blue".
If the value is found, it is pushed on top of the stack and the returned cStackValue is valid. If the value is found, it is pushed on top of the stack and the returned cStackValue is valid.
@ -606,14 +637,14 @@ public:
} }
/** Retrieves a list of values from the Lua stack, starting at the specified index. */ /** Retrieves a list of values from the Lua stack, starting at the specified index. */
template <typename T, typename... Args> template <typename Arg1, typename... Args>
inline bool GetStackValues(int a_StartStackPos, T & a_Ret, Args &&... args) inline bool GetStackValues(int a_StartStackPos, Arg1 && a_Arg1, Args &&... args)
{ {
if (!GetStackValue(a_StartStackPos, a_Ret)) if (!GetStackValue(a_StartStackPos, std::forward<Arg1>(a_Arg1)))
{ {
return false; return false;
} }
return GetStackValues(a_StartStackPos + 1, args...); return GetStackValues(a_StartStackPos + 1, std::forward<Args>(args)...);
} }
/** Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions */ /** Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions */