tin  1.5.9
runtime.h
Go to the documentation of this file.
1 // Copyright (c) 2026 Tinverse LLC. All rights reserved.
2 // SPDX-License-Identifier: LicenseRef-Tinverse-Commercial
3 
19 
20 #pragma once
21 
22 #include <cstddef>
23 #include <tuple>
24 #include <type_traits>
25 #include <utility>
26 
27 #include "tsm.h"
28 #include "tsm/runtime/policy.h"
30 #include "tsm/runtime/transport.h"
31 
32 namespace tsm::runtime::detail {
33 
40 template<typename Definition>
41 struct default_machine_policy
42 {
44 };
45 
56 template<typename Overflow>
57 struct overflow_strategy;
58 
59 template<>
60 struct overflow_strategy<overflow::reject_newest>
61 {
62  template<typename Queue, typename Event>
63  [[nodiscard]] static bool push(Queue& queue, Event&& event)
64  {
65  return queue.try_push(std::forward<Event>(event));
66  }
67 };
68 
69 template<>
70 struct overflow_strategy<overflow::drop_oldest>
71 {
72  template<typename Queue, typename Event>
73  [[nodiscard]] static bool push(Queue& queue, Event&& event)
74  {
75  if (queue.try_push(std::forward<Event>(event))) {
76  return true;
77  }
78  typename Queue::value_type discarded{};
79  if (!queue.try_pop(discarded)) {
80  return false;
81  }
82  return queue.try_push(std::forward<Event>(event));
83  }
84 };
85 
86 template<>
87 struct overflow_strategy<overflow::overwrite_latest>
88 {
89  template<typename Queue, typename Event>
90  [[nodiscard]] static bool push(Queue& queue, Event&& event)
91  {
92  if (queue.try_push(std::forward<Event>(event))) {
93  return true;
94  }
95  return queue.try_overwrite_latest(std::forward<Event>(event));
96  }
97 };
98 
99 template<typename Definition,
100  typename Policy,
101  template<typename>
102  class MachinePolicy,
103  typename Topology = typename Policy::topology>
104 class runtime_impl;
105 
114 template<typename Definition,
115  typename Policy,
116  template<typename>
117  class MachinePolicy>
118 class runtime_impl<Definition, Policy, MachinePolicy, topology::direct_dispatch>
119 {
120  public:
121  using definition = Definition;
122  using policy = Policy;
123  using machine_type = typename MachinePolicy<Definition>::type;
124  using context_type = typename machine_type::context_type;
126 
127  [[nodiscard]] machine_type& machine() noexcept
128  {
129  return machine_;
130  }
131  [[nodiscard]] machine_type const& machine() const noexcept
132  {
133  return machine_;
134  }
135 
136  [[nodiscard]] context_type& context() noexcept
137  {
138  return machine_.context();
139  }
140  [[nodiscard]] context_type const& context() const noexcept
141  {
142  return machine_.context();
143  }
144 
145  template<typename Event>
146  requires(tsm::detail::contains_type<std::decay_t<Event>>(
148  [[nodiscard]] bool send_event(Event&& event)
149  {
152  last_event_handled_ = machine_.handle(std::forward<Event>(event));
153  return last_event_handled_;
154  }
155 
156  [[nodiscard]] bool step()
157  {
158  last_event_handled_ = false;
159  return false;
160  }
161 
162  std::size_t drain()
163  {
164  return 0;
165  }
166 
167  [[nodiscard]] bool empty() const
168  {
169  return true;
170  }
171  [[nodiscard]] std::size_t pending_events() const
172  {
173  return 0;
174  }
175  [[nodiscard]] bool last_event_handled() const
176  {
177  return last_event_handled_;
178  }
179 
180  private:
181  machine_type machine_{};
182  bool last_event_handled_{};
183 };
184 
194 template<typename Definition,
195  typename Policy,
196  template<typename>
197  class MachinePolicy>
198 class runtime_impl<Definition, Policy, MachinePolicy, topology::composite_queue>
199 {
200  public:
201  using definition = Definition;
202  using policy = Policy;
203  using machine_type = typename MachinePolicy<Definition>::type;
204  using context_type = typename machine_type::context_type;
206  using queued_event = tsm::detail::erased_event<machine_type, events>;
207  using queue_type = typename Policy::storage::template queue<queued_event>;
208 
209  static_assert(queue_storage<queue_type, queued_event>,
210  "tsm: composite queue storage must satisfy queue_storage");
211 
212  [[nodiscard]] machine_type& machine() noexcept
213  {
214  return machine_;
215  }
216  [[nodiscard]] machine_type const& machine() const noexcept
217  {
218  return machine_;
219  }
220 
221  [[nodiscard]] context_type& context() noexcept
222  {
223  return machine_.context();
224  }
225  [[nodiscard]] context_type const& context() const noexcept
226  {
227  return machine_.context();
228  }
229 
230  template<typename Event>
231  requires(tsm::detail::contains_type<std::decay_t<Event>>(
233  [[nodiscard]] bool send_event(Event&& event)
234  {
238  queued_event queued(std::forward<Event>(event));
239  return overflow_strategy<typename Policy::overflow>::push(
240  event_queue_, std::move(queued));
241  }
242 
243  [[nodiscard]] bool step()
244  {
248  queued_event event{};
249  if (!event_queue_.try_pop(event)) {
250  last_event_handled_ = false;
251  return false;
252  }
253  last_event_handled_ = event.dispatch(machine_);
254  return true;
255  }
256 
257  std::size_t drain()
258  {
261  std::size_t dispatched{};
262  while (!event_queue_.empty()) {
263  static_cast<void>(step());
264  ++dispatched;
265  }
266  return dispatched;
267  }
268 
269  [[nodiscard]] bool empty() const
270  {
271  return event_queue_.empty();
272  }
273  [[nodiscard]] std::size_t pending_events() const
274  {
275  return event_queue_.size();
276  }
277  [[nodiscard]] bool last_event_handled() const
278  {
279  return last_event_handled_;
280  }
281 
282  private:
283  machine_type machine_{};
284  queue_type event_queue_{};
285  bool last_event_handled_{};
286 };
287 
293 template<typename Machine, typename RegionDefinition, typename Storage>
294 class region_queue
295 {
296  public:
297  using region_definition = RegionDefinition;
298  using region_hsm = typename Machine::template region_hsm<RegionDefinition>;
300  using queued_event = tsm::detail::erased_event<region_hsm, events>;
301  using queue_type = typename Storage::template queue<queued_event>;
302 
303  static_assert(queue_storage<queue_type, queued_event>,
304  "tsm: region queue storage must satisfy queue_storage");
305 
306  template<typename Event>
307  static consteval bool accepts()
308  {
309  return tsm::detail::contains_type<Event>(
311  }
312 
313  template<typename Event, typename Overflow>
314  [[nodiscard]] bool send(Event&& event)
315  {
316  queued_event queued(std::forward<Event>(event));
317  return overflow_strategy<Overflow>::push(queue_, std::move(queued));
318  }
319 
320  [[nodiscard]] bool step(Machine& machine, bool& handled)
321  {
322  queued_event event{};
323  if (!queue_.try_pop(event)) {
324  return false;
325  }
326  handled = event.dispatch(machine.template region<RegionDefinition>());
327  return true;
328  }
329 
330  [[nodiscard]] bool empty() const
331  {
332  return queue_.empty();
333  }
334  [[nodiscard]] std::size_t pending_events() const
335  {
336  return queue_.size();
337  }
338 
339  private:
340  queue_type queue_{};
341 };
342 
354 template<typename... RegionDefinitions,
355  typename Policy,
356  template<typename>
357  class MachinePolicy>
358 class runtime_impl<tsm::detail::OrthogonalExecutionPolicy<RegionDefinitions...>,
359  Policy,
360  MachinePolicy,
362 {
363  public:
364  using definition =
365  tsm::detail::OrthogonalExecutionPolicy<RegionDefinitions...>;
366  using policy = Policy;
367  using machine_type = definition;
368  using regions = typename machine_type::regions;
369  using queues = std::tuple<region_queue<machine_type,
370  RegionDefinitions,
371  typename Policy::storage>...>;
372 
373  [[nodiscard]] machine_type& machine() noexcept
374  {
375  return machine_;
376  }
377  [[nodiscard]] machine_type const& machine() const noexcept
378  {
379  return machine_;
380  }
381 
382  template<typename RegionDefinition, typename Event>
383  [[nodiscard]] bool send_event(Event&& event)
384  {
387  using event_type = std::decay_t<Event>;
388  using queue_holder = region_queue<machine_type,
389  RegionDefinition,
390  typename Policy::storage>;
391  static_assert(queue_holder::template accepts<event_type>(),
392  "tsm: region queue cannot accept this event type");
393  return std::get<queue_holder>(queues_)
394  .template send<Event, typename Policy::overflow>(
395  std::forward<Event>(event));
396  }
397 
398  template<typename Event>
399  [[nodiscard]] bool broadcast_event(Event const& event)
400  {
404  bool accepted = true;
405  bool matched = false;
406  broadcast_event_impl<std::decay_t<Event>, 0U>(event, accepted, matched);
407  return matched && accepted;
408  }
409 
410  [[nodiscard]] bool step()
411  {
415  last_event_handled_ = false;
416  return step_region<0U>();
417  }
418 
419  std::size_t drain()
420  {
421  std::size_t dispatched{};
422  while (!empty()) {
423  static_cast<void>(step());
424  ++dispatched;
425  }
426  return dispatched;
427  }
428 
429  [[nodiscard]] bool empty() const
430  {
431  return empty_region<0U>();
432  }
433 
434  [[nodiscard]] std::size_t pending_events() const
435  {
436  return pending_region<0U>();
437  }
438 
439  [[nodiscard]] bool last_event_handled() const
440  {
441  return last_event_handled_;
442  }
443 
444  private:
445  template<std::size_t Index>
446  [[nodiscard]] bool step_region()
447  {
448  if constexpr (Index < sizeof...(RegionDefinitions)) {
449  using RegionDefinition = tsm::detail::type_at_t<Index, regions>;
450  using queue_holder = region_queue<machine_type,
451  RegionDefinition,
452  typename Policy::storage>;
453  if (std::get<queue_holder>(queues_).step(machine_,
454  last_event_handled_)) {
455  return true;
456  }
457  return step_region<Index + 1U>();
458  } else {
459  return false;
460  }
461  }
462 
463  template<std::size_t Index>
464  [[nodiscard]] bool empty_region() const
465  {
466  if constexpr (Index < sizeof...(RegionDefinitions)) {
467  using RegionDefinition = tsm::detail::type_at_t<Index, regions>;
468  using queue_holder = region_queue<machine_type,
469  RegionDefinition,
470  typename Policy::storage>;
471  return std::get<queue_holder>(queues_).empty() &&
472  empty_region<Index + 1U>();
473  } else {
474  return true;
475  }
476  }
477 
478  template<std::size_t Index>
479  [[nodiscard]] std::size_t pending_region() const
480  {
481  if constexpr (Index < sizeof...(RegionDefinitions)) {
482  using RegionDefinition = tsm::detail::type_at_t<Index, regions>;
483  using queue_holder = region_queue<machine_type,
484  RegionDefinition,
485  typename Policy::storage>;
486  return std::get<queue_holder>(queues_).pending_events() +
487  pending_region<Index + 1U>();
488  } else {
489  return 0;
490  }
491  }
492 
493  template<typename Event, std::size_t Index>
494  void broadcast_event_impl(Event const& event, bool& accepted, bool& matched)
495  {
496  if constexpr (Index < sizeof...(RegionDefinitions)) {
497  using RegionDefinition = tsm::detail::type_at_t<Index, regions>;
498  using queue_holder = region_queue<machine_type,
499  RegionDefinition,
500  typename Policy::storage>;
501  if constexpr (queue_holder::template accepts<Event>()) {
502  matched = true;
503  accepted =
504  std::get<queue_holder>(queues_)
505  .template send<Event const&, typename Policy::overflow>(
506  event) &&
507  accepted;
508  }
509  broadcast_event_impl<Event, Index + 1U>(event, accepted, matched);
510  }
511  }
512 
513  machine_type machine_{};
514  queues queues_{};
515  bool last_event_handled_{};
516 };
517 
518 } // namespace tsm::runtime::detail
519 
520 namespace tsm::runtime {
521 
527 template<typename Definition,
528  typename Policy,
529  template<typename> class MachinePolicy =
530  detail::default_machine_policy>
531 using Runtime = detail::runtime_impl<Definition, Policy, MachinePolicy>;
532 
533 template<typename Definition,
534  typename Policy,
535  template<typename> class MachinePolicy =
536  detail::default_machine_policy>
538 
539 template<typename Definition,
540  template<typename> class MachinePolicy =
541  detail::default_machine_policy>
543  Runtime<Definition,
546  MachinePolicy>;
547 
548 template<typename Definition,
549  std::size_t Capacity,
550  typename Overflow = overflow::reject_newest,
551  template<typename> class MachinePolicy =
552  detail::default_machine_policy>
554  Runtime<Definition,
558  MachinePolicy>;
559 
560 template<typename Definition,
561  std::size_t Capacity,
562  typename Overflow = overflow::reject_newest,
563  template<typename> class MachinePolicy =
564  detail::default_machine_policy>
566  Runtime<Definition,
570  MachinePolicy>;
571 
572 } // namespace tsm::runtime
unique_tuple_t< typename get_events_from_hsm< HsmType >::type > get_events_t
Definition: tsm.h:2077
typename make_hsm< T >::type make_hsm_t
Definition: tsm.h:1489
requires(!has_transition_type_c< T > &&has_transition_member_c< T >) struct transitions_of< T >
Definition: transition.h:479
typename as_type_list< T >::type as_type_list_t
Definition: type_list.h:175
typename type_at< Index, List >::type type_at_t
Definition: type_list.h:100
consteval bool contains_type(type_list< Ts... >)
Definition: type_list.h:124
Definition: concepts.h:40
Definition: actor.h:347
::tsm::overflow::reject_newest reject_newest
Definition: concepts.h:87
::tsm::overflow::drop_oldest drop_oldest
Definition: concepts.h:88
::tsm::overflow::overwrite_latest overwrite_latest
Definition: concepts.h:89
::tsm::dispatch_model::per_region_queued per_region_queue
Definition: concepts.h:81
::tsm::dispatch_model::queued composite_queue
Definition: concepts.h:80
::tsm::dispatch_model::direct direct_dispatch
Definition: concepts.h:79
Definition: freertos.h:26
detail::runtime_impl< Definition, Policy, MachinePolicy > Runtime
Definition: runtime.h:531
Runtime< Definition, ::tsm::runtime_policy< ::tsm::dispatch_model::queued, ::tsm::queue_policy<::tsm::target_storage< Capacity >, Overflow > >, MachinePolicy > queued_runtime
Definition: runtime.h:558
Runtime< Definition, ::tsm::runtime_policy< ::tsm::dispatch_model::per_region_queued, ::tsm::queue_policy<::tsm::target_storage< Capacity >, Overflow > >, MachinePolicy > per_region_runtime
Definition: runtime.h:570
Runtime< Definition, Policy, MachinePolicy > runtime_for
Definition: runtime.h:537
::tsm::runtime_policy< Topology, Storage, Scheduler, Overflow, Transport > policy
Definition: policy.h:119
Runtime< Definition, ::tsm::runtime_policy<::tsm::dispatch_model::direct, ::tsm::queue_policy<::tsm::static_storage< 2 > >>, MachinePolicy > direct_runtime
Definition: runtime.h:546
Definition: bare_metal.h:20
auto send_event(Runtime &runtime, Event &&event)
Definition: coroutine.h:972
auto send(Runtime &runtime, Args &&... args)
Definition: coroutine.h:980
Runtime policy tags for dispatch and bounded queue admission.
Fixed-capacity ring queue storage for runtime events.
Definition: policy.h:27
Definition: policy.h:29
Definition: policy.h:52
Definition: policy.h:89
Local runtime transport boundary for typed events.