Program Listing for File sharedstate.cpp¶
↰ Return to documentation for file (falcon/sharedstate.cpp
)
// ---------------------------------------------------------------------
// This file is part of falcon-core.
//
// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
//
// Falcon-server is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Falcon-server is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------
#include "sharedstate.hpp"
#include <string>
#include <vector>
Permission permission_from_string(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
if (s == "none") {
return Permission::NONE;
} else if (s == "read") {
return Permission::READ;
} else if (s == "write") {
return Permission::WRITE;
} else {
throw std::runtime_error("Unknown permission value.");
}
}
std::string permission_to_string(Permission p, bool shorthand) {
std::string s;
if (shorthand) {
if (p == Permission::READ) {
s = "read";
} else if (p == Permission::WRITE) {
s = "write";
} else {
s = "none";
}
} else {
if (p == Permission::READ) {
s = "R";
} else if (p == Permission::WRITE) {
s = "W";
} else {
s = "N";
}
}
return s;
}
Permissions::Permissions(Permission self, Permission others,
Permission external)
: self_(self), others_(others), external_(external) {}
const Permission Permissions::self() const { return self_; }
const Permission Permissions::others() const { return others_; }
const Permission Permissions::external() const { return external_; }
void Permissions::set_self(const Permission p) { self_ = p; }
void Permissions::set_others(const Permission p) { others_ = p; }
void Permissions::set_external(const Permission p) { external_ = p; }
std::string Permissions::to_string(bool shorthand) const {
std::string s;
std::string delimiter = "";
if (!shorthand) {
delimiter = "|";
}
s += permission_to_string(self_) + delimiter;
s += permission_to_string(others_) + delimiter;
s += permission_to_string(external_);
return s;
}
bool Permissions::IsCompatible(const Permissions &p) {
return !(others_ == Permission::NONE || p.others() == Permission::NONE ||
(others_ == Permission::READ && p.self() != Permission::READ) ||
(self_ != Permission::READ && p.others() == Permission::READ));
}
IState::IState(const Permissions &permissions, std::string description)
: permissions_(permissions), description_(description), shared_(false),
external_permission_(
std::make_shared<ExternalPermissionTracker>(permissions.external())) {
}
IState::IState(const IState &other)
: IState(other.permissions_, other.description_) {}
bool IState::IsCompatible(const Permissions &permissions) {
return this->permissions_.IsCompatible(permissions);
}
const Permissions &IState::permissions() const {
return permissions_;
} // read-only
Permission IState::external_permission() {
return external_permission_->permission();
}
std::string IState::description() { return description_; }
bool IState::IsShared() { return shared_; }
void IState::set_description(std::string value) { description_ = value; }
void IState::set_external_permission(Permission permission) {
external_permission_->add(permission);
external_permission_->subtract(permissions_.external());
permissions_.set_external(permission);
}
void IState::lock() {
while (lock_.test_and_set(std::memory_order_acquire)) {}
}
void IState::unlock() { lock_.clear(std::memory_order_release); }
SharedStateAlias::SharedStateAlias(Permission external, std::string description)
: external_(external), description_(description) {}
SharedStateAlias::~SharedStateAlias() { RemoveAllStates(); }
void SharedStateAlias::AddState(std::string name,
const std::shared_ptr<IState> &dependent) {
// already part of group
if (dependents_.count(name)) {
return;
}
// check for compatibility against existing dependents
for (auto const &state : dependents_) {
if (!dependent->IsLikeMe(state.second) ||
!dependent->IsCompatible(state.second->permissions())) {
throw std::runtime_error("New state \"" + name + "\" (" +
state.second->permissions().to_string() +
") is not compatible with existing state (" +
dependent->permissions().to_string() + ")");
}
}
if (dependents_.size() == 0) {
// create master state
master_ = std::shared_ptr<IState>(dependent->clone());
master_->set_external_permission(external_);
}
dependent->Share(master_);
dependents_[name] = dependent;
}
void SharedStateAlias::RemoveState(std::string name) {
if (dependents_.count(name)) {
dependents_[name]->UnShare();
dependents_.erase(name);
}
if (dependents_.size() == 0) {
master_.reset();
}
}
void SharedStateAlias::RemoveAllStates() {
for (auto const &state : dependents_) {
state.second->UnShare();
}
dependents_.clear();
master_.reset();
}
bool SharedStateAlias::Update(std::string value) {
if (!master_) {
throw std::runtime_error("Alias is not linked to states.");
}
return master_->set_string(value);
}
std::string SharedStateAlias::Retrieve() {
if (!master_) {
throw std::runtime_error("Alias is not linked to states.");
}
return master_->get_string();
}
YAML::Node SharedStateAlias::ExportYAML() {
YAML::Node alias_description;
for (auto &it : dependents_) {
alias_description["states"].push_back(it.first);
}
if (external_ == Permission::READ || external_ == Permission::WRITE) {
alias_description["value"] = Retrieve();
}
alias_description["description"] = description_;
return alias_description;
}
SharedStateMap::~SharedStateMap() { clear(); }
void SharedStateMap::AddAlias(std::string alias, Permission permission,
std::string description) {
if (aliases_.count(alias)) {
throw std::runtime_error("Shared state alias already exists.");
}
aliases_.emplace(std::piecewise_construct, std::make_tuple(alias),
std::make_tuple(permission, description));
}
void SharedStateMap::RemoveAlias(std::string alias) { aliases_.erase(alias); }
void SharedStateMap::ShareState(std::string alias, std::string name,
std::shared_ptr<IState> state) {
if (aliases_.count(alias) == 0) {
throw std::runtime_error("Group does not exist.");
}
// if state already linked, unlink first
if (IsShared(name)) {
if (shared_states_[name] == alias) {
return;
} else {
UnShareState(name);
}
}
// try add state to group
aliases_[alias].AddState(name, state);
shared_states_[name] = alias;
}
void SharedStateMap::UnShareState(std::string name) {
if (IsShared(name)) {
aliases_[shared_states_[name]].RemoveState(name);
shared_states_.erase(name);
}
}
void SharedStateMap::UnShareAll() {
for (auto const &state : shared_states_) {
aliases_[state.second].RemoveState(state.first);
}
shared_states_.clear();
}
void SharedStateMap::clear() {
UnShareAll();
aliases_.clear();
}
bool SharedStateMap::IsShared(std::string name) {
return (shared_states_.count(name) == 1);
}
std::vector<std::string> SharedStateMap::ListSharedStates(std::string alias) {
std::vector<std::string> state_list;
for (auto const &imap : shared_states_) {
state_list.push_back(imap.first);
}
return state_list;
}
bool SharedStateMap::UpdateAlias(std::string alias, std::string value) {
if (aliases_.count(alias) == 0) {
throw std::runtime_error("No alias named " + alias);
}
return aliases_[alias].Update(value);
}
std::string SharedStateMap::RetrieveAlias(std::string alias) {
if (aliases_.count(alias) == 0) {
throw std::runtime_error("No alias named " + alias);
}
return aliases_[alias].Retrieve();
}
YAML::Node SharedStateMap::ExportYAML() {
YAML::Node node;
for (auto &it : this->aliases_) {
node[it.first] = it.second.ExportYAML();
}
return node;
}