LiteFX 0.4.1.2025
Computer Graphics Engine
Loading...
Searching...
No Matches
LiteFX::Enumerable< T > Struct Template Reference

An input range over another range, where the returned values of type T are covariants of the values stored by the underlying range. More...

#include <containers.hpp>

Public Types

using value_type = std::remove_cvref_t<T>
 The type of the value that is contained by the Enumerable.
 
using pointer = std::remove_reference_t<T>*
 The type of a pointer returned by the Enumerable.
 
using reference = std::remove_reference_t<T>&
 The type of a reference returned by the Enumerable.
 
using iterator = CovariantIterator<T>
 The type of the iterator used to iterate the elements of the Enumerable.
 
using const_iterator = CovariantIterator<const std::remove_const_t<T>>
 The type of the iterator used to iterate constant elements of the Enumerable.
 

Public Member Functions

 Enumerable ()
 Creates an enumerable over an empty range.
 
 Enumerable (const Enumerable &range)=default
 
 Enumerable (Enumerable &&range) noexcept=default
 
Enumerableoperator= (const Enumerable &range)=default
 
Enumerableoperator= (Enumerable &&range) noexcept=default
 
 ~Enumerable () noexcept=default
 
template<typename TRange , typename enabled = std::enable_if_t<!std::is_same_v<TRange, Enumerable>>>
 Enumerable (TRange &&range)
 Creates a new Enumerable instance from an underlying range.
 
auto begin () const
 Returns an iterator pointing to the start of the underlying range.
 
auto end () const
 Returns an iterator pointing to the end of the underlying range.
 
auto cbegin () const
 Returns a constant iterator pointing to the start of the underlying range.
 
auto cend () const
 Returns a constant iterator pointing to the end of the underlying range.
 
bool empty () const noexcept
 Returns true, if there are no elements inside the Enumerable and false otherwise.
 

Detailed Description

template<typename T>
struct LiteFX::Enumerable< T >

An input range over another range, where the returned values of type T are covariants of the values stored by the underlying range.

An Enumerable is intended to be used as a covariant input range for interfaces that want to expose a range of elements that are also interfaces for the stored elements of the actual range. In the context of an Enumerable, covariance refers to the type T either being assignable or constructible from the underlying range value type. This allows not only derived types (in a stricter definition that the C++ language standard uses), but also unrelated types, such as smart pointers to be used in a covariant fashion.

In the following example, the interface IContainer returns an Enumerable&lt;IContained&gt; from a class Container, where the contained elements are of type Contained.

class IContained { }; class Contained : public IContained { };

class IContainer { public: virtual Enumerable<const IContained&> elements() const noexcept = 0; };

class Container : public IContainer { private: std::vector<Contained> _elements;

public: Enumerable<const IContained&> elements() const noexcept override { return _elements; } };

As Contained is derived from IContained, they are covariant in terms of the language. In the context of Enumerable, they are covariant, because a const IContained&amp; can be constructed from a const Contained&amp;. This way, using Enumeable in IContainer allows to iterate the interface instances without knowing their type when declaring the interface. The covariance relation only applies to the elements of the range, not the range itself. In the example above, std::vector&lt;Contained&gt; is not covariant to Enumerable&lt;const IContained&gt;, as the two types are not related. This is important as Enumerable has a slight performance impact compared to returning a reference of the underlying range directly, both in terms of memory (it stores type information about the original iterators) as well as runtime (it requires a virtual call for iterator increments, dereferencing and comparison). If you want to expose covariant ranges in interfaces, but allow for maximum performance when the implementation is called directly, you can hide the interface method using private inheritance:

class IContainer { public: inline Enumerable<const IContained&> elements() const noexcept { return this->getElements(); }

private: virtual Enumerable<const IContained&> getElements() const noexcept = 0; };

class Container : public IContainer { private: std::vector<Contained> _elements;

public: const std::vector<IContained>& elements() const noexcept { return _elements; }

private: Enumerable<const IContained&> getElements() const noexcept override { return _elements; } };

Enumerable can be using in two ways: first, it can be initialized with a lvalue reference of the underlying range or view as shown above. In this case, only the begin and end iterators of the underlying range are stored. However, when passed a rvalue reference, the Enumerable will store the underlying range until it and all copies of it are destroyed. This allows to use Enumerable either for returning a temporary range or a view as shown in the example below.

