$darkmode
time_event.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
24 #pragma once
25 
26 #include <chrono> // for duration_cast<>
27 #include <memory> // for unique_ptr<>, make_unique<>
28 #include <queue> // for priority_queue<>
29 
30 #include <cloe/core.hpp> // for Json, Duration, Seconds
31 #include <cloe/sync.hpp> // for Sync
32 #include <cloe/trigger.hpp> // for Trigger, Event, EventFactory, ...
33 
34 namespace engine {
35 namespace events {
36 
37 class NextCallback;
38 
39 class TimeEvent : public cloe::Event {
40  public:
41  TimeEvent(const std::string& name, cloe::Duration t) : Event(name), time_(t) {}
42  cloe::Duration time() const { return time_; }
43  cloe::EventPtr clone() const override { return std::make_unique<TimeEvent>(name(), time_); }
44  void to_json(cloe::Json& j) const override {
45  j = cloe::Json{
46  {"time", cloe::Seconds{time_}.count()},
47  };
48  }
49 
50  private:
51  friend NextCallback;
52 
53  private:
54  cloe::Duration time_;
55 };
56 
58  public:
59  TimeFactory() : cloe::EventFactory("time", "at simulation time") {}
60 
61  cloe::TriggerSchema schema() const override {
62  using namespace cloe::schema; // NOLINT(build/namespaces)
63  static const char* desc = "absolute number of seconds in simulation time";
64  return cloe::TriggerSchema{
65  this->name(),
66  this->description(),
67  cloe::InlineSchema(desc, cloe::Json::value_t::number_float),
69  {"time", Number<double>(nullptr, desc).require()},
70  },
71  };
72  }
73 
74  cloe::EventPtr make(const cloe::Conf& c) const override {
75  auto secs = cloe::Seconds{c.get<double>("time")};
76  return std::make_unique<TimeEvent>(name(), std::chrono::duration_cast<cloe::Duration>(secs));
77  }
78 
79  cloe::EventPtr make(const std::string& s) const override {
80  return make(cloe::Conf{cloe::Json{
81  {"time", std::stod(s)},
82  }});
83  }
84 };
85 
86 struct TimeTrigger {
87  TimeTrigger(cloe::Duration t, cloe::TriggerPtr&& tp) : time(t), trigger(std::move(tp)) {}
88 
89  friend void to_json(cloe::Json& j, const TimeTrigger& t) { j = t.trigger; }
90 
91  public:
92  cloe::Duration time;
93  cloe::TriggerPtr trigger;
94 };
95 
96 using TimeEmplaceHook = std::function<void(const cloe::Trigger&, cloe::Duration)>;
97 
98 class TimeCallback : public cloe::Callback {
99  public:
100  TimeCallback(cloe::Logger log, TimeEmplaceHook h) : log_(log), hook_(h) {}
101 
102  void emplace(cloe::TriggerPtr&& t, const cloe::Sync& sync) override {
103  auto now = sync.time();
104  auto when = dynamic_cast<const TimeEvent&>(t->event()).time();
105  hook_(*t, when);
106  if (when < now) {
107  log_->error("Inserting timed trigger for the past!");
108  log_->error("> trigger time = {} s", std::chrono::duration_cast<cloe::Seconds>(when).count());
109  log_->error("> current time = {} s", std::chrono::duration_cast<cloe::Seconds>(now).count());
110  }
111  if (t->is_sticky()) {
112  log_->error("Inserting timed trigger that is sticky discards stickiness!");
113  }
114  storage_.emplace(std::make_shared<TimeTrigger>(when, std::move(t)));
115  }
116 
117  void to_json(cloe::Json& j) const override {
118  // Make a copy of the storage, and then empty it.
119  decltype(storage_) st_copy{storage_};
120  while (!st_copy.empty()) {
121  j.push_back(st_copy.top());
122  st_copy.pop();
123  }
124  }
125 
126  void trigger(const cloe::Sync& sync) {
127  auto now = sync.time();
128  while (!storage_.empty() && storage_.top()->time <= now) {
129  auto tt = storage_.top();
130  storage_.pop();
131  this->execute(std::move(tt->trigger), sync);
132  }
133  }
134 
135  private:
136  cloe::Logger log_;
137  TimeEmplaceHook hook_;
138 
139  // This is ridiculous: We need to wrap the unique_ptr of Trigger in
140  // a shared_ptr because you can only get objects by copy out of
141  // a priority_queue.
142  std::priority_queue<
143  std::shared_ptr<TimeTrigger>, std::vector<std::shared_ptr<TimeTrigger>>,
144  std::function<bool(const std::shared_ptr<TimeTrigger>&, const std::shared_ptr<TimeTrigger>&)>>
145  storage_{[](const std::shared_ptr<TimeTrigger>& x,
146  const std::shared_ptr<TimeTrigger>& y) -> bool { return x->time > y->time; }};
147 };
148 
150  public:
151  NextFactory() : cloe::EventFactory("next", "next step in simulation") {}
152 
153  cloe::TriggerSchema schema() const override {
154  using namespace cloe::schema; // NOLINT(build/namespaces)
155  static const char* desc = "optional number of seconds from current simulation time";
156  return cloe::TriggerSchema{
157  name(),
158  description(),
159  cloe::InlineSchema(desc, cloe::Json::value_t::number_float, false),
160  cloe::Schema{
161  {"time", Number<double>(nullptr, desc)},
162  },
163  };
164  }
165 
166  std::unique_ptr<cloe::Event> make(const cloe::Conf& c) const override {
167  auto next_time = cloe::Duration{0};
168  if (c.has("time")) {
169  auto secs = cloe::Seconds{c.get<double>("time")};
170  next_time += std::chrono::duration_cast<cloe::Duration>(secs);
171  }
172  return std::make_unique<TimeEvent>(name(), next_time);
173  }
174 
175  std::unique_ptr<cloe::Event> make(const std::string& s) const override {
176  if (!s.empty()) {
177  return make(cloe::Conf{cloe::Json{
178  {"time", std::stod(s)},
179  }});
180  }
181  return make(cloe::Conf{});
182  }
183 };
184 
186  public:
187  using cloe::AliasCallback::AliasCallback;
188  void emplace(cloe::TriggerPtr&& t, const cloe::Sync& s) override {
189  auto& time_event = const_cast<TimeEvent&>(dynamic_cast<const TimeEvent&>(t->event()));
190  time_event.set_name("time");
191  time_event.time_ += s.time();
192  cloe::AliasCallback::emplace(std::move(t), s);
193  }
194 };
195 
196 } // namespace events
197 } // namespace engine
Definition: trigger.hpp:570
void emplace(TriggerPtr &&t, const Sync &s) override
Definition: trigger.hpp:578
Definition: trigger.hpp:533
friend void to_json(fable::Json &j, const Entity &e)
Definition: entity.hpp:120
void set_name(std::string name)
Definition: entity.cpp:30
const std::string & description() const
Definition: entity.hpp:90
const std::string & name() const
Definition: entity.hpp:67
Definition: trigger.hpp:478
Definition: sync.hpp:34
virtual Duration time() const =0
Definition: trigger.hpp:290
Definition: trigger.hpp:396
Definition: time_event.hpp:185
void emplace(cloe::TriggerPtr &&t, const cloe::Sync &s) override
Definition: time_event.hpp:188
Definition: time_event.hpp:149
std::unique_ptr< cloe::Event > make(const cloe::Conf &c) const override
Definition: time_event.hpp:166
std::unique_ptr< cloe::Event > make(const std::string &s) const override
Definition: time_event.hpp:175
cloe::TriggerSchema schema() const override
Definition: time_event.hpp:153
Definition: time_event.hpp:98
void emplace(cloe::TriggerPtr &&t, const cloe::Sync &sync) override
Definition: time_event.hpp:102
Definition: time_event.hpp:39
cloe::EventPtr clone() const override
Definition: time_event.hpp:43
Definition: time_event.hpp:57
cloe::EventPtr make(const cloe::Conf &c) const override
Definition: time_event.hpp:74
cloe::EventPtr make(const std::string &s) const override
Definition: time_event.hpp:79
cloe::TriggerSchema schema() const override
Definition: time_event.hpp:61
Definition: conf.hpp:82
bool has(const std::string &key) const
Definition: conf.hpp:166
T get() const
Definition: conf.hpp:298
Definition: schema.hpp:173
Definition: number.hpp:36
std::chrono::nanoseconds Duration
Definition: cloe_fwd.hpp:36
Definition: trigger.hpp:87
Definition: trigger.hpp:207
Definition: time_event.hpp:86