effil/src/cpp/channel.cpp
mihacooper 5057116136 Channels implementation and tests (#42)
Channel implementation
2017-04-16 22:58:21 +03:00

69 lines
1.9 KiB
C++

#include "channel.h"
#include "sol.hpp"
namespace effil {
void Channel::getUserType(sol::state_view& lua) {
sol::usertype<Channel> type("new", sol::no_constructor,
"push", &Channel::push,
"pop", &Channel::pop
);
sol::stack::push(lua, type);
sol::stack::pop<sol::object>(lua);
}
Channel::Channel(sol::optional<int> capacity) : data_(std::make_shared<SharedData>()){
if (capacity) {
REQUIRE(capacity.value() >= 0) << "Invalid capacity value = " << capacity.value();
data_->capacity_ = static_cast<size_t>(capacity.value());
}
else {
data_->capacity_ = 0;
}
}
bool Channel::push(const sol::variadic_args& args) {
if (!args.leftover_count())
return false;
std::unique_lock<std::mutex> lock(data_->lock_);
if (data_->capacity_ && data_->channel_.size() >= data_->capacity_)
return false;
effil::StoredArray array;
for (const auto& arg : args) {
auto obj = createStoredObject(arg.get<sol::object>());
if (obj->gcHandle())
refs_->insert(obj->gcHandle());
array.emplace_back(obj);
}
if (data_->channel_.empty())
data_->cv_.notify_one();
data_->channel_.emplace(array);
return true;
}
StoredArray Channel::pop(const sol::optional<int>& duration,
const sol::optional<std::string>& period) {
std::unique_lock<std::mutex> lock(data_->lock_);
while (data_->channel_.empty()) {
if (duration) {
if (data_->cv_.wait_for(lock, fromLuaTime(duration.value(), period)) == std::cv_status::timeout)
return StoredArray();
}
else { // No time limit
data_->cv_.wait(lock);
}
}
auto ret = data_->channel_.front();
for (const auto& obj: ret) {
if (obj->gcHandle())
refs_->erase(obj->gcHandle());
}
data_->channel_.pop();
return ret;
}
} // namespace effil