LiteFX 0.3.1.2022
Computer Graphics Engine
containers.hpp
1#pragma once
2
3// Disable warning C4251: STL class needs to have dll-interface to be used by clients.
4// See: https://stackoverflow.com/a/22054743/1254352
5#pragma warning(disable: 4251)
6
7#include <array>
8#include <cassert>
9#include <algorithm>
10#include <string>
11#include <optional>
12#include <map>
13#include <vector>
14#include <queue>
15#include <tuple>
16#include <memory>
17#include <functional>
18#include <variant>
19#include <ranges>
20#include <mutex>
21
22#include "traits.hpp"
23#include "string.hpp"
24#include "exceptions.hpp"
25
26#ifndef LITEFX_DEFINE_FLAGS
27# define LITEFX_DEFINE_FLAGS(T) \
28 inline T operator| (const T lhs, const T rhs) { using _base_t = std::underlying_type_t<T>; return static_cast<T>(static_cast<_base_t>(lhs) | static_cast<_base_t>(rhs)); } \
29 inline T& operator|= (T& lhs, const T& rhs) { lhs = lhs | rhs; return lhs; } \
30 inline T operator& (const T lhs, const T rhs) { using _base_t = std::underlying_type_t<T>; return static_cast<T>(static_cast<_base_t>(lhs) & static_cast<_base_t>(rhs)); } \
31 inline T& operator&= (T& lhs, const T& rhs) { lhs = lhs & rhs; return lhs; }
32#endif
33
34#ifndef LITEFX_FLAG_IS_SET
35# define LITEFX_FLAG_IS_SET(val, flag) static_cast<bool>((static_cast<UInt32>(val) & static_cast<UInt32>(flag)) == static_cast<UInt32>(flag))
36#endif
37
38namespace LiteFX {
39
43 using Handle = void*;
44
50 template<class TKey, class TVal>
51 using Dictionary = std::unordered_map<TKey, TVal>;
52
57 template<class T>
58 using Array = std::vector<T>;
59
64 template<class T>
65 using Queue = std::queue<T>;
66
71 template<class T>
72 using Span = std::span<T>;
73
78 template<class T>
79 using Optional = std::optional<T>;
80
86 template<class T, class TDeleter = std::default_delete<T>>
87 using UniquePtr = std::unique_ptr<T, TDeleter>;
88
93 template <class T>
94 using SharedPtr = std::shared_ptr<T>;
95
100 template <class T>
101 using WeakPtr = std::weak_ptr<T>;
102
107 template <class... T>
108 using Tuple = std::tuple<T...>;
109
114 template <class... T>
115 using Variant = std::variant<T...>;
116
122 template <class T>
124 return std::make_unique<T>();
125 }
126
132 template <class T, class... TArgs>
133 UniquePtr<T> makeUnique(TArgs&&... _args) {
134 return std::make_unique<T>(std::forward<TArgs>(_args)...);
135 }
136
142 template <class T>
144 return std::make_shared<T>();
145 }
146
152 template <class T, class... TArgs>
153 SharedPtr<T> makeShared(TArgs&&... _args) {
154 return std::make_shared<T>(std::forward<TArgs>(_args)...);
155 }
156
163 template <class T>
165 return std::make_shared<T>(ptr.release());
166 }
167
171 namespace ranges {
172
173 template <typename TContainer>
174 struct to_container { };
175
176 template <typename TContainer, std::ranges::range TRange> requires
177 std::convertible_to<std::ranges::range_value_t<TRange>, typename TContainer::value_type>
178 inline TContainer operator|(TRange&& range, to_container<TContainer>) {
179 auto it = range | std::views::common;
180 return TContainer{ it.begin(), it.end() };
181 }
182
190 template <std::ranges::range TContainer> requires
191 (!std::ranges::view<TContainer>)
192 auto to() {
194 }
195
196 }
197
198#if (defined(BUILD_LITEFX_PIMPL) && BUILD_LITEFX_PIMPL) || (!defined(BUILD_LITEFX_PIMPL)) && !defined(LITEFX_IMPLEMENTATION)
203 template <class pImpl>
204 class PimplPtr {
205 private:
206 UniquePtr<pImpl> m_ptr;
207
208 public:
212 PimplPtr() noexcept = default;
213
222 PimplPtr(const PimplPtr& src) noexcept : m_ptr(new pImpl(*src.m_ptr)) { }
223
228 PimplPtr(PimplPtr&& src) noexcept = default;
229
239 PimplPtr& operator= (const PimplPtr& src) noexcept { m_ptr.reset(new pImpl(*src.m_ptr)); return *this; }
240
246 PimplPtr& operator= (PimplPtr&& src) noexcept = default;
247
248 ~PimplPtr() noexcept = default;
249
250 private:
255 PimplPtr(pImpl* pimpl) noexcept : m_ptr(pimpl) { }
256
257 public:
261 void destroy() { m_ptr = nullptr; }
262
267 pImpl* release() noexcept { m_ptr.release(); }
268
269 public:
274 pImpl& operator* () const noexcept { return *m_ptr; }
275
280 pImpl* operator-> () const noexcept { return m_ptr.get(); }
281
282 public:
283 template <class T, class... Arg>
284 friend PimplPtr<T> makePimpl(Arg&&... arg);
285 };
286
294 template <class T, class... Arg>
295 PimplPtr<T> makePimpl(Arg&&... arg) {
296 return PimplPtr<T>(new T(std::forward<Arg>(arg)...));
297 }
298
307# define LITEFX_IMPLEMENTATION(impl) private: \
308 class impl; \
309 PimplPtr<impl> m_impl;
310#endif
311
317 template <class TInterface>
318 class Implement {
319 public:
320 using interface_type = TInterface;
322
323 protected:
324 TInterface* m_parent{ nullptr };
325
326 public:
331 Implement(TInterface* parent) : m_parent(parent) {
332 if (parent == nullptr)
333 throw std::runtime_error("Initializing an implementation requires the parent to be provided.");
334 }
335
338 virtual ~Implement() = default;
339 };
340
346 template <class THandle>
347 class IResource {
348 public:
349 virtual ~IResource() noexcept = default;
350
351 protected:
356 virtual THandle& handle() noexcept = 0;
357
358 public:
363 virtual const THandle& handle() const noexcept = 0;
364 };
365
370 template <class THandle>
371 class Resource : public virtual IResource<THandle> {
372 private:
373 THandle m_handle;
374
375 protected:
380 explicit Resource(const THandle handle) noexcept : m_handle(handle) { }
381
382 public:
383 Resource(const Resource&) = delete;
384 Resource(Resource&&) = delete;
385 virtual ~Resource() noexcept = default;
386
387 protected:
389 THandle& handle() noexcept override { return m_handle; }
390
391 public:
393 const THandle& handle() const noexcept override { return m_handle; }
394 };
395
421 template <typename TDerived, typename T, typename TParent = std::nullptr_t, typename TPointer = UniquePtr<T>>
422 class Builder;
423
431 template <typename TDerived, typename T, typename TPointer>
432 class Builder<TDerived, T, std::nullptr_t, typename TPointer> {
433 private:
434 TPointer m_instance;
435
436 public:
437 using derived_type = TDerived;
438 using instance_type = T;
439 using parent_type = std::nullptr_t;
440 using pointer_type = TPointer;
442
443 public:
448 const T* instance() const noexcept { return m_instance.get(); }
449
450 protected:
455 T* instance() noexcept { return m_instance.get(); }
456
457 public:
462 explicit Builder(TPointer&& instance) noexcept : m_instance(std::move(instance)) { }
463
468 Builder(builder_type&& _other) noexcept : m_instance(std::move(_other.m_instance)) { }
469
470 Builder(const builder_type&) = delete;
471 virtual ~Builder() noexcept = default;
472
473 protected:
477 virtual void build() { };
478
479 public:
480 // TODO: Provide concept (`is_buildable<TBuilder>`)
488 template <typename TInstance>
489 void use(pointer_type&&) = delete;
490
494 [[nodiscard]]
495 operator TPointer&& () {
496 this->build();
497 return std::move(m_instance);
498 }
499 };
500
508 template <typename TDerived, typename T, typename TParent, typename TPointer>
509 class Builder {
510 private:
511 TPointer m_instance;
512 TParent& m_parent;
513
514 public:
515 using derived_type = TDerived;
516 using instance_type = T;
517 using parent_type = TParent;
518 using pointer_type = TPointer;
520
521 public:
526 const T* instance() const noexcept { return m_instance.get(); }
527
532 const TParent& parent() const noexcept { return m_parent; }
533
534 protected:
539 T* instance() noexcept { return m_instance.get(); }
540
541 public:
547 explicit Builder(TParent& parent, TPointer&& instance) noexcept : m_parent(parent), m_instance(std::move(instance)) { }
548
553 Builder(builder_type&& _other) noexcept : m_instance(std::move(_other.m_instance)), m_parent(_other.m_parent) { }
554
555 Builder(const builder_type&) = delete;
556 virtual ~Builder() noexcept = default;
557
558 protected:
562 virtual void build() { };
563
564 public:
565 // TODO: Provide concept (`is_buildable<TBuilder>`)
573 template <typename TInstance>
574 void use(pointer_type&&) = delete;
575
579 [[nodiscard]]
580 TParent& add() {
581 this->build();
582 m_parent.use(std::move(m_instance));
583 return m_parent;
584 }
585 };
586
587#if !defined(LITEFX_BUILDER)
588# define LITEFX_BUILDER(BuilderType) public: \
589 using builder_type = BuilderType; \
590 friend class BuilderType;
591#endif // !defined(LITEFX_BUILDER)
592
593}
void use(pointer_type &&)=delete
Called by child builders to pass a constructed object back to the parent builder.
Builder(TPointer &&instance) noexcept
Initializes the builder instance.
Definition: containers.hpp:462
std::nullptr_t parent_type
Definition: containers.hpp:439
Builder(builder_type &&_other) noexcept
Initializes the builder instance by taking over another instance.
Definition: containers.hpp:468
T * instance() noexcept
Returns a pointer to the current instance of the object that is built by the builder.
Definition: containers.hpp:455
const T * instance() const noexcept
Returns a pointer to the current instance of the object that is built by the builder.
Definition: containers.hpp:448
Describes an generic builder type.
Definition: containers.hpp:509
T * instance() noexcept
Returns a pointer to the current instance of the object that is built by the builder.
Definition: containers.hpp:539
TParent & add()
First, calls build, then use on the parent builder using the current object instance and finally retu...
Definition: containers.hpp:580
Builder(builder_type &&_other) noexcept
Initializes the builder instance by taking over another instance.
Definition: containers.hpp:553
T instance_type
Definition: containers.hpp:516
Builder(const builder_type &)=delete
TPointer pointer_type
Definition: containers.hpp:518
TDerived derived_type
Definition: containers.hpp:515
virtual ~Builder() noexcept=default
Builder(TParent &parent, TPointer &&instance) noexcept
Initializes the builder instance.
Definition: containers.hpp:547
const T * instance() const noexcept
Returns a pointer to the current instance of the object that is built by the builder.
Definition: containers.hpp:526
TParent parent_type
Definition: containers.hpp:517
void use(pointer_type &&)=delete
Called by child builders to pass a constructed object back to the parent builder.
const TParent & parent() const noexcept
Returns a reference of the parent builder.
Definition: containers.hpp:532
Provides access to a resource managed by the class.
Definition: containers.hpp:347
virtual THandle & handle() noexcept=0
Returns the resource managed by the class.
virtual ~IResource() noexcept=default
Base class for an implementation of a public interface class.
Definition: containers.hpp:318
Implement(TInterface *parent)
Initializes the implementation instance.
Definition: containers.hpp:331
TInterface * m_parent
Definition: containers.hpp:324
TInterface interface_type
Definition: containers.hpp:320
Implement(const Implement< TInterface > &)=delete
virtual ~Implement()=default
Implement(Implement< TInterface > &&)=delete
A smart pointer that manages an implementation instance for a public interface class.
Definition: containers.hpp:204
pImpl * release() noexcept
Releases the implementation instance managed by this pointer and returns it.
Definition: containers.hpp:267
void destroy()
Destroys the implementation instance managed by this pointer.
Definition: containers.hpp:261
friend PimplPtr< T > makePimpl(Arg &&... arg)
Creates a pointer to an implementation.
Definition: containers.hpp:295
PimplPtr(PimplPtr &&src) noexcept=default
Initializes a new pointer by taking over the implementation instance managed by src .
PimplPtr() noexcept=default
Initializes a new pointer to an uninitialized implementation instance.
pImpl * operator->() const noexcept
Returns a pointer to the managed implementation instance.
Definition: containers.hpp:280
~PimplPtr() noexcept=default
PimplPtr & operator=(const PimplPtr &src) noexcept
Initializes a new pointer to a copy of the implementation instance managed by src .
Definition: containers.hpp:239
pImpl & operator*() const noexcept
Returns a reference to the managed implementation instance.
Definition: containers.hpp:274
Implements the IResource interface.
Definition: containers.hpp:371
virtual ~Resource() noexcept=default
Resource(Resource &&)=delete
const THandle & handle() const noexcept override
Returns the resource managed by the class.
Definition: containers.hpp:393
Resource(const THandle handle) noexcept
Initializes the managed resource.
Definition: containers.hpp:380
Resource(const Resource &)=delete
auto to()
Definition: containers.hpp:192
TContainer operator|(TRange &&range, to_container< TContainer >)
Definition: containers.hpp:178
Definition: app.hpp:6
SharedPtr< T > makeShared()
Creates a new shared pointer.
Definition: containers.hpp:143
UniquePtr< T > makeUnique()
Creates a new unique pointer.
Definition: containers.hpp:123
std::vector< T > Array
Represents a dynamic array.
Definition: containers.hpp:58
void * Handle
Represents a handle type.
Definition: containers.hpp:43
std::weak_ptr< T > WeakPtr
Represents a weak pointer, that expresses a reference to a shared pointer instance.
Definition: containers.hpp:101
std::span< T > Span
Represents a view of an array.
Definition: containers.hpp:72
std::queue< T > Queue
Represents a queue.
Definition: containers.hpp:65
std::shared_ptr< T > SharedPtr
Represents a shared pointer, that expresses non-exclusive ownership.
Definition: containers.hpp:94
PimplPtr< T > makePimpl(Arg &&... arg)
Creates a pointer to an implementation.
Definition: containers.hpp:295
std::unordered_map< TKey, TVal > Dictionary
Represents a dictionary that maps a key to a certain value.
Definition: containers.hpp:51
std::unique_ptr< T, TDeleter > UniquePtr
Represents a unique pointer, that expresses exclusive ownership.
Definition: containers.hpp:87
std::variant< T... > Variant
Represents a variant of objects.
Definition: containers.hpp:115
std::optional< T > Optional
Represents an optional value.
Definition: containers.hpp:79
std::tuple< T... > Tuple
Represents a tuple of multiple objects.
Definition: containers.hpp:108
Definition: containers.hpp:174