Program Listing for File reaction.cc

Return to documentation for file (lib/reaction.cc)

/*
 * Copyright (C) 2019 TU Dresden
 * All rights reserved.
 *
 * Authors:
 *   Christian Menard
 */

#include <utility>

#include "reactor-cpp/reaction.hh"

#include "reactor-cpp/action.hh"
#include "reactor-cpp/assert.hh"
#include "reactor-cpp/environment.hh"
#include "reactor-cpp/port.hh"

namespace reactor {

Reaction::Reaction(const std::string& name, int priority, Reactor* container, std::function<void(void)> body)
    : ReactorElement(name, ReactorElement::Type::Reaction, container)
    , priority_(priority)
    , body_(std::move(std::move(body))) {
  reactor_assert(priority != 0);
}

void Reaction::declare_trigger(BaseAction* action) {
  reactor_assert(action != nullptr);
  reactor_assert(this->environment() == action->environment());
  assert_phase(this, Environment::Phase::Assembly);
  validate(this->container() == action->container(), "Action triggers must belong to the same reactor as the triggered "
                                                     "reaction");

  reactor_assert(action_triggers_.insert(action).second);
  action->register_trigger(this);
}

void Reaction::declare_schedulable_action(BaseAction* action) {
  reactor_assert(action != nullptr);
  reactor_assert(this->environment() == action->environment());
  assert_phase(this, Environment::Phase::Assembly);
  validate(this->container() == action->container(), "Scheduable actions must belong to the same reactor as the "
                                                     "triggered reaction");

  reactor_assert(scheduable_actions_.insert(action).second);
  action->register_scheduler(this);
}

void Reaction::declare_trigger(BasePort* port) {
  reactor_assert(port != nullptr);
  reactor_assert(this->environment() == port->environment());
  reactor_assert(this->environment()->phase() == Environment::Phase::Assembly);
  assert_phase(this, Environment::Phase::Assembly);

  if (port->is_input()) {
    validate(this->container() == port->container(),
             "Input port triggers must belong to the same reactor as the triggered "
             "reaction");
  } else {
    validate(this->container() == port->container()->container(),
             "Output port triggers must belong to a contained reactor");
  }

  reactor_assert(port_trigger_.insert(port).second);
  reactor_assert(dependencies_.insert(port).second);
  port->register_dependency(this, true);
}

void Reaction::declare_dependency(BasePort* port) {
  reactor_assert(port != nullptr);
  reactor_assert(this->environment() == port->environment());
  assert_phase(this, Environment::Phase::Assembly);

  if (port->is_input()) {
    validate(this->container() == port->container(), "Dependent input ports must belong to the same reactor as the "
                                                     "reaction");
  } else {
    validate(this->container() == port->container()->container(),
             "Dependent output ports must belong to a contained reactor");
  }

  reactor_assert(dependencies_.insert(port).second);
  port->register_dependency(this, false);
}

void Reaction::declare_antidependency(BasePort* port) {
  reactor_assert(port != nullptr);
  reactor_assert(this->environment() == port->environment());
  assert_phase(this, Environment::Phase::Assembly);

  if (port->is_output()) {
    validate(this->container() == port->container(), "Antidependent output ports must belong to the same reactor as "
                                                     "the reaction");
  } else {
    validate(this->container() == port->container()->container(),
             "Antidependent input ports must belong to a contained reactor");
  }

  reactor_assert(antidependencies_.insert(port).second);
  port->register_antidependency(this);
}

void Reaction::trigger() {
  if (has_deadline()) {
    reactor_assert(deadline_handler_ != nullptr);
    auto lag = Reactor::get_physical_time() - container()->get_logical_time();
    if (lag > deadline_) {
      deadline_handler_();
      return;
    }
  }

  body_();
}

void Reaction::set_deadline_impl(Duration deadline, const std::function<void(void)>& handler) {
  reactor_assert(!has_deadline());
  reactor_assert(handler != nullptr);
  this->deadline_ = deadline;
  this->deadline_handler_ = handler;
}

void Reaction::set_index(unsigned index) {
  validate(this->environment()->phase() == Environment::Phase::Assembly,
           "Reaction indexes may only be set during assembly phase!");
  this->index_ = index;
}

} // namespace reactor