Merge branch 'master' into clang-format
This commit is contained in:
commit
24d0678ccf
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 mihacooper
|
Copyright (c) 2017 Mikhail Kupriyanov <mihakuper@gmail.com>, Ilia Udalov <UdalovIlia@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@ -22,7 +22,9 @@ sol::object SharedTable::getUserType(sol::state_view &lua) {
|
|||||||
"new", sol::no_constructor, //
|
"new", sol::no_constructor, //
|
||||||
sol::meta_function::new_index, &SharedTable::luaSet,//
|
sol::meta_function::new_index, &SharedTable::luaSet,//
|
||||||
sol::meta_function::index, &SharedTable::luaGet,//
|
sol::meta_function::index, &SharedTable::luaGet,//
|
||||||
sol::meta_function::length, &SharedTable::size //
|
sol::meta_function::length, &SharedTable::length,//
|
||||||
|
"__pairs", &SharedTable::pairs, //
|
||||||
|
"__ipairs", &SharedTable::ipairs //
|
||||||
);
|
);
|
||||||
sol::stack::push(lua, type);
|
sol::stack::push(lua, type);
|
||||||
return sol::stack::pop<sol::object>(lua);
|
return sol::stack::pop<sol::object>(lua);
|
||||||
@ -37,6 +39,16 @@ void SharedTable::set(StoredObject&& key, StoredObject&& value) {
|
|||||||
data_->entries[std::move(key)] = std::move(value);
|
data_->entries[std::move(key)] = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sol::object SharedTable::get(const StoredObject& key, const sol::this_state& state) const {
|
||||||
|
std::lock_guard<SpinMutex> g(data_->lock);
|
||||||
|
auto val = data_->entries.find(key);
|
||||||
|
if (val == data_->entries.end()) {
|
||||||
|
return sol::nil;
|
||||||
|
} else {
|
||||||
|
return val->second->unpack(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue) {
|
void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue) {
|
||||||
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
||||||
|
|
||||||
@ -59,15 +71,8 @@ void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_objec
|
|||||||
|
|
||||||
sol::object SharedTable::luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const {
|
sol::object SharedTable::luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const {
|
||||||
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
||||||
|
|
||||||
StoredObject key = createStoredObject(luaKey);
|
StoredObject key = createStoredObject(luaKey);
|
||||||
std::lock_guard<SpinMutex> g(data_->lock);
|
return get(key, state);
|
||||||
auto val = data_->entries.find(key);
|
|
||||||
if (val == data_->entries.end()) {
|
|
||||||
return sol::nil;
|
|
||||||
} else {
|
|
||||||
return val->second->unpack(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SharedTable::size() const {
|
size_t SharedTable::size() const {
|
||||||
@ -75,4 +80,62 @@ size_t SharedTable::size() const {
|
|||||||
return data_->entries.size();
|
return data_->entries.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t SharedTable::length() const {
|
||||||
|
std::lock_guard<SpinMutex> g(data_->lock);
|
||||||
|
size_t len = 0u;
|
||||||
|
sol::optional<double> value;
|
||||||
|
auto iter = data_->entries.find(createStoredObject(static_cast<double>(1)));
|
||||||
|
if (iter != data_->entries.end())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++len;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
while ((iter != data_->entries.end()) && (value = storedObjectToDouble(iter->first)) && (static_cast<size_t>(value.value()) == len + 1));
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedTable::PairsIterator SharedTable::getNext(const sol::object& key, sol::this_state lua) {
|
||||||
|
std::lock_guard<SpinMutex> g(data_->lock);
|
||||||
|
if (key) {
|
||||||
|
auto obj = createStoredObject(key);
|
||||||
|
auto upper = data_->entries.upper_bound(obj);
|
||||||
|
if (upper != data_->entries.end())
|
||||||
|
return std::tuple<sol::object, sol::object>(upper->first->unpack(lua), upper->second->unpack(lua));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!data_->entries.empty()) {
|
||||||
|
const auto& begin = data_->entries.begin();
|
||||||
|
return std::tuple<sol::object, sol::object>(begin->first->unpack(lua), begin->second->unpack(lua));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::tuple<sol::object, sol::object>(sol::nil, sol::nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedTable::PairsIterator SharedTable::pairs(sol::this_state lua) const {
|
||||||
|
auto next = [](sol::this_state lua, SharedTable table, sol::stack_object key){ return table.getNext(key, lua); };
|
||||||
|
return std::tuple<sol::function, sol::object>(
|
||||||
|
sol::make_object(lua, std::function<PairsIterator(sol::this_state lua, SharedTable table, sol::stack_object key)>(next)).as<sol::function>(),
|
||||||
|
sol::make_object(lua, *this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<sol::object, sol::object> ipairsNext(sol::this_state lua, SharedTable table, sol::optional<unsigned long> key) {
|
||||||
|
size_t index = key ? key.value() + 1 : 1;
|
||||||
|
auto objKey = createStoredObject(static_cast<double>(index));
|
||||||
|
sol::object value = table.get(objKey, lua);
|
||||||
|
if (!value.valid())
|
||||||
|
return std::tuple<sol::object, sol::object>(sol::nil, sol::nil);
|
||||||
|
return std::tuple<sol::object, sol::object>(objKey->unpack(lua), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<sol::function, sol::object> SharedTable::ipairs(sol::this_state lua) const {
|
||||||
|
return std::tuple<sol::function, sol::object>(
|
||||||
|
sol::make_object(lua, ipairsNext).as<sol::function>(),
|
||||||
|
sol::make_object(lua, *this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
} // effil
|
} // effil
|
||||||
|
|||||||
@ -12,6 +12,10 @@
|
|||||||
namespace effil {
|
namespace effil {
|
||||||
|
|
||||||
class SharedTable : public GCObject {
|
class SharedTable : public GCObject {
|
||||||
|
private:
|
||||||
|
typedef std::tuple<sol::function, sol::object> PairsIterator;
|
||||||
|
typedef std::map<StoredObject, StoredObject, StoredObjectLess> DataEntries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SharedTable();
|
SharedTable();
|
||||||
SharedTable(SharedTable&&) = default;
|
SharedTable(SharedTable&&) = default;
|
||||||
@ -20,20 +24,24 @@ public:
|
|||||||
|
|
||||||
static sol::object getUserType(sol::state_view &lua);
|
static sol::object getUserType(sol::state_view &lua);
|
||||||
void set(StoredObject&&, StoredObject&&);
|
void set(StoredObject&&, StoredObject&&);
|
||||||
|
sol::object get(const StoredObject& key, const sol::this_state& state) const;
|
||||||
|
PairsIterator getNext(const sol::object& key, sol::this_state lua);
|
||||||
|
|
||||||
// These functions could be invoked from lua scripts
|
// These functions could be invoked from lua scripts
|
||||||
void luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue);
|
void luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue);
|
||||||
sol::object luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const;
|
sol::object luaGet(const sol::stack_object& key, const sol::this_state& state) const;
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
size_t length() const;
|
||||||
|
PairsIterator pairs(sol::this_state) const;
|
||||||
|
PairsIterator ipairs(sol::this_state) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::unique_ptr<BaseHolder> StoredObject;
|
|
||||||
struct SharedData {
|
struct SharedData {
|
||||||
SpinMutex lock;
|
SpinMutex lock;
|
||||||
std::unordered_map<StoredObject, StoredObject, StoredObjectHash, StoredObjectEqual> entries;
|
DataEntries entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<SharedData> data_;
|
std::shared_ptr<SharedData> data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -26,17 +26,15 @@ public:
|
|||||||
: data_(init) {}
|
: data_(init) {}
|
||||||
|
|
||||||
bool rawCompare(const BaseHolder* other) const noexcept final {
|
bool rawCompare(const BaseHolder* other) const noexcept final {
|
||||||
return static_cast<const PrimitiveHolder<StoredType>*>(other)->data_ == data_;
|
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 final {
|
sol::object unpack(sol::this_state state) const final {
|
||||||
return sol::make_object(state, data_);
|
return sol::make_object(state, data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StoredType getData() { return data_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StoredType data_;
|
StoredType data_;
|
||||||
};
|
};
|
||||||
@ -52,11 +50,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool rawCompare(const BaseHolder* other) const noexcept final {
|
bool rawCompare(const BaseHolder* other) const noexcept final {
|
||||||
return static_cast<const FunctionHolder*>(other)->function_ == function_;
|
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 final {
|
sol::object unpack(sol::this_state state) const final {
|
||||||
@ -86,11 +80,7 @@ public:
|
|||||||
: handle_(handle) {}
|
: handle_(handle) {}
|
||||||
|
|
||||||
bool rawCompare(const BaseHolder *other) const final {
|
bool rawCompare(const BaseHolder *other) const final {
|
||||||
return static_cast<const TableHolder*>(other)->handle_ == handle_;
|
return handle_ < static_cast<const TableHolder*>(other)->handle_;
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t hash() const final {
|
|
||||||
return std::hash<GCObjectHandle>()(handle_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object unpack(sol::this_state state) const final {
|
sol::object unpack(sol::this_state state) const final {
|
||||||
@ -98,6 +88,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
GCObjectHandle gcHandle() const override { return handle_; }
|
GCObjectHandle gcHandle() const override { return handle_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GCObjectHandle handle_;
|
GCObjectHandle handle_;
|
||||||
};
|
};
|
||||||
@ -197,4 +188,24 @@ StoredObject createStoredObject(GCObjectHandle handle) {
|
|||||||
return std::make_unique<TableHolder>(handle);
|
return std::make_unique<TableHolder>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename DataType>
|
||||||
|
sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) {
|
||||||
|
auto ptr = dynamic_cast<PrimitiveHolder<DataType>*>(sobj.get());
|
||||||
|
if (ptr)
|
||||||
|
return ptr->getData();
|
||||||
|
return sol::optional<DataType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::optional<bool> storedObjectToBool(const StoredObject& sobj) {
|
||||||
|
return getPrimitiveHolderData<bool>(sobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::optional<double> storedObjectToDouble(const StoredObject& sobj) {
|
||||||
|
return getPrimitiveHolderData<double>(sobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::optional<std::string> storedObjectToString(const StoredObject& sobj) {
|
||||||
|
return getPrimitiveHolderData<std::string>(sobj);
|
||||||
|
}
|
||||||
|
|
||||||
} // effil
|
} // effil
|
||||||
|
|||||||
@ -12,14 +12,14 @@ public:
|
|||||||
virtual ~BaseHolder() = default;
|
virtual ~BaseHolder() = default;
|
||||||
|
|
||||||
bool compare(const BaseHolder* other) const {
|
bool compare(const BaseHolder* other) const {
|
||||||
return typeid(*this) == typeid(*other) && rawCompare(other);
|
if (typeid(*this) == typeid(*other))
|
||||||
|
return rawCompare(other);
|
||||||
|
return typeid(*this).before(typeid(*other));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool rawCompare(const BaseHolder* other) const = 0;
|
virtual bool rawCompare(const BaseHolder* other) const = 0;
|
||||||
virtual const std::type_info& type() { return typeid(*this); }
|
virtual const std::type_info& type() { return typeid(*this); }
|
||||||
|
|
||||||
virtual std::size_t hash() const = 0;
|
|
||||||
virtual sol::object unpack(sol::this_state state) const = 0;
|
virtual sol::object unpack(sol::this_state state) const = 0;
|
||||||
|
|
||||||
virtual GCObjectHandle gcHandle() const { return GCNull; }
|
virtual GCObjectHandle gcHandle() const { return GCNull; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -29,13 +29,7 @@ private:
|
|||||||
|
|
||||||
typedef std::unique_ptr<BaseHolder> StoredObject;
|
typedef std::unique_ptr<BaseHolder> StoredObject;
|
||||||
|
|
||||||
struct StoredObjectHash {
|
struct StoredObjectLess {
|
||||||
size_t operator()(const StoredObject& o) const {
|
|
||||||
return o->hash();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StoredObjectEqual {
|
|
||||||
bool operator()(const StoredObject& lhs, const StoredObject& rhs) const {
|
bool operator()(const StoredObject& lhs, const StoredObject& rhs) const {
|
||||||
return lhs->compare(rhs.get());
|
return lhs->compare(rhs.get());
|
||||||
}
|
}
|
||||||
@ -48,4 +42,8 @@ StoredObject createStoredObject(GCObjectHandle);
|
|||||||
StoredObject createStoredObject(const sol::object &);
|
StoredObject createStoredObject(const sol::object &);
|
||||||
StoredObject createStoredObject(const sol::stack_object &);
|
StoredObject createStoredObject(const sol::stack_object &);
|
||||||
|
|
||||||
|
sol::optional<bool> storedObjectToBool(const StoredObject&);
|
||||||
|
sol::optional<double> storedObjectToDouble(const StoredObject&);
|
||||||
|
sol::optional<std::string> storedObjectToString(const StoredObject&);
|
||||||
|
|
||||||
} // effil
|
} // effil
|
||||||
|
|||||||
@ -218,3 +218,50 @@ function TestSmoke:testCheckThreadReturns()
|
|||||||
test.assertEquals(returns[5](11, 89), 100)
|
test.assertEquals(returns[5](11, 89), 100)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function TestSmoke:testCheckPairsInterating()
|
||||||
|
local effil = require('libeffil')
|
||||||
|
local share = effil.share()
|
||||||
|
local data = { 0, 0, 0, ["key1"] = 0, ["key2"] = 0, ["key3"] = 0 }
|
||||||
|
|
||||||
|
for k, _ in pairs(data) do
|
||||||
|
share[k] = k .. "-value"
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in pairs(share) do
|
||||||
|
test.assertEquals(data[k], 0)
|
||||||
|
data[k] = 1
|
||||||
|
test.assertEquals(v, k .. "-value")
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in pairs(data) do
|
||||||
|
log("Check: " .. k)
|
||||||
|
test.assertEquals(v, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in ipairs(share) do
|
||||||
|
test.assertEquals(data[k], 1)
|
||||||
|
data[k] = 2
|
||||||
|
test.assertEquals(v, k .. "-value")
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in ipairs(data) do
|
||||||
|
log("Check: " .. k)
|
||||||
|
test.assertEquals(v, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TestSmoke:testCheckLengthOperator()
|
||||||
|
local effil = require('libeffil')
|
||||||
|
local share = effil.share()
|
||||||
|
share[1] = 10
|
||||||
|
share[2] = 20
|
||||||
|
share[3] = 30
|
||||||
|
share[4] = 40
|
||||||
|
share["str"] = 50
|
||||||
|
log "Check values"
|
||||||
|
test.assertEquals(#share, 4)
|
||||||
|
share[3] = nil
|
||||||
|
test.assertEquals(#share, 2)
|
||||||
|
share[1] = nil
|
||||||
|
test.assertEquals(#share, 0)
|
||||||
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user