File Event.hpp¶
File List > astrea > astro > astro > propagation > event_detection > Event.hpp
Go to the documentation of this file
#pragma once
#include <units/units.hpp>
#include <astro/platforms/Vehicle.hpp>
#include <astro/state/State.hpp>
namespace astrea {
namespace astro {
template <typename T>
concept HasGetName = requires(const T event) {
{ event.get_name() } -> std::same_as<std::string>;
};
template <typename T>
concept HasMeasureEvent = requires(const T event, const Time& time, const State& state, const Vehicle& vehicle) {
{ event.measure_event(time, state, vehicle) } -> std::same_as<Unitless>;
};
template <typename T>
concept HasIsTerminal = requires(const T event) {
{ event.is_terminal() } -> std::same_as<bool>;
};
template <typename T>
concept HasTriggerEvent = requires(const T event, const Time& time, State& state, Vehicle& vehicle) {
{ event.trigger_action(time, state, vehicle) } -> std::same_as<void>;
};
template <typename T>
concept IsUserDefinedEvent = requires(T) {
std::is_same<T, remove_cv_ref<T>>::value;
std::is_default_constructible<T>::value;
std::is_copy_constructible<T>::value;
std::is_move_constructible<T>::value;
std::is_destructible<T>::value;
requires HasGetName<T>;
requires HasMeasureEvent<T>;
requires HasIsTerminal<T>;
};
namespace detail {
struct EventInnerBase {
virtual ~EventInnerBase() {}
virtual std::string get_name() const = 0;
virtual Unitless measure_event(const Time& time, const State& state, const Vehicle& vehicle) const = 0;
virtual bool is_terminal() const = 0;
virtual void trigger_action(const Time& time, State& state, Vehicle& vehicle) const = 0;
virtual std::unique_ptr<EventInnerBase> clone() const = 0;
virtual const void* get_ptr() const = 0;
virtual void* get_ptr() = 0;
};
template <typename T>
struct EventInner final : public EventInnerBase {
EventInner() = default;
EventInner(const EventInner&) = delete;
EventInner(EventInner&&) = delete;
EventInner& operator=(const EventInner&) = delete;
EventInner& operator=(EventInner&&) = delete;
explicit EventInner(const T& x) :
_value(x)
{
}
explicit EventInner(T&& x) :
_value(std::move(x))
{
}
std::string get_name() const override final { return _value.get_name(); }
Unitless measure_event(const Time& time, const State& state, const Vehicle& vehicle) const override final
{
return _value.measure_event(time, state, vehicle);
}
bool is_terminal() const override final { return _value.is_terminal(); }
void trigger_action(const Time& time, State& state, Vehicle& vehicle) const override final
{
return trigger_action_impl(_value, time, state, vehicle);
}
template <typename U>
requires(HasTriggerEvent<U>)
void trigger_action_impl(const U& value, const Time& time, State& state, Vehicle& vehicle) const
{
value.trigger_action(time, state, vehicle);
}
template <typename U>
requires(!HasTriggerEvent<U>)
void trigger_action_impl(const U& value, const Time& time, State& state, Vehicle& vehicle) const
{
}
std::unique_ptr<EventInnerBase> clone() const final { return std::make_unique<EventInner>(_value); }
const void* get_ptr() const final { return &_value; }
void* get_ptr() final { return &_value; }
T _value;
};
} // namespace detail
class Event; // Forward declaration of the Event class
template <typename T>
concept IsGenericallyConstructableEvent = requires(T) {
requires IsUserDefinedEvent<T>;
std::negation<std::is_same<Event, remove_cv_ref<T>>>::value;
};
class Event {
public:
Event();
private:
void generic_ctor_impl() {}
public:
template <typename T>
requires(IsGenericallyConstructableEvent<T>)
explicit Event(T&& x) :
_ptr(std::make_unique<detail::EventInner<remove_cv_ref<T>>>(std::forward<T>(x)))
{
generic_ctor_impl();
}
Event(const Event&);
Event(Event&&) noexcept;
Event& operator=(Event&&) noexcept;
Event& operator=(const Event&);
template <typename T>
requires(IsGenericallyConstructableEvent<T>)
Event& operator=(T&& x)
{
return (*this) = Event(std::forward<T>(x));
}
template <typename T>
requires(IsGenericallyConstructableEvent<T>)
const T* extract() const noexcept
{
auto p = static_cast<const detail::EventInner<T>*>(ptr());
return p == nullptr ? nullptr : &(p->_value);
}
Unitless measure_event(const Time& time, const State& state, const Vehicle& vehicle) const
{
return ptr()->measure_event(time, state, vehicle);
}
bool is_terminal() const { return ptr()->is_terminal(); }
void trigger_action(const Time& time, State& state, Vehicle& vehicle) const
{
return ptr()->trigger_action(time, state, vehicle);
}
std::string get_name() const { return ptr()->get_name(); }
const void* get_ptr() const;
void* get_ptr();
private:
std::unique_ptr<detail::EventInnerBase> _ptr;
detail::EventInnerBase const* ptr() const
{
assert(_ptr.get() != nullptr);
return _ptr.get();
}
detail::EventInnerBase* ptr()
{
assert(_ptr.get() != nullptr);
return _ptr.get();
}
};
} // namespace astro
} // namespace astrea