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)
|
||||
|
||||
if(APPLE)
|
||||
# Supress CMP0042
|
||||
# Supress warning CMP0042
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
endif()
|
||||
|
||||
|
||||
@ -3,24 +3,25 @@
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
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>());
|
||||
}
|
||||
|
||||
extern "C" int luaopen_libwoofer(lua_State *L)
|
||||
{
|
||||
} // namespace
|
||||
|
||||
extern "C" int luaopen_libwoofer(lua_State *L) {
|
||||
sol::state_view lua(L);
|
||||
threading::LuaThread::get_user_type(lua);
|
||||
share_data::SharedTable::get_user_type(lua);
|
||||
threading::LuaThread::getUserType(lua);
|
||||
share_data::SharedTable::getUserType(lua);
|
||||
sol::table public_api = lua.create_table_with(
|
||||
"thread", create_thread,
|
||||
"share", create_share
|
||||
"thread", createThread,
|
||||
"share", createShare
|
||||
);
|
||||
sol::stack::push(lua, public_api);
|
||||
return 1;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
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(
|
||||
sol::call_construction(), sol::default_constructor,
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
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());
|
||||
|
||||
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_);
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
SharedTable* TablePool::getNew() noexcept {
|
||||
SharedTable* ptr = new SharedTable();
|
||||
std::lock_guard<SpinMutex> g(lock_);
|
||||
data_.push_back(std::make_unique<SharedTable>());
|
||||
return (*data_.rend()).get();
|
||||
data_.emplace_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
std::size_t TablePool::size() const noexcept {
|
||||
std::lock_guard<SpinMutex> g(lock_);
|
||||
|
||||
@ -15,16 +15,17 @@ class SharedTable {
|
||||
public:
|
||||
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;
|
||||
sol::object luaGet(sol::stack_object key, sol::this_state state) noexcept;
|
||||
|
||||
static sol::object get_user_type(sol::state_view& lua) noexcept;
|
||||
|
||||
private: // lau bindings
|
||||
size_t size() noexcept;
|
||||
sol::object luaGet(sol::stack_object key, sol::this_state state) const noexcept;
|
||||
|
||||
protected:
|
||||
SpinMutex lock_;
|
||||
mutable SpinMutex lock_;
|
||||
std::unordered_map<StoredObject, StoredObject> data_;
|
||||
|
||||
private:
|
||||
@ -49,4 +50,4 @@ private:
|
||||
|
||||
TablePool& defaultPool() noexcept;
|
||||
|
||||
} // core
|
||||
} // share_data
|
||||
|
||||
@ -21,4 +21,4 @@ private:
|
||||
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
} // core
|
||||
} // share_data
|
||||
|
||||
@ -1,51 +1,183 @@
|
||||
#include "stored-object.h"
|
||||
|
||||
#include "shared-table.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace share_data {
|
||||
|
||||
bool FunctionHolder::rawCompare(const BaseHolder* other) const noexcept {
|
||||
return function_ == static_cast<const FunctionHolder*>(other)->function_;
|
||||
}
|
||||
namespace {
|
||||
|
||||
bool FunctionHolder::rawLess(const BaseHolder* other) const noexcept {
|
||||
return function_ < static_cast<const FunctionHolder*>(other)->function_;
|
||||
}
|
||||
template<typename StoredType>
|
||||
class PrimitiveHolder : public BaseHolder {
|
||||
public:
|
||||
PrimitiveHolder(sol::stack_object luaObject) noexcept
|
||||
: data_(luaObject.as<StoredType>()) {}
|
||||
|
||||
std::size_t FunctionHolder::hash() const noexcept {
|
||||
return std::hash<std::string>()(function_);
|
||||
}
|
||||
PrimitiveHolder(sol::object luaObject) noexcept
|
||||
: data_(luaObject.as<StoredType>()) {}
|
||||
|
||||
sol::object FunctionHolder::unpack(sol::this_state state) const noexcept {
|
||||
sol::state_view lua((lua_State*)state);
|
||||
sol::function loader = lua["loadstring"];
|
||||
assert(loader.valid());
|
||||
PrimitiveHolder(const StoredType& init) noexcept
|
||||
: data_(init) {}
|
||||
|
||||
sol::function result = loader(function_);
|
||||
if (!result.valid()) {
|
||||
ERROR << "Unable to restore function!" << std::endl;
|
||||
ERROR << "Content:" << std::endl;
|
||||
ERROR << function_ << std::endl;
|
||||
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 {
|
||||
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
|
||||
: data_(std::move(init.data_)) {}
|
||||
|
||||
StoredObject::operator bool() const noexcept {
|
||||
return (bool)data_;
|
||||
}
|
||||
|
||||
StoredObject::StoredObject(SharedTable* table) noexcept
|
||||
: 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 {
|
||||
if (data_)
|
||||
return data_->hash();
|
||||
@ -79,4 +211,4 @@ bool StoredObject::operator<(const StoredObject& o) const noexcept {
|
||||
return data_.get() < o.data_.get();
|
||||
}
|
||||
|
||||
}
|
||||
} // share_data
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
namespace share_data {
|
||||
|
||||
#define ERROR std::cerr
|
||||
|
||||
class BaseHolder {
|
||||
public:
|
||||
BaseHolder() noexcept : type_(sol::type::nil) {}
|
||||
@ -40,60 +38,6 @@ private:
|
||||
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 StoredObject {
|
||||
@ -101,32 +45,8 @@ public:
|
||||
StoredObject() = default;
|
||||
StoredObject(StoredObject&& init) noexcept;
|
||||
StoredObject(SharedTable*) noexcept;
|
||||
|
||||
template<typename SolObject>
|
||||
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;
|
||||
}
|
||||
}
|
||||
StoredObject(sol::object) noexcept;
|
||||
StoredObject(sol::stack_object) noexcept;
|
||||
|
||||
operator bool() const noexcept;
|
||||
std::size_t hash() const noexcept;
|
||||
@ -147,6 +67,7 @@ private:
|
||||
|
||||
namespace std {
|
||||
|
||||
// For storing as key in std::unordered_map
|
||||
template<>
|
||||
struct hash<share_data::StoredObject> {
|
||||
std::size_t operator()(const share_data::StoredObject &object) const noexcept {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
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
|
||||
sol::state_view lua(function.lua_state());
|
||||
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::package, sol::lib::io, sol::lib::os
|
||||
);
|
||||
get_user_type(*p_state_);
|
||||
share_data::SharedTable::get_user_type(*p_state_);
|
||||
getUserType(*p_state_);
|
||||
share_data::SharedTable::getUserType(*p_state_);
|
||||
|
||||
// 3. Save parameters
|
||||
store_args(args);
|
||||
storeArgs(args);
|
||||
|
||||
// 4. Run thread
|
||||
p_thread_.reset(new std::thread(&LuaThread::work, this));
|
||||
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>>();
|
||||
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>());
|
||||
p_arguments_->push_back(store.unpack(sol::this_state{p_state_->lua_state()}));
|
||||
}
|
||||
}
|
||||
|
||||
void LuaThread::join() noexcept
|
||||
{
|
||||
if (p_thread_.get())
|
||||
{
|
||||
void LuaThread::join() noexcept {
|
||||
if (p_thread_.get()) {
|
||||
p_thread_->join();
|
||||
p_thread_.reset();
|
||||
}
|
||||
@ -48,44 +44,38 @@ void LuaThread::join() noexcept
|
||||
p_state_.reset();
|
||||
}
|
||||
|
||||
void LuaThread::detach() noexcept
|
||||
{
|
||||
void LuaThread::detach() noexcept {
|
||||
p_thread_->detach();
|
||||
}
|
||||
|
||||
void LuaThread::work() noexcept
|
||||
{
|
||||
if (p_state_.get() && p_arguments_.get())
|
||||
{
|
||||
void LuaThread::work() noexcept {
|
||||
if (p_state_.get() && p_arguments_.get()) {
|
||||
std::string func_owner = std::move(str_function_);
|
||||
std::shared_ptr<sol::state> state_owner = p_state_;
|
||||
std::shared_ptr<std::vector<sol::object>> arguments_owner = p_arguments_;
|
||||
sol::function_result func = (*state_owner)["loadstring"](func_owner);
|
||||
func.get<sol::function>()(sol::as_args(*arguments_owner));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw sol::error("Internal error: invalid thread Lua state");
|
||||
}
|
||||
}
|
||||
|
||||
std::string LuaThread::thread_id() noexcept
|
||||
{
|
||||
std::string LuaThread::threadId() noexcept {
|
||||
std::stringstream ss;
|
||||
ss << std::this_thread::get_id();
|
||||
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(
|
||||
sol::call_construction(), sol::constructors<sol::types<sol::function, sol::variadic_args>>(),
|
||||
"join", &LuaThread::join,
|
||||
"detach", &LuaThread::detach,
|
||||
"thread_id", &LuaThread::thread_id
|
||||
"thread_id", &LuaThread::threadId
|
||||
);
|
||||
sol::stack::push(lua, type);
|
||||
return sol::stack::pop<sol::object>(lua);
|
||||
}
|
||||
|
||||
}
|
||||
} // threading
|
||||
|
||||
@ -10,20 +10,19 @@
|
||||
|
||||
namespace threading {
|
||||
|
||||
class LuaThread
|
||||
{
|
||||
class LuaThread {
|
||||
public:
|
||||
LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept;
|
||||
virtual ~LuaThread() noexcept = default;
|
||||
void join() noexcept;
|
||||
void detach() noexcept;
|
||||
|
||||
static std::string thread_id() noexcept;
|
||||
static sol::object get_user_type(sol::state_view& lua) noexcept;
|
||||
static std::string threadId() noexcept;
|
||||
static sol::object getUserType(sol::state_view &lua) noexcept;
|
||||
|
||||
private:
|
||||
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::shared_ptr<sol::state> p_state_;
|
||||
@ -31,4 +30,4 @@ private:
|
||||
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"
|
||||
|
||||
using namespace core;
|
||||
#include <thread>
|
||||
|
||||
using namespace share_data;
|
||||
|
||||
namespace {
|
||||
|
||||
void bootstrapState(sol::state& lua) {
|
||||
lua.open_libraries(
|
||||
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;
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
@ -30,10 +33,8 @@ st.thr = true
|
||||
st.del = "secret"
|
||||
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"]["snd"], (double)2);
|
||||
ASSERT_EQ(lua["st"]["thr"], true);
|
||||
@ -48,10 +49,8 @@ st[42] = "answer"
|
||||
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"][2], std::string("number"));
|
||||
ASSERT_EQ(lua["st"][-1], false);
|
||||
@ -61,34 +60,13 @@ st.deleted = st[42] == nil
|
||||
st[true] = false
|
||||
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"][false], 9);
|
||||
}
|
||||
|
||||
TEST(sharedTable, asGlobalTable) {
|
||||
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) {
|
||||
TEST(sharedTable, multipleStates) {
|
||||
sol::state lua1, lua2;
|
||||
bootstrapState(lua1);
|
||||
bootstrapState(lua2);
|
||||
@ -153,7 +131,7 @@ st.thr = true)");
|
||||
ASSERT_EQ(lua["st"]["thr"], true);
|
||||
}
|
||||
|
||||
TEST(sharedTable, nestedTables) {
|
||||
TEST(sharedTable, playingWithSharedTables) {
|
||||
SharedTable recursive, st1, st2;
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
@ -204,3 +182,96 @@ end
|
||||
|
||||
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