Enumerable<Foo> temporaryFoos() { std::vector<Foo> foos {}; foos.emplace_back(); foos.emplace_back(); foos.emplace_back();

return std::move(foos);

// Or better: //return std::vector<Foo>(3); }

Enumerable<Foo&> filteredFoos(const std::vector<Foo>& foos) { return foos | std::views::drop(1) | std::views::take(2); }

Keep in mind that the type parameter T dictates what an iterator returns from the Enumerable, i.e. if an lvalue or (p)rvalue should be returned and wheather or not a copy is created accordingly.

Template Parameters
TThe type of the values returned by the enumerable.
See also
CovariantIterator

Member Typedef Documentation

◆ const_iterator

template<typename T >
using LiteFX::Enumerable< T >::const_iterator = CovariantIterator<const std::remove_const_t<T>>

The type of the iterator used to iterate constant elements of the Enumerable.

◆ iterator

template<typename T >
using LiteFX::Enumerable< T >::iterator = CovariantIterator<T>

The type of the iterator used to iterate the elements of the Enumerable.

◆ pointer

template<typename T >
using LiteFX::Enumerable< T >::pointer = std::remove_reference_t<T>*

The type of a pointer returned by the Enumerable.

◆ reference

template<typename T >
using LiteFX::Enumerable< T >::reference = std::remove_reference_t<T>&

The type of a reference returned by the Enumerable.

◆ value_type

template<typename T >
using LiteFX::Enumerable< T >::value_type = std::remove_cvref_t<T>

The type of the value that is contained by the Enumerable.

Constructor & Destructor Documentation

◆ Enumerable() [1/4]

template<typename T >
LiteFX::Enumerable< T >::Enumerable ( )
inline

Creates an enumerable over an empty range.

◆ Enumerable() [2/4]

template<typename T >
LiteFX::Enumerable< T >::Enumerable ( const Enumerable< T > & range)
inlinedefault

◆ Enumerable() [3/4]

template<typename T >
LiteFX::Enumerable< T >::Enumerable ( Enumerable< T > && range)
inlinedefaultnoexcept

◆ ~Enumerable()

template<typename T >
LiteFX::Enumerable< T >::~Enumerable ( )
defaultnoexcept

◆ Enumerable() [4/4]

template<typename T >
template<typename TRange , typename enabled = std::enable_if_t<!std::is_same_v<TRange, Enumerable>>>
LiteFX::Enumerable< T >::Enumerable ( TRange && range)
inline

Creates a new Enumerable instance from an underlying range.

Template Parameters
TRangeThe type of the underlying range.
enabledDisables the constructor, if TRange is equal to the current type, in which case the move constructor should be called.
Parameters
rangeA reference of the underlying range.

Member Function Documentation

◆ begin()

template<typename T >
auto LiteFX::Enumerable< T >::begin ( ) const
inline

Returns an iterator pointing to the start of the underlying range.

Returns
An iterator pointing to the start of the underlying range.

◆ cbegin()

template<typename T >
auto LiteFX::Enumerable< T >::cbegin ( ) const
inline

Returns a constant iterator pointing to the start of the underlying range.

Returns
A constant iterator pointing to the start of the underlying range.

◆ cend()

template<typename T >
auto LiteFX::Enumerable< T >::cend ( ) const
inline

Returns a constant iterator pointing to the end of the underlying range.

Returns
A constant iterator pointing to the end of the underlying range.

◆ empty()

template<typename T >
bool LiteFX::Enumerable< T >::empty ( ) const
inlinenoexcept

Returns true, if there are no elements inside the Enumerable and false otherwise.

Returns
true, if there are no elements inside the Enumerable and false otherwise.

◆ end()

template<typename T >
auto LiteFX::Enumerable< T >::end ( ) const
inline

Returns an iterator pointing to the end of the underlying range.

Returns
An iterator pointing to the end of the underlying range.

◆ operator=() [1/2]

template<typename T >
Enumerable & LiteFX::Enumerable< T >::operator= ( const Enumerable< T > & range)
inlinedefault

◆ operator=() [2/2]

template<typename T >
Enumerable & LiteFX::Enumerable< T >::operator= ( Enumerable< T > && range)
inlinedefaultnoexcept