65class ExternalPermissionTracker {
67 ExternalPermissionTracker() : none_(0), read_(0), write_(0) {}
68 ExternalPermissionTracker(Permission permission) : ExternalPermissionTracker() {
72 Permission permission() {
73 if (none_.load() > 0) {
74 return Permission::NONE;
76 if (read_.load() > 0) {
77 return Permission::READ;
79 if (write_.load() > 0) {
80 return Permission::WRITE;
82 return Permission::NONE;
85 void add(Permission permission) {
86 if (permission == Permission::NONE) {
88 }
else if (permission == Permission::READ) {
90 }
else if (permission == Permission::WRITE) {
95 void subtract(Permission permission) {
96 if (permission == Permission::NONE) {
98 }
else if (permission == Permission::READ) {
100 }
else if (permission == Permission::WRITE) {
106 std::atomic<int> none_;
107 std::atomic<int> read_;
108 std::atomic<int> write_;
139 friend class SharedStateAlias;
143 IState(
const Permissions& permissions,
const std::string& description =
"");
144 IState(
const IState& other);
146 virtual IState* clone()
const = 0;
150 Permission external_permission();
152 std::string description();
153 virtual std::string get_string(
bool cache =
true) = 0;
156 virtual bool IsLikeMe(
const std::shared_ptr<IState>& other) = 0;
158 virtual void Share(
const std::shared_ptr<IState>& other) = 0;
159 virtual void UnShare() = 0;
161 virtual bool IsShared();
163 void set_description(
const std::string& value);
165 virtual bool set_string(
const std::string& value,
bool cache =
true) = 0;
167 void set_external_permission(Permission permission);
175 std::string description_;
177 std::shared_ptr<ExternalPermissionTracker> external_permission_;
180 std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
194 ReadableState(T default_value, std::string description =
"",
195 Permission peers = Permission::WRITE, Permission external = Permission::NONE)
198 default_(default_value),
199 cache_(default_value),
200 state_(std::make_shared<std::atomic<T>>(default_value)) {}
202 ReadableState(
const ReadableState& other)
204 default_(other.default_),
205 cache_(other.cache_),
206 state_(std::make_shared<std::atomic<T>>(other.state_->load())) {
211 T get(
bool cache =
true) {
214 val = state_->load();
223 bool changed_get(T& val,
bool cache =
true) {
226 val = state_->load();
236 std::string get_string(
bool cache =
true)
override {
237 if constexpr (std::is_convertible_v<T, std::string>) {
238 T value = get(cache);
239 if (std::is_same_v<T, bool>) {
240 return value ?
"true" :
"false";
242 return std::to_string(value);
244 throw std::runtime_error(
245 "This state should not have external permission to be read "
246 "because it cannot be serialized via string transformation.");
250 void set(T value,
bool cache =
true) {
252 state_->store(value);
259 T exchange(T value,
bool cache =
true) {
261 value = state_->exchange(value);
270 bool set_string(
const std::string& value,
bool cache =
true)
override {
271 if constexpr (std::is_convertible_v<T, std::string>) {
272 std::stringstream ss(value);
274 if ((std::is_same_v<T, bool> and ss >> std::boolalpha >> result) or ss >> result) {
282 void reset() { set(default_); }
284 void Share(
const std::shared_ptr<IState>& other)
override {
285 if (other.get() ==
this) {
289 auto cast =
dynamic_cast<ReadableState<T>*
>(other.get());
292 this->state_ = cast->state_;
293 this->external_permission_ = cast->external_permission_;
294 this->external_permission_->add(this->permissions_.external());
295 this->shared_ =
true;
298 throw std::runtime_error(
"Cannot delegate to incompatible state.");
302 void UnShare()
override {
304 this->state_ = std::make_shared<std::atomic<T>>(this->state_->load());
305 this->external_permission_->subtract(this->permissions_.external());
306 this->external_permission_ =
307 std::make_shared<ExternalPermissionTracker>(this->permissions_.external());
308 this->shared_ =
false;
312 bool IsLikeMe(
const std::shared_ptr<IState>& other)
override {
314 auto cast =
dynamic_cast<const ReadableState<T>*
>(other.get());
320 }
catch (
const std::bad_cast& e) {
328 std::shared_ptr<std::atomic<T>> state_;
332class WritableState :
public ReadableState<T> {
334 WritableState(T default_value, std::string description =
"",
335 Permission peers = Permission::READ, Permission external = Permission::NONE)
336 : ReadableState<T>(default_value, description, peers, external) {
337 this->permissions_.set_self(Permission::WRITE);
341 void set(T value,
bool cache =
true) { ReadableState<T>::set(value, cache); }
342 T exchange(T value,
bool cache =
true) {
return ReadableState<T>::exchange(value, cache); }
343 bool set_string(
const std::string& value,
bool cache =
true)
override {
344 return ReadableState<T>::set_string(value, cache);
346 void reset() { ReadableState<T>::reset(); }
349class SharedStateAlias {
351 SharedStateAlias(Permission external = Permission::WRITE,
const std::string& description =
"");
353 void AddState(
const std::string& name,
const std::shared_ptr<IState>& dependent);
354 void RemoveState(
const std::string& name);
355 void RemoveAllStates();
356 bool Update(
const std::string& value);
357 std::string Retrieve();
358 YAML::Node ExportYAML();
361 Permission external_;
362 std::string description_;
363 std::shared_ptr<IState> master_;
364 std::map<std::string, std::shared_ptr<IState>> dependents_;
376class SharedStateMap {
380 void AddAlias(
const std::string& alias, Permission permission = Permission::WRITE,
381 const std::string& description =
"");
382 void RemoveAlias(
const std::string& alias);
383 void ShareState(
const std::string& alias,
const std::string& name,
384 const std::shared_ptr<IState>& state);
385 void UnShareState(
const std::string& name);
388 bool IsShared(
const std::string& name);
389 std::vector<std::string> ListSharedStates(
const std::string& alias);
390 bool UpdateAlias(
const std::string& alias,
const std::string& value);
391 std::string RetrieveAlias(
const std::string& alias);
392 YAML::Node ExportYAML();
395 std::map<std::string, SharedStateAlias> aliases_;
396 std::map<std::string, std::string> shared_states_;