LiteFX 0.4.1.2025
Computer Graphics Engine
Loading...
Searching...
No Matches
app.hpp
1#pragma once
2
3#include <litefx/app_api.hpp>
4#include <litefx/app_formatters.hpp>
5
6namespace LiteFX {
7 using namespace LiteFX::Logging;
8
18 class LITEFX_APPMODEL_API IBackend {
19 friend class App;
20
21 private:
22 BackendState m_state = BackendState::Inactive;
23
24 protected:
25 IBackend() noexcept = default;
26 IBackend(const IBackend&) = default;
27 IBackend(IBackend&&) noexcept = default;
28 IBackend& operator=(const IBackend&) = default;
29 IBackend& operator=(IBackend&&) noexcept = default;
30
31 public:
32 virtual ~IBackend() noexcept = default;
33
34 public:
40 virtual BackendType type() const noexcept = 0;
41
47 const BackendState& state() const noexcept { return m_state; }
48
53 virtual StringView name() const noexcept = 0;
54
55 protected:
60 BackendState& state() noexcept { return m_state; }
61
65 virtual void activate() = 0;
66
70 virtual void deactivate() = 0;
71
72 private:
73 std::type_index typeId() const noexcept { return typeid(*this); }
74 };
75
79 template <typename T>
81
86 class LITEFX_APPMODEL_API EventArgs {
87 public:
88 EventArgs() = default;
89
90 EventArgs(const EventArgs&) = default;
91 EventArgs(EventArgs&&) noexcept = default;
92 EventArgs& operator=(const EventArgs&) = default;
93 EventArgs& operator=(EventArgs&&) noexcept = default;
94 virtual ~EventArgs() noexcept = default;
95 };
96
107 template <typename TResult, typename... TArgs>
108 class Delegate final {
109 public:
110 using function_type = std::function<TResult(TArgs...)>;
111 using token_type = size_t;
112
113 private:
114 function_type m_target;
115 token_type m_token;
116
117 public:
123 inline Delegate(function_type fn, token_type t) noexcept :
124 m_target(std::move(fn)), m_token(t) { }
125
126 public:
132 inline TResult invoke(TArgs... args) const {
133 return m_target(std::move(args)...);
134 }
135
140 inline token_type token() const {
141 return m_token;
142 }
143
144 public:
150 inline TResult operator()(TArgs... args) const {
151 return this->invoke(std::move(args)...);
152 }
153 };
154
167 template <typename TEventArgs>
168 class Event final {
169 public:
170 using event_args_type = TEventArgs;
174
175 private:
176 Array<delegate_type> m_subscribers{};
177
178 public:
182 constexpr Event() = default;
183
191 constexpr Event([[maybe_unused]] const Event& _other) { }
192
197 constexpr Event(Event&& _other) noexcept = default;
198
207 constexpr Event& operator=([[maybe_unused]] const Event& _other) {
208 m_subscribers.clear();
209 return *this;
210 }
211
217 constexpr Event& operator=(Event&& _other) noexcept = default;
218
222 constexpr ~Event() noexcept = default;
223
224 public:
230 event_token_type add(const function_type& subscriber) {
231 const auto match = std::max_element(m_subscribers.begin(), m_subscribers.end(), [](const auto& lhs, const auto& rhs) { return lhs.token() < rhs.token(); });
232 event_token_type token = match == m_subscribers.end() ? 0 : match->token() + 1;
233 m_subscribers.emplace_back(subscriber, token);
234 return token;
235 }
236
242 bool remove(const delegate_type& subscriber) noexcept {
243 return this->remove(subscriber.token());
244 }
245
251 bool remove(event_token_type token) noexcept {
252 const auto last = std::remove_if(m_subscribers.begin(), m_subscribers.end(), [&token](const auto& s) { return s.token() == token; });
253
254 if (last == m_subscribers.end())
255 return false;
256
257 m_subscribers.erase(last, m_subscribers.end());
258 return true;
259 }
260
264 void clear() noexcept {
265 m_subscribers.clear();
266 }
267
273 void invoke(const void* sender, const TEventArgs& args) const {
274 for (const auto& handler : m_subscribers)
275 handler(sender, args);
276 }
277
283 bool contains(event_token_type token) const noexcept {
284 return std::find_if(m_subscribers.begin(), m_subscribers.end(), [&token](const auto& d) { return d.token() == token; }) != m_subscribers.end();
285 }
286
294 if (auto match = std::find_if(m_subscribers.begin(), m_subscribers.end(), [&token](const auto& d) { return d.token() == token; }); match != m_subscribers.end()) [[likely]]
295 return *match;
296
297 throw InvalidArgumentException("token", "The event does not contain the provided token.");
298 }
299
300 public:
305 explicit operator bool() const noexcept {
306 return !m_subscribers.empty();
307 }
308
314 event_token_type operator +=(const function_type& subscriber) {
315 return this->add(subscriber);
316 }
317
323 bool operator -=(const delegate_type& subscriber) noexcept {
324 return this->remove(subscriber);
325 }
326
332 bool operator -=(event_token_type token) noexcept {
333 return this->remove(token);
334 }
335
341 void operator ()(const void* sender, const TEventArgs& args) const {
342 this->invoke(sender, args);
343 }
344
351 const delegate_type& operator [](event_token_type token) const {
352 return this->handler(token);
353 }
354 };
355
360 struct LITEFX_APPMODEL_API ResizeEventArgs : public EventArgs {
361 private:
362 int m_width, m_height;
363
364 public:
370 ResizeEventArgs(int width, int height) noexcept : m_width(width), m_height(height) { }
372 ResizeEventArgs(ResizeEventArgs&&) noexcept = default;
373 ~ResizeEventArgs() noexcept override = default;
374
375 public:
376 ResizeEventArgs& operator=(const ResizeEventArgs&) = default;
377 ResizeEventArgs& operator=(ResizeEventArgs&&) noexcept = default;
378
379 public:
384 inline int width() const noexcept {
385 return m_width;
386 }
387
392 inline int height() const noexcept {
393 return m_height;
394 }
395 };
396
402 class LITEFX_APPMODEL_API App {
403 LITEFX_IMPLEMENTATION(AppImpl);
404 LITEFX_BUILDER(AppBuilder);
405
406 public:
410 App();
411 App(const App&) = delete;
412 App(App&&) noexcept = delete;
413 auto operator=(const App&) = delete;
414 auto operator=(App&&) noexcept = delete;
415
416 virtual ~App() noexcept;
417
418 public:
423 virtual StringView name() const noexcept = 0;
424
429 virtual AppVersion version() const noexcept = 0;
430
435 Platform platform() const noexcept;
436
442 const IBackend* operator[](std::type_index type) const;
443
449 const IBackend* getBackend(std::type_index type) const;
450
456 Enumerable<const IBackend&> getBackends(const BackendType type) const;
457
458 protected:
464 IBackend* getBackend(std::type_index type);
465
471 template <typename TBackend> requires
472 meta::implements<TBackend, IBackend>
473 TBackend* findBackend() {
474 return dynamic_cast<TBackend*>(this->getBackend(typeid(TBackend)));
475 }
476
487 void startBackend(std::type_index type) const;
488
498 void stopBackend(std::type_index type) const;
499
505 void stopActiveBackends(BackendType type) const;
506
512 IBackend* activeBackend(BackendType type) const;
513
519 std::type_index activeBackendType(BackendType type) const;
520
521 private:
527 void registerStartCallback(std::type_index type, const std::function<bool()>& callback);
528
534 void registerStopCallback(std::type_index type, const std::function<void()>& callback);
535
536 public:
541
546
563 template <typename TBackend> requires
565 void onBackendStart(const std::function<bool(TBackend*)>& callback) {
566 this->registerStartCallback(typeid(TBackend), [this, callback]() {
567 auto backend = this->findBackend<TBackend>();
568
569 if (backend == nullptr)
570 throw InvalidArgumentException("callback", "No backend of type {0} has been registered.", typeid(TBackend).name());
571
572 if (backend->state() == BackendState::Active)
573 return true;
574 else
575 return callback(backend);
576 });
577 }
578
590 template <typename TBackend> requires
592 void onBackendStop(const std::function<void(TBackend*)>& callback) {
593 this->registerStopCallback(typeid(TBackend), [this, callback]() {
594 auto backend = this->findBackend<TBackend>();
595
596 if (backend == nullptr)
597 throw InvalidArgumentException("callback", "No backend of type {0} has been registered.", typeid(TBackend).name());
598
599 if (backend->state() != BackendState::Inactive)
600 callback(backend);
601 });
602 }
603
604 public:
610 template <typename TBackend> requires
612 const TBackend* findBackend() const {
613 return dynamic_cast<const TBackend*>(this->getBackend(typeid(TBackend)));
614 }
615
621 template <typename TBackend> requires
624 this->startBackend(typeid(TBackend));
625 }
626
632 template <typename TBackend> requires
634 void stopBackend() {
635 this->stopBackend(typeid(TBackend));
636 }
637
638 public:
642 mutable Event<EventArgs> startup; // NOLINT
643
648
652 mutable Event<EventArgs> shutdown; // NOLINT
653
659 virtual void use(UniquePtr<IBackend>&& backend);
660
664 void run();
665
666 public:
671
677 void resize(int width, int height);
678
679 public:
683 template <typename TApp, typename ...TArgs>
684 [[nodiscard]] static AppBuilder build(TArgs&&... _args);
685 };
686
690 class LITEFX_APPMODEL_API [[nodiscard]] AppBuilder : public Builder<App> {
691 public:
692 using Builder<App>::Builder;
693
694 public:
696 void use(UniquePtr<IBackend>&& backend);
697
701 template <typename TSink, typename ...TArgs> requires
702 std::convertible_to<TSink*, ISink*>
703 AppBuilder& logTo(TArgs&&... args) {
704 auto sink = makeUnique<TSink>(std::forward<TArgs>(args)...);
705 Logger::sinkTo(sink.get());
706 return *this;
707 }
708
712 template <typename TBackend, typename ...TArgs> requires
714 AppBuilder& useBackend(TArgs&&... args) {
715 this->use(makeUnique<TBackend>(*this->instance(), std::forward<TArgs>(args)...));
716 return *this;
717 }
718 };
719
720 template<typename TApp, typename ...TArgs>
721 inline AppBuilder App::build(TArgs && ..._args)
722 {
723 return AppBuilder(makeUnique<TApp>(std::forward<TArgs>(_args)...));
724 }
725
726}
Definition app.cpp:9
Creates a new builder for an App.
Definition app.hpp:690
AppBuilder & useBackend(TArgs &&... args)
Registers a new backend.
Definition app.hpp:714
AppBuilder & logTo(TArgs &&... args)
Registers a sink for logging.
Definition app.hpp:703
The base class for an application.
Definition app.hpp:402
Event< EventArgs > shutdown
Invoked, if the application has is shutting down.
Definition app.hpp:652
Event< EventArgs > startup
Invoked, if the application has been started.
Definition app.hpp:642
Event< const IBackend * > backendStarted
Invoked, if a backend has been started.
Definition app.hpp:540
Event< ResizeEventArgs > resized
Invoked, if the app window or context gets resized.
Definition app.hpp:670
App(App &&) noexcept=delete
void onBackendStop(const std::function< void(TBackend *)> &callback)
Sets a callback that is called, if a backend is stopped.
Definition app.hpp:592
App(const App &)=delete
void onBackendStart(const std::function< bool(TBackend *)> &callback)
Sets a callback that is called, if a backend is started.
Definition app.hpp:565
void stopBackend()
Stops a backend, if it is currently running.
Definition app.hpp:634
Event< const IBackend * > backendStopped
Invoked, if a backend has been stopped.
Definition app.hpp:545
const TBackend * findBackend() const
Returns the registered backend instance for a type index.
Definition app.hpp:612
void startBackend()
Attempts to start a backend of type TBackend and stops the active backend of the same BackendType,...
Definition app.hpp:623
Event< EventArgs > initializing
Invoked during initialization.
Definition app.hpp:647
Contains the version of an App.
Definition app_api.hpp:50
Describes an generic builder type.
Definition containers.hpp:960
Represents a handler for an Event, that is assigned a unique token when created, so that it can be id...
Definition app.hpp:108
Delegate(function_type fn, token_type t) noexcept
Creates a new delegate.
Definition app.hpp:123
token_type token() const
Returns the unique token of the delegate.
Definition app.hpp:140
TResult invoke(TArgs... args) const
Invokes the delegate function.
Definition app.hpp:132
size_t token_type
Definition app.hpp:111
TResult operator()(TArgs... args) const
Invokes the delegate function.
Definition app.hpp:150
std::function< TResult(TArgs...)> function_type
Definition app.hpp:110
Base class for additional event arguments.
Definition app.hpp:86
EventArgs()=default
EventArgs(EventArgs &&) noexcept=default
EventArgs(const EventArgs &)=default
A class that is used to declare an event, which a number of listeners can subscribe to.
Definition app.hpp:168
bool remove(event_token_type token) noexcept
Unsubscribes an event handler from the event.
Definition app.hpp:251
typename delegate_type::token_type event_token_type
Definition app.hpp:173
constexpr ~Event() noexcept=default
Releases the event instance.
void clear() noexcept
Clears the event handlers.
Definition app.hpp:264
bool contains(event_token_type token) const noexcept
Returns true, if the event contains a subscriber with the provided token .
Definition app.hpp:283
constexpr Event()=default
Initializes a new event.
TEventArgs event_args_type
Definition app.hpp:170
constexpr Event & operator=(Event &&_other) noexcept=default
Assigns a event by taking it over.
bool remove(const delegate_type &subscriber) noexcept
Unsubscribes an event handler from the event.
Definition app.hpp:242
constexpr Event(const Event &_other)
Creates a copy of a event.
Definition app.hpp:191
constexpr Event & operator=(const Event &_other)
Assigns a event by copying it.
Definition app.hpp:207
typename delegate_type::function_type function_type
Definition app.hpp:172
void invoke(const void *sender, const TEventArgs &args) const
Invokes all event handlers of the event.
Definition app.hpp:273
const delegate_type & handler(event_token_type token) const
Returns the delegate associated with token .
Definition app.hpp:293
constexpr Event(Event &&_other) noexcept=default
Takes over another instance of a event.
The base class for an app backend.
Definition app.hpp:18
virtual StringView name() const noexcept=0
Gets the name of the backend.
IBackend() noexcept=default
virtual void deactivate()=0
Called by the parent App, if the backend is stopped.
virtual void activate()=0
Called by the parent App, if the backend is started.
An exception that is thrown, if a provided argument is not valid.
Definition exceptions.hpp:60
Concept that can be used to refer to backend implementations.
Definition app.hpp:80
Checks if a type TDerived is derived from another type TBase and is non-abstract.
Definition traits.hpp:118
Definition logging.hpp:23
Definition app.hpp:6
BackendState
Definition app_api.hpp:42
std::vector< T > Array
Represents a dynamic array.
Definition containers.hpp:73
std::unique_ptr< T, TDeleter > UniquePtr
Represents a unique pointer, that expresses exclusive ownership.
Definition containers.hpp:102
std::string_view StringView
Definition string.hpp:26
BackendType
Definition app_api.hpp:35
Platform
Definition app_api.hpp:29
An input range over another range, where the returned values of type T are covariants of the values ...
Definition containers.hpp:529
Stores event arguments of a window resize event.
Definition app.hpp:360
int height() const noexcept
Returns the new window height.
Definition app.hpp:392
ResizeEventArgs(int width, int height) noexcept
Creates a new set of window resize event arguments.
Definition app.hpp:370
ResizeEventArgs(ResizeEventArgs &&) noexcept=default
ResizeEventArgs(const ResizeEventArgs &)=default