SharedTable able to store lua tables && related tests.
Fix codestyle.
This commit is contained in:
parent
7e35ab3a76
commit
5407a33947
@ -14,7 +14,7 @@ FILE(GLOB SOURCES src/*.cpp src/*.h)
|
|||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
# Supress CMP0042
|
# Supress warning CMP0042
|
||||||
set(CMAKE_MACOSX_RPATH 1)
|
set(CMAKE_MACOSX_RPATH 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@ -3,24 +3,25 @@
|
|||||||
|
|
||||||
#include <lua.hpp>
|
#include <lua.hpp>
|
||||||
|
|
||||||
static sol::object create_thread(sol::this_state lua, sol::function func, const sol::variadic_args& args)
|
namespace {
|
||||||
{
|
|
||||||
|
static sol::object createThread(sol::this_state lua, sol::function func, const sol::variadic_args &args) noexcept {
|
||||||
return sol::make_object(lua, std::make_unique<threading::LuaThread>(func, args));
|
return sol::make_object(lua, std::make_unique<threading::LuaThread>(func, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
static sol::object create_share(sol::this_state lua)
|
static sol::object createShare(sol::this_state lua) noexcept {
|
||||||
{
|
|
||||||
return sol::make_object(lua, std::make_unique<share_data::SharedTable>());
|
return sol::make_object(lua, std::make_unique<share_data::SharedTable>());
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int luaopen_libwoofer(lua_State *L)
|
} // namespace
|
||||||
{
|
|
||||||
|
extern "C" int luaopen_libwoofer(lua_State *L) {
|
||||||
sol::state_view lua(L);
|
sol::state_view lua(L);
|
||||||
threading::LuaThread::get_user_type(lua);
|
threading::LuaThread::getUserType(lua);
|
||||||
share_data::SharedTable::get_user_type(lua);
|
share_data::SharedTable::getUserType(lua);
|
||||||
sol::table public_api = lua.create_table_with(
|
sol::table public_api = lua.create_table_with(
|
||||||
"thread", create_thread,
|
"thread", createThread,
|
||||||
"share", create_share
|
"share", createShare
|
||||||
);
|
);
|
||||||
sol::stack::push(lua, public_api);
|
sol::stack::push(lua, public_api);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace share_data {
|
namespace share_data {
|
||||||
|
|
||||||
sol::object SharedTable::get_user_type(sol::state_view& lua) noexcept {
|
sol::object SharedTable::getUserType(sol::state_view &lua) noexcept {
|
||||||
static sol::usertype<share_data::SharedTable> type(
|
static sol::usertype<share_data::SharedTable> type(
|
||||||
sol::call_construction(), sol::default_constructor,
|
sol::call_construction(), sol::default_constructor,
|
||||||
sol::meta_function::new_index, &share_data::SharedTable::luaSet,
|
sol::meta_function::new_index, &share_data::SharedTable::luaSet,
|
||||||
@ -16,6 +16,11 @@ sol::object SharedTable::get_user_type(sol::state_view& lua) noexcept {
|
|||||||
return sol::stack::pop<sol::object>(lua);
|
return sol::stack::pop<sol::object>(lua);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SharedTable::set(StoredObject key, StoredObject value) noexcept {
|
||||||
|
std::lock_guard<SpinMutex> g(lock_);
|
||||||
|
data_[std::move(key)] = std::move(value);
|
||||||
|
}
|
||||||
|
|
||||||
void SharedTable::luaSet(sol::stack_object luaKey, sol::stack_object luaValue) noexcept {
|
void SharedTable::luaSet(sol::stack_object luaKey, sol::stack_object luaValue) noexcept {
|
||||||
assert(luaKey.valid());
|
assert(luaKey.valid());
|
||||||
|
|
||||||
@ -31,7 +36,7 @@ void SharedTable::luaSet(sol::stack_object luaKey, sol::stack_object luaValue) n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object SharedTable::luaGet(sol::stack_object key, sol::this_state state) noexcept {
|
sol::object SharedTable::luaGet(sol::stack_object key, sol::this_state state) const noexcept {
|
||||||
assert(key.valid());
|
assert(key.valid());
|
||||||
|
|
||||||
StoredObject cppKey(key);
|
StoredObject cppKey(key);
|
||||||
@ -44,15 +49,16 @@ sol::object SharedTable::luaGet(sol::stack_object key, sol::this_state state) no
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SharedTable::size() noexcept {
|
size_t SharedTable::size() const noexcept {
|
||||||
std::lock_guard<SpinMutex> g(lock_);
|
std::lock_guard<SpinMutex> g(lock_);
|
||||||
return data_.size();
|
return data_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedTable* TablePool::getNew() noexcept {
|
SharedTable* TablePool::getNew() noexcept {
|
||||||
|
SharedTable* ptr = new SharedTable();
|
||||||
std::lock_guard<SpinMutex> g(lock_);
|
std::lock_guard<SpinMutex> g(lock_);
|
||||||
data_.push_back(std::make_unique<SharedTable>());
|
data_.emplace_back(ptr);
|
||||||
return (*data_.rend()).get();
|
return ptr;
|
||||||
}
|
}
|
||||||
std::size_t TablePool::size() const noexcept {
|
std::size_t TablePool::size() const noexcept {
|
||||||
std::lock_guard<SpinMutex> g(lock_);
|
std::lock_guard<SpinMutex> g(lock_);
|
||||||
|
|||||||
@ -15,16 +15,17 @@ class SharedTable {
|
|||||||
public:
|
public:
|
||||||
SharedTable() = default;
|
SharedTable() = default;
|
||||||
virtual ~SharedTable() = default;
|
virtual ~SharedTable() = default;
|
||||||
|
|
||||||
|
static sol::object getUserType(sol::state_view &lua) noexcept;
|
||||||
|
void set(StoredObject, StoredObject) noexcept;
|
||||||
|
size_t size() const noexcept;
|
||||||
|
|
||||||
|
public: // lua bindings
|
||||||
void luaSet(sol::stack_object luaKey, sol::stack_object luaValue) noexcept;
|
void luaSet(sol::stack_object luaKey, sol::stack_object luaValue) noexcept;
|
||||||
sol::object luaGet(sol::stack_object key, sol::this_state state) noexcept;
|
sol::object luaGet(sol::stack_object key, sol::this_state state) const noexcept;
|
||||||
|
|
||||||
static sol::object get_user_type(sol::state_view& lua) noexcept;
|
|
||||||
|
|
||||||
private: // lau bindings
|
|
||||||
size_t size() noexcept;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SpinMutex lock_;
|
mutable SpinMutex lock_;
|
||||||
std::unordered_map<StoredObject, StoredObject> data_;
|
std::unordered_map<StoredObject, StoredObject> data_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -49,4 +50,4 @@ private:
|
|||||||
|
|
||||||
TablePool& defaultPool() noexcept;
|
TablePool& defaultPool() noexcept;
|
||||||
|
|
||||||
} // core
|
} // share_data
|
||||||
|
|||||||
@ -21,4 +21,4 @@ private:
|
|||||||
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // core
|
} // share_data
|
||||||
|
|||||||
@ -1,51 +1,183 @@
|
|||||||
#include "stored-object.h"
|
#include "stored-object.h"
|
||||||
|
|
||||||
#include "shared-table.h"
|
#include "shared-table.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace share_data {
|
namespace share_data {
|
||||||
|
|
||||||
bool FunctionHolder::rawCompare(const BaseHolder* other) const noexcept {
|
namespace {
|
||||||
return function_ == static_cast<const FunctionHolder*>(other)->function_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FunctionHolder::rawLess(const BaseHolder* other) const noexcept {
|
template<typename StoredType>
|
||||||
return function_ < static_cast<const FunctionHolder*>(other)->function_;
|
class PrimitiveHolder : public BaseHolder {
|
||||||
}
|
public:
|
||||||
|
PrimitiveHolder(sol::stack_object luaObject) noexcept
|
||||||
|
: data_(luaObject.as<StoredType>()) {}
|
||||||
|
|
||||||
std::size_t FunctionHolder::hash() const noexcept {
|
PrimitiveHolder(sol::object luaObject) noexcept
|
||||||
return std::hash<std::string>()(function_);
|
: data_(luaObject.as<StoredType>()) {}
|
||||||
}
|
|
||||||
|
|
||||||
sol::object FunctionHolder::unpack(sol::this_state state) const noexcept {
|
PrimitiveHolder(const StoredType& init) noexcept
|
||||||
sol::state_view lua((lua_State*)state);
|
: data_(init) {}
|
||||||
sol::function loader = lua["loadstring"];
|
|
||||||
assert(loader.valid());
|
|
||||||
|
|
||||||
sol::function result = loader(function_);
|
bool rawCompare(const BaseHolder* other) const noexcept final {
|
||||||
if (!result.valid()) {
|
assert(type_ == other->type());
|
||||||
ERROR << "Unable to restore function!" << std::endl;
|
return static_cast<const PrimitiveHolder<StoredType>*>(other)->data_ == data_;
|
||||||
ERROR << "Content:" << std::endl;
|
}
|
||||||
ERROR << function_ << std::endl;
|
|
||||||
|
bool rawLess(const BaseHolder* other) const noexcept final {
|
||||||
|
assert(type_ == other->type());
|
||||||
|
return data_ < static_cast<const PrimitiveHolder<StoredType>*>(other)->data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hash() const noexcept final {
|
||||||
|
return std::hash<StoredType>()(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object unpack(sol::this_state state) const noexcept final {
|
||||||
|
return sol::make_object(state, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
StoredType data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FunctionHolder : public BaseHolder {
|
||||||
|
public:
|
||||||
|
template<typename SolObject>
|
||||||
|
FunctionHolder(SolObject luaObject) noexcept {
|
||||||
|
sol::state_view lua(luaObject.lua_state());
|
||||||
|
sol::function dumper = lua["string"]["dump"];
|
||||||
|
|
||||||
|
assert(dumper.valid());
|
||||||
|
function_ = dumper(luaObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rawCompare(const BaseHolder* other) const noexcept final {
|
||||||
|
return function_ == static_cast<const FunctionHolder*>(other)->function_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rawLess(const BaseHolder* other) const noexcept final {
|
||||||
|
return function_ < static_cast<const FunctionHolder*>(other)->function_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hash() const noexcept final {
|
||||||
|
return std::hash<std::string>()(function_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object unpack(sol::this_state state) const noexcept final {
|
||||||
|
sol::state_view lua((lua_State*)state);
|
||||||
|
sol::function loader = lua["loadstring"];
|
||||||
|
assert(loader.valid());
|
||||||
|
|
||||||
|
sol::function result = loader(function_);
|
||||||
|
if (!result.valid()) {
|
||||||
|
ERROR << "Unable to restore function!" << std::endl;
|
||||||
|
ERROR << "Content:" << std::endl;
|
||||||
|
ERROR << function_ << std::endl;
|
||||||
|
}
|
||||||
|
return sol::make_object(state, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string function_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is used as a storage for visited sol::tables
|
||||||
|
// TODO: try to use map or unordered map instead of linear search in vector
|
||||||
|
// TODO: Trick is - sol::object has only operator==:/
|
||||||
|
typedef std::vector<std::pair<sol::object, SharedTable*>> SolTableToShared;
|
||||||
|
|
||||||
|
void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visited) noexcept;
|
||||||
|
|
||||||
|
StoredObject makeStoredObject(sol::object luaObject, SolTableToShared& visited) noexcept {
|
||||||
|
if (luaObject.get_type() == sol::type::table) {
|
||||||
|
sol::table luaTable = luaObject;
|
||||||
|
auto comparator = [&luaTable](const std::pair<sol::table, SharedTable*>& element){
|
||||||
|
return element.first == luaTable;
|
||||||
|
};
|
||||||
|
auto st = std::find_if(visited.begin(), visited.end(), comparator);
|
||||||
|
|
||||||
|
if (st == std::end(visited)) {
|
||||||
|
SharedTable* table = defaultPool().getNew();
|
||||||
|
visited.emplace_back(std::make_pair(luaTable, table));
|
||||||
|
dumpTable(table, luaTable, visited);
|
||||||
|
return StoredObject(table);
|
||||||
|
} else {
|
||||||
|
return StoredObject(st->second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return StoredObject(luaObject);
|
||||||
}
|
}
|
||||||
return sol::make_object(state, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visited) noexcept {
|
||||||
|
for(auto& row : luaTable) {
|
||||||
|
target->set(makeStoredObject(row.first, visited), makeStoredObject(row.second, visited));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SolObject>
|
||||||
|
std::unique_ptr<BaseHolder> fromSolObject(SolObject luaObject) {
|
||||||
|
switch(luaObject.get_type()) {
|
||||||
|
case sol::type::nil:
|
||||||
|
break;
|
||||||
|
case sol::type::boolean:
|
||||||
|
return std::make_unique<PrimitiveHolder<bool>>(luaObject);
|
||||||
|
case sol::type::number:
|
||||||
|
return std::make_unique<PrimitiveHolder<double>>(luaObject);
|
||||||
|
case sol::type::string:
|
||||||
|
return std::make_unique<PrimitiveHolder<std::string>>(luaObject);
|
||||||
|
case sol::type::userdata:
|
||||||
|
return std::make_unique<PrimitiveHolder<SharedTable*>>(luaObject);
|
||||||
|
case sol::type::function:
|
||||||
|
return std::make_unique<FunctionHolder>(luaObject);
|
||||||
|
case sol::type::table:
|
||||||
|
{
|
||||||
|
sol::table luaTable = luaObject;
|
||||||
|
// Tables pool is used to store tables.
|
||||||
|
// Right now not defiantly clear how ownership between states works.
|
||||||
|
SharedTable* table = defaultPool().getNew();
|
||||||
|
SolTableToShared visited{{luaTable, table}};
|
||||||
|
|
||||||
|
// Let's dump table and all subtables
|
||||||
|
// SolTableToShared is used to prevent from infinity recursion
|
||||||
|
// in recursive tables
|
||||||
|
dumpTable(table, luaTable, visited);
|
||||||
|
return std::make_unique<PrimitiveHolder<SharedTable*>>(table);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ERROR << "Unable to store object of that type: " << (int)luaObject.get_type() << std::endl;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
StoredObject::StoredObject(StoredObject&& init) noexcept
|
StoredObject::StoredObject(StoredObject&& init) noexcept
|
||||||
: data_(std::move(init.data_)) {}
|
: data_(std::move(init.data_)) {}
|
||||||
|
|
||||||
StoredObject::operator bool() const noexcept {
|
|
||||||
return (bool)data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
StoredObject::StoredObject(SharedTable* table) noexcept
|
StoredObject::StoredObject(SharedTable* table) noexcept
|
||||||
: data_(new PrimitiveHolder<SharedTable*>(table)) {
|
: data_(new PrimitiveHolder<SharedTable*>(table)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StoredObject::StoredObject(sol::object object) noexcept
|
||||||
|
: data_(fromSolObject(object)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StoredObject::StoredObject(sol::stack_object object) noexcept
|
||||||
|
: data_(fromSolObject(object)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StoredObject::operator bool() const noexcept {
|
||||||
|
return (bool)data_;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t StoredObject::hash() const noexcept {
|
std::size_t StoredObject::hash() const noexcept {
|
||||||
if (data_)
|
if (data_)
|
||||||
return data_->hash();
|
return data_->hash();
|
||||||
@ -79,4 +211,4 @@ bool StoredObject::operator<(const StoredObject& o) const noexcept {
|
|||||||
return data_.get() < o.data_.get();
|
return data_.get() < o.data_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // share_data
|
||||||
|
|||||||
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
namespace share_data {
|
namespace share_data {
|
||||||
|
|
||||||
#define ERROR std::cerr
|
|
||||||
|
|
||||||
class BaseHolder {
|
class BaseHolder {
|
||||||
public:
|
public:
|
||||||
BaseHolder() noexcept : type_(sol::type::nil) {}
|
BaseHolder() noexcept : type_(sol::type::nil) {}
|
||||||
@ -40,60 +38,6 @@ private:
|
|||||||
BaseHolder(BaseHolder&) = delete;
|
BaseHolder(BaseHolder&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename StoredType>
|
|
||||||
class PrimitiveHolder : public BaseHolder {
|
|
||||||
public:
|
|
||||||
PrimitiveHolder(sol::stack_object luaObject) noexcept
|
|
||||||
: data_(luaObject.as<StoredType>()) {}
|
|
||||||
|
|
||||||
PrimitiveHolder(sol::object luaObject) noexcept
|
|
||||||
: data_(luaObject.as<StoredType>()) {}
|
|
||||||
|
|
||||||
PrimitiveHolder(const StoredType& init) noexcept
|
|
||||||
: data_(init) {}
|
|
||||||
|
|
||||||
bool rawCompare(const BaseHolder* other) const noexcept final {
|
|
||||||
assert(type_ == other->type());
|
|
||||||
return static_cast<const PrimitiveHolder<StoredType>*>(other)->data_ == data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rawLess(const BaseHolder* other) const noexcept final {
|
|
||||||
assert(type_ == other->type());
|
|
||||||
return data_ < static_cast<const PrimitiveHolder<StoredType>*>(other)->data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t hash() const noexcept final {
|
|
||||||
return std::hash<StoredType>()(data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
sol::object unpack(sol::this_state state) const noexcept final {
|
|
||||||
return sol::make_object(state, data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StoredType data_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FunctionHolder : public BaseHolder {
|
|
||||||
public:
|
|
||||||
template<typename SolObject>
|
|
||||||
FunctionHolder(SolObject luaObject) noexcept {
|
|
||||||
sol::state_view lua(luaObject.lua_state());
|
|
||||||
sol::function dumper = lua["string"]["dump"];
|
|
||||||
|
|
||||||
assert(dumper.valid());
|
|
||||||
function_ = dumper(luaObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rawCompare(const BaseHolder* other) const noexcept final;
|
|
||||||
bool rawLess(const BaseHolder* other) const noexcept final;
|
|
||||||
std::size_t hash() const noexcept final;
|
|
||||||
sol::object unpack(sol::this_state state) const noexcept final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string function_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedTable;
|
class SharedTable;
|
||||||
|
|
||||||
class StoredObject {
|
class StoredObject {
|
||||||
@ -101,32 +45,8 @@ public:
|
|||||||
StoredObject() = default;
|
StoredObject() = default;
|
||||||
StoredObject(StoredObject&& init) noexcept;
|
StoredObject(StoredObject&& init) noexcept;
|
||||||
StoredObject(SharedTable*) noexcept;
|
StoredObject(SharedTable*) noexcept;
|
||||||
|
StoredObject(sol::object) noexcept;
|
||||||
template<typename SolObject>
|
StoredObject(sol::stack_object) noexcept;
|
||||||
StoredObject(SolObject luaObject)
|
|
||||||
{
|
|
||||||
switch(luaObject.get_type()) {
|
|
||||||
case sol::type::nil:
|
|
||||||
break;
|
|
||||||
case sol::type::boolean:
|
|
||||||
data_.reset(new PrimitiveHolder<bool>(luaObject));
|
|
||||||
break;
|
|
||||||
case sol::type::number:
|
|
||||||
data_.reset(new PrimitiveHolder<double>(luaObject));
|
|
||||||
break;
|
|
||||||
case sol::type::string:
|
|
||||||
data_.reset(new PrimitiveHolder<std::string>(luaObject));
|
|
||||||
break;
|
|
||||||
case sol::type::userdata:
|
|
||||||
data_.reset(new PrimitiveHolder<SharedTable*>(luaObject));
|
|
||||||
break;
|
|
||||||
case sol::type::function:
|
|
||||||
data_.reset(new FunctionHolder(luaObject));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR << "Unable to store object of that type: " << (int)luaObject.get_type() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() const noexcept;
|
operator bool() const noexcept;
|
||||||
std::size_t hash() const noexcept;
|
std::size_t hash() const noexcept;
|
||||||
@ -147,6 +67,7 @@ private:
|
|||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
|
// For storing as key in std::unordered_map
|
||||||
template<>
|
template<>
|
||||||
struct hash<share_data::StoredObject> {
|
struct hash<share_data::StoredObject> {
|
||||||
std::size_t operator()(const share_data::StoredObject &object) const noexcept {
|
std::size_t operator()(const share_data::StoredObject &object) const noexcept {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace threading {
|
namespace threading {
|
||||||
|
|
||||||
LuaThread::LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept{
|
LuaThread::LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept {
|
||||||
// 1. Dump function to string
|
// 1. Dump function to string
|
||||||
sol::state_view lua(function.lua_state());
|
sol::state_view lua(function.lua_state());
|
||||||
str_function_ = lua["string"]["dump"](function);
|
str_function_ = lua["string"]["dump"](function);
|
||||||
@ -14,31 +14,27 @@ LuaThread::LuaThread(const sol::function& function, const sol::variadic_args& ar
|
|||||||
sol::lib::base, sol::lib::string,
|
sol::lib::base, sol::lib::string,
|
||||||
sol::lib::package, sol::lib::io, sol::lib::os
|
sol::lib::package, sol::lib::io, sol::lib::os
|
||||||
);
|
);
|
||||||
get_user_type(*p_state_);
|
getUserType(*p_state_);
|
||||||
share_data::SharedTable::get_user_type(*p_state_);
|
share_data::SharedTable::getUserType(*p_state_);
|
||||||
|
|
||||||
// 3. Save parameters
|
// 3. Save parameters
|
||||||
store_args(args);
|
storeArgs(args);
|
||||||
|
|
||||||
// 4. Run thread
|
// 4. Run thread
|
||||||
p_thread_.reset(new std::thread(&LuaThread::work, this));
|
p_thread_.reset(new std::thread(&LuaThread::work, this));
|
||||||
assert(p_thread_.get() != NULL);
|
assert(p_thread_.get() != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaThread::store_args(const sol::variadic_args& args) noexcept
|
void LuaThread::storeArgs(const sol::variadic_args &args) noexcept {
|
||||||
{
|
|
||||||
p_arguments_ = std::make_shared<std::vector<sol::object>>();
|
p_arguments_ = std::make_shared<std::vector<sol::object>>();
|
||||||
for(auto iter = args.begin(); iter != args.end(); iter++)
|
for(auto iter = args.begin(); iter != args.end(); iter++) {
|
||||||
{
|
|
||||||
share_data::StoredObject store(iter->get<sol::object>());
|
share_data::StoredObject store(iter->get<sol::object>());
|
||||||
p_arguments_->push_back(store.unpack(sol::this_state{p_state_->lua_state()}));
|
p_arguments_->push_back(store.unpack(sol::this_state{p_state_->lua_state()}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaThread::join() noexcept
|
void LuaThread::join() noexcept {
|
||||||
{
|
if (p_thread_.get()) {
|
||||||
if (p_thread_.get())
|
|
||||||
{
|
|
||||||
p_thread_->join();
|
p_thread_->join();
|
||||||
p_thread_.reset();
|
p_thread_.reset();
|
||||||
}
|
}
|
||||||
@ -48,44 +44,38 @@ void LuaThread::join() noexcept
|
|||||||
p_state_.reset();
|
p_state_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaThread::detach() noexcept
|
void LuaThread::detach() noexcept {
|
||||||
{
|
|
||||||
p_thread_->detach();
|
p_thread_->detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaThread::work() noexcept
|
void LuaThread::work() noexcept {
|
||||||
{
|
if (p_state_.get() && p_arguments_.get()) {
|
||||||
if (p_state_.get() && p_arguments_.get())
|
|
||||||
{
|
|
||||||
std::string func_owner = std::move(str_function_);
|
std::string func_owner = std::move(str_function_);
|
||||||
std::shared_ptr<sol::state> state_owner = p_state_;
|
std::shared_ptr<sol::state> state_owner = p_state_;
|
||||||
std::shared_ptr<std::vector<sol::object>> arguments_owner = p_arguments_;
|
std::shared_ptr<std::vector<sol::object>> arguments_owner = p_arguments_;
|
||||||
sol::function_result func = (*state_owner)["loadstring"](func_owner);
|
sol::function_result func = (*state_owner)["loadstring"](func_owner);
|
||||||
func.get<sol::function>()(sol::as_args(*arguments_owner));
|
func.get<sol::function>()(sol::as_args(*arguments_owner));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
throw sol::error("Internal error: invalid thread Lua state");
|
throw sol::error("Internal error: invalid thread Lua state");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LuaThread::thread_id() noexcept
|
std::string LuaThread::threadId() noexcept {
|
||||||
{
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::this_thread::get_id();
|
ss << std::this_thread::get_id();
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object LuaThread::get_user_type(sol::state_view& lua) noexcept
|
sol::object LuaThread::getUserType(sol::state_view &lua) noexcept
|
||||||
{
|
{
|
||||||
static sol::usertype<LuaThread> type(
|
static sol::usertype<LuaThread> type(
|
||||||
sol::call_construction(), sol::constructors<sol::types<sol::function, sol::variadic_args>>(),
|
sol::call_construction(), sol::constructors<sol::types<sol::function, sol::variadic_args>>(),
|
||||||
"join", &LuaThread::join,
|
"join", &LuaThread::join,
|
||||||
"detach", &LuaThread::detach,
|
"detach", &LuaThread::detach,
|
||||||
"thread_id", &LuaThread::thread_id
|
"thread_id", &LuaThread::threadId
|
||||||
);
|
);
|
||||||
sol::stack::push(lua, type);
|
sol::stack::push(lua, type);
|
||||||
return sol::stack::pop<sol::object>(lua);
|
return sol::stack::pop<sol::object>(lua);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // threading
|
||||||
|
|||||||
@ -10,20 +10,19 @@
|
|||||||
|
|
||||||
namespace threading {
|
namespace threading {
|
||||||
|
|
||||||
class LuaThread
|
class LuaThread {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept;
|
LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept;
|
||||||
virtual ~LuaThread() noexcept = default;
|
virtual ~LuaThread() noexcept = default;
|
||||||
void join() noexcept;
|
void join() noexcept;
|
||||||
void detach() noexcept;
|
void detach() noexcept;
|
||||||
|
|
||||||
static std::string thread_id() noexcept;
|
static std::string threadId() noexcept;
|
||||||
static sol::object get_user_type(sol::state_view& lua) noexcept;
|
static sol::object getUserType(sol::state_view &lua) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void work() noexcept;
|
void work() noexcept;
|
||||||
void store_args(const sol::variadic_args& args) noexcept;
|
void storeArgs(const sol::variadic_args &args) noexcept;
|
||||||
|
|
||||||
std::string str_function_;
|
std::string str_function_;
|
||||||
std::shared_ptr<sol::state> p_state_;
|
std::shared_ptr<sol::state> p_state_;
|
||||||
@ -31,4 +30,4 @@ private:
|
|||||||
std::shared_ptr<std::vector<sol::object>> p_arguments_;
|
std::shared_ptr<std::vector<sol::object>> p_arguments_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // threading
|
||||||
|
|||||||
9
src/utils.h
Normal file
9
src/utils.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
# define ERROR if(false) std::cerr
|
||||||
|
#else
|
||||||
|
# define ERROR std::cerr
|
||||||
|
#endif
|
||||||
@ -2,21 +2,24 @@
|
|||||||
|
|
||||||
#include "shared-table.h"
|
#include "shared-table.h"
|
||||||
|
|
||||||
using namespace core;
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace share_data;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void bootstrapState(sol::state& lua) {
|
void bootstrapState(sol::state& lua) {
|
||||||
lua.open_libraries(
|
lua.open_libraries(
|
||||||
sol::lib::base,
|
sol::lib::base,
|
||||||
sol::lib::string
|
sol::lib::string,
|
||||||
|
sol::lib::table
|
||||||
);
|
);
|
||||||
SharedTable::bind(lua);
|
SharedTable::getUserType(lua);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
TEST(sharedTable, singleThreadSet) {
|
TEST(sharedTable, primitiveTypes) {
|
||||||
SharedTable st;
|
SharedTable st;
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
bootstrapState(lua);
|
bootstrapState(lua);
|
||||||
@ -30,10 +33,8 @@ st.thr = true
|
|||||||
st.del = "secret"
|
st.del = "secret"
|
||||||
st.del = nil
|
st.del = nil
|
||||||
)");
|
)");
|
||||||
if (!res1.valid()) {
|
|
||||||
FAIL() << "Set res1 failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ASSERT_TRUE(res1.valid()) << "Set res1 failed";
|
||||||
ASSERT_EQ(lua["st"]["fst"], std::string("first"));
|
ASSERT_EQ(lua["st"]["fst"], std::string("first"));
|
||||||
ASSERT_EQ(lua["st"]["snd"], (double)2);
|
ASSERT_EQ(lua["st"]["snd"], (double)2);
|
||||||
ASSERT_EQ(lua["st"]["thr"], true);
|
ASSERT_EQ(lua["st"]["thr"], true);
|
||||||
@ -48,10 +49,8 @@ st[42] = "answer"
|
|||||||
st[42] = nil
|
st[42] = nil
|
||||||
st.deleted = st[42] == nil
|
st.deleted = st[42] == nil
|
||||||
)");
|
)");
|
||||||
if (!res2.valid()) {
|
|
||||||
FAIL() << "Set res2 failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ASSERT_TRUE(res2.valid()) << "Set res2 failed";
|
||||||
ASSERT_EQ(lua["st"][1], 3);
|
ASSERT_EQ(lua["st"][1], 3);
|
||||||
ASSERT_EQ(lua["st"][2], std::string("number"));
|
ASSERT_EQ(lua["st"][2], std::string("number"));
|
||||||
ASSERT_EQ(lua["st"][-1], false);
|
ASSERT_EQ(lua["st"][-1], false);
|
||||||
@ -61,34 +60,13 @@ st.deleted = st[42] == nil
|
|||||||
st[true] = false
|
st[true] = false
|
||||||
st[false] = 9
|
st[false] = 9
|
||||||
)");
|
)");
|
||||||
if (!res3.valid()) {
|
|
||||||
FAIL() << "Set res3 failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ASSERT_TRUE(res3.valid()) << "Set res3 failed";
|
||||||
ASSERT_EQ(lua["st"][true], false);
|
ASSERT_EQ(lua["st"][true], false);
|
||||||
ASSERT_EQ(lua["st"][false], 9);
|
ASSERT_EQ(lua["st"][false], 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(sharedTable, asGlobalTable) {
|
TEST(sharedTable, multipleStates) {
|
||||||
sol::state lua;
|
|
||||||
SharedTable st;
|
|
||||||
SharedTable::bind(lua);
|
|
||||||
|
|
||||||
lua["st"] = &st;
|
|
||||||
|
|
||||||
lua.script(R"(
|
|
||||||
_G = st
|
|
||||||
n = 1
|
|
||||||
b = false
|
|
||||||
s = "Oo"
|
|
||||||
)");
|
|
||||||
|
|
||||||
ASSERT_EQ(lua["n"], 1);
|
|
||||||
ASSERT_EQ(lua["b"], false);
|
|
||||||
ASSERT_EQ(lua["s"], std::string("Oo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(sharedTable, severalStates) {
|
|
||||||
sol::state lua1, lua2;
|
sol::state lua1, lua2;
|
||||||
bootstrapState(lua1);
|
bootstrapState(lua1);
|
||||||
bootstrapState(lua2);
|
bootstrapState(lua2);
|
||||||
@ -153,7 +131,7 @@ st.thr = true)");
|
|||||||
ASSERT_EQ(lua["st"]["thr"], true);
|
ASSERT_EQ(lua["st"]["thr"], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(sharedTable, nestedTables) {
|
TEST(sharedTable, playingWithSharedTables) {
|
||||||
SharedTable recursive, st1, st2;
|
SharedTable recursive, st1, st2;
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
bootstrapState(lua);
|
bootstrapState(lua);
|
||||||
@ -204,3 +182,96 @@ end
|
|||||||
|
|
||||||
ASSERT_EQ(sf2(std::string("SUCCESS")).get<std::string>(), std::string("*SUCCESS*"));
|
ASSERT_EQ(sf2(std::string("SUCCESS")).get<std::string>(), std::string("*SUCCESS*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(sharedTable, playingWithTables) {
|
||||||
|
SharedTable st;
|
||||||
|
sol::state lua;
|
||||||
|
bootstrapState(lua);
|
||||||
|
|
||||||
|
lua["st"] = &st;
|
||||||
|
auto res = lua.script(R"(
|
||||||
|
st.works = "fine"
|
||||||
|
st.person = {name = 'John Doe', age = 25}
|
||||||
|
pet = {
|
||||||
|
type = "cat",
|
||||||
|
name = "Tomas",
|
||||||
|
real = "Яша",
|
||||||
|
owner = "Mama",
|
||||||
|
spec = { colour = "grey", legs = 4, eyes = 2 }
|
||||||
|
}
|
||||||
|
st.pet = pet
|
||||||
|
recursive = {}
|
||||||
|
recursive.next = recursive
|
||||||
|
recursive.prev = recursive
|
||||||
|
recursive.val = "recursive"
|
||||||
|
st.recursive = recursive
|
||||||
|
)");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res.valid());
|
||||||
|
ASSERT_EQ(lua["st"]["person"]["name"], std::string("John Doe"));
|
||||||
|
ASSERT_EQ(lua["st"]["person"]["age"], 25);
|
||||||
|
ASSERT_EQ(lua["st"]["pet"]["type"], std::string("cat"));
|
||||||
|
ASSERT_EQ(lua["st"]["pet"]["name"], std::string("Tomas"));
|
||||||
|
ASSERT_EQ(lua["st"]["pet"]["real"], std::string("Яша"));
|
||||||
|
ASSERT_EQ(lua["st"]["pet"]["spec"]["colour"], std::string("grey"));
|
||||||
|
ASSERT_EQ(lua["st"]["pet"]["spec"]["legs"], 4);
|
||||||
|
ASSERT_EQ(lua["st"]["recursive"]["prev"]["next"]["next"]["val"], std::string("recursive"));
|
||||||
|
|
||||||
|
defaultPool().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sharedTable, stress) {
|
||||||
|
sol::state lua;
|
||||||
|
bootstrapState(lua);
|
||||||
|
SharedTable st;
|
||||||
|
|
||||||
|
lua["st"] = &st;
|
||||||
|
|
||||||
|
auto res1 = lua.script(R"(
|
||||||
|
for i = 1, 1000000 do
|
||||||
|
st[i] = tostring(i)
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res1.valid());
|
||||||
|
ASSERT_TRUE(st.size() == 1'000'000);
|
||||||
|
|
||||||
|
auto res2 = lua.script(R"(
|
||||||
|
for i = 1000000, 1, -1 do
|
||||||
|
st[i] = nil
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
ASSERT_TRUE(res2.valid());
|
||||||
|
ASSERT_TRUE(st.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sharedTable, stressWithThreads) {
|
||||||
|
SharedTable st;
|
||||||
|
|
||||||
|
const size_t threadCount = 10;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for(size_t i = 0; i < threadCount; i++) {
|
||||||
|
threads.emplace_back([&st, thrId(i)] {
|
||||||
|
sol::state lua;
|
||||||
|
bootstrapState(lua);
|
||||||
|
lua["st"] = &st;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "st[" << thrId << "] = 1" << std::endl;
|
||||||
|
ss << "for i = 1, 100000 do" << std::endl;
|
||||||
|
ss << " st[" << thrId << "] = " << "st[" << thrId << "] + 1" << std::endl;
|
||||||
|
ss << "end" << std::endl;
|
||||||
|
lua.script(ss.str());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
bootstrapState(lua);
|
||||||
|
lua["st"] = &st;
|
||||||
|
for(size_t i = 0; i < threadCount; i++) {
|
||||||
|
ASSERT_TRUE(lua["st"][i] == 100'001) << (double)lua["st"][i] << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user