mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 18:31:26 -10:00
w_bank: add a move constructor. object_copy_including_array_member returns by value, and without a move constructor the return fell back to the shallow copy constructor whenever NRVO was not applied (e.g. MSVC debug builds), after which the local's destructor deleted the freshly allocated arrays -- leaving the stored bank dangling and double-deleting at model unload. Also add noexcept to the move operations, replace the destructor call in move-assignment with explicit delete[]s (using an object after its lifetime has ended is undefined behavior), guard against self-move, and document that the defaulted copy constructor is intentionally shallow for object_copy_including_array_member's copy-then-replace pattern. LuaThread: declare the defaulted move operations noexcept. This exposed that LuaTable was not movable at all (its user-declared destructor suppressed the implicit moves), so LuaThread's implicit move spec was formally throwing -- a hard error on gcc 9, which still requires the spec on a defaulted redeclaration to match the implicit one. Restore LuaTable's rule of five and declare the LuaValue and LuaFunction copy operations noexcept (they only copy a shared_ptr, a raw pointer, and an enum), making the noexcept claims hold throughout the hierarchy. Co-Authored-By: Claude Fable 5 <[email protected]>
247 lines
6.1 KiB
C++
247 lines
6.1 KiB
C++
#ifndef LUATABLE_H
|
|
#define LUATABLE_H
|
|
#pragma once
|
|
|
|
#include "LuaConvert.h"
|
|
#include "LuaValue.h"
|
|
|
|
#include <iterator>
|
|
|
|
namespace luacpp {
|
|
class LuaTable;
|
|
|
|
/**
|
|
* @brief Utility class for iterating over the contents of a lua table
|
|
*
|
|
* The elements are returned as key-value pairs of the table
|
|
*
|
|
* @warning Never manipulate the lua stack while using an instance of this class! It's ok to change the stack but it must
|
|
* be in the exact same state when you call the next method of this class.
|
|
*/
|
|
class LuaTableIterator {
|
|
lua_State* _luaState = nullptr;
|
|
|
|
int _stackTop = 0;
|
|
|
|
bool _hasElement = false;
|
|
|
|
std::pair<LuaValue, LuaValue> _currentVal;
|
|
public:
|
|
/**
|
|
* @brief Initializes the iterator with a table
|
|
* @param t The table to iterate iver
|
|
*/
|
|
explicit LuaTableIterator(const LuaTable& t);
|
|
~LuaTableIterator();
|
|
|
|
LuaTableIterator(const LuaTableIterator&) = delete;
|
|
LuaTableIterator& operator=(const LuaTableIterator&) = delete;
|
|
|
|
/**
|
|
* @brief Test if there is a valid element
|
|
* @return @c true if there is a value, @c false otherwise
|
|
*/
|
|
bool hasElement();
|
|
|
|
/**
|
|
* @brief Advances the iterator to the next element
|
|
*/
|
|
void toNextElement();
|
|
|
|
/**
|
|
* @brief Gets the key-value pair of the current element
|
|
* @return The key-value pair
|
|
*/
|
|
std::pair<LuaValue, LuaValue> getElement();
|
|
};
|
|
|
|
/**
|
|
* @brief Class to improve handling of lua tables.
|
|
*
|
|
* This class provides a high-level interface to lua tables without the need to directly call
|
|
* lua-API functions.
|
|
*
|
|
* @see LuaConvert
|
|
*/
|
|
class LuaTable: public LuaValue {
|
|
public:
|
|
/**
|
|
* @brief STL adaptor for LuaTableIterator
|
|
*
|
|
* This wraps a shared pointer to an iterator so that this class can be copied like the iterator interface expects
|
|
*/
|
|
class iterator {
|
|
public:
|
|
using iterator_category = std::input_iterator_tag;
|
|
using value_type = std::pair<LuaValue, LuaValue>;
|
|
using difference_type = std::ptrdiff_t;
|
|
using pointer = value_type*;
|
|
using reference = value_type&;
|
|
|
|
explicit iterator(const LuaTable& _parent);
|
|
iterator();
|
|
|
|
bool operator==(const iterator& other);
|
|
bool operator!=(const iterator& other);
|
|
|
|
iterator& operator++();
|
|
iterator& operator++(int);
|
|
|
|
std::pair<LuaValue, LuaValue> operator*();
|
|
private:
|
|
std::shared_ptr<LuaTableIterator> _iter;
|
|
bool _atEnd = false;
|
|
};
|
|
|
|
typedef iterator iterator_type;
|
|
|
|
/**
|
|
* @brief Creates a new empty table.
|
|
*/
|
|
static LuaTable create(lua_State* state);
|
|
|
|
/**
|
|
* @brief Default constructor
|
|
*/
|
|
LuaTable();
|
|
|
|
/**
|
|
* Dereferences the stored reference to the table if it exists.
|
|
*/
|
|
~LuaTable() override;
|
|
|
|
// Since we have a user-declared destructor, we need these too.
|
|
LuaTable(const LuaTable&) noexcept = default;
|
|
LuaTable& operator=(const LuaTable&) noexcept = default;
|
|
LuaTable(LuaTable&&) noexcept = default;
|
|
LuaTable& operator=(LuaTable&&) noexcept = default;
|
|
|
|
/**
|
|
* @brief Sets the metatable.
|
|
*
|
|
* The given table will be set as the metatable of this table.
|
|
*
|
|
* @param ref The new metatable.
|
|
* @return Always `true`.
|
|
*/
|
|
bool setMetatable(const LuaTable& ref);
|
|
|
|
/**
|
|
* @brief Sets a new reference.
|
|
* This overload checks if the passed reference is a table
|
|
*
|
|
* @param ref The new reference
|
|
* @return void
|
|
*/
|
|
void setReference(const LuaReference& ref) override;
|
|
|
|
/**
|
|
* @brief Adds a value to this lua table.
|
|
*
|
|
* @param index The index value to use.
|
|
* @param value The value to set at the index.
|
|
*/
|
|
template<class IndexType, class ValueType>
|
|
void addValue(IndexType&& index, ValueType&& value) {
|
|
// Push the table onto the stack by using the reference
|
|
this->pushValue(_luaState);
|
|
|
|
// Push the index and value onto the stac by using the template functions
|
|
convert::pushValue(_luaState, std::forward<IndexType>(index));
|
|
convert::pushValue(_luaState, std::forward<ValueType>(value));
|
|
|
|
// Set the value in the table
|
|
lua_settable(_luaState, -3);
|
|
|
|
// And pop the table again
|
|
lua_pop(_luaState, 1);
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves a value from the table.
|
|
*
|
|
* @param index The index where the value is located.
|
|
* @param target The target location where the value should be stored.
|
|
* @return @c true when the value could be successfully converted, @c false otherwise
|
|
*/
|
|
template<class IndexType, class ValueType>
|
|
bool getValue(const IndexType& index, ValueType& target) const {
|
|
this->pushValue(_luaState);
|
|
|
|
convert::pushValue(_luaState, index);
|
|
|
|
lua_gettable(_luaState, -2);
|
|
|
|
bool ret = convert::popValue(_luaState, target);
|
|
|
|
if (!ret) {
|
|
lua_pop(_luaState, 1);
|
|
}
|
|
|
|
lua_pop(_luaState, 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets a value or throws an exception.
|
|
* This function gets the specified value from the table and returns it
|
|
* or throws an exception if that faild
|
|
*
|
|
* @param index The index of the value to retrieve
|
|
* @return luacpp::ValueType The value
|
|
*
|
|
* @exception LuaException Thrown when an error occurs while converting the value
|
|
*/
|
|
template<class ValueType, class IndexType>
|
|
// IndexType is last so the compiler can deduce it from the argument
|
|
ValueType getValue(const IndexType& index) const {
|
|
ValueType target;
|
|
|
|
if (!getValue(index, target)) {
|
|
throw LuaException("Failed to get lua value!");
|
|
} else {
|
|
return target;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the length of the table.
|
|
*
|
|
* Gets size of the table (the same as using the '#' operator in Lua).
|
|
*
|
|
* @return The size value.
|
|
*/
|
|
size_t getLength() const;
|
|
|
|
/**
|
|
* @brief Returns an iterator to the begin of this table
|
|
*
|
|
* This can be used with STL algorithms or with the C++11 range-base-for-loop
|
|
*
|
|
* @warning Never manipulate the lua stack while using this iterator!
|
|
*
|
|
* @return The iterator to the begin of the table
|
|
*/
|
|
iterator begin() const;
|
|
|
|
/**
|
|
* @brief Returns an iterator to the end of this table
|
|
*
|
|
* This can be used with STL algorithms or with the C++11 range-base-for-loop
|
|
*
|
|
* @return The iterator to the end of the table
|
|
*/
|
|
iterator end() const;
|
|
|
|
};
|
|
|
|
namespace convert {
|
|
|
|
bool popValue(lua_State* luaState, LuaTable& target, int stackposition = -1, bool remove = true);
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|