1155 lines
38 KiB
C++
1155 lines
38 KiB
C++
///\file
|
|
|
|
/******************************************************************************
|
|
The MIT License(MIT)
|
|
|
|
Embedded Template Library.
|
|
https://github.com/ETLCPP/etl
|
|
https://www.etlcpp.com
|
|
|
|
Copyright(c) 2016 John Wellbelove
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files(the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions :
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#ifndef ETL_UTILITY_INCLUDED
|
|
#define ETL_UTILITY_INCLUDED
|
|
|
|
#include "platform.h"
|
|
#include "type_traits.h"
|
|
|
|
#include "private/tuple_element.h"
|
|
#include "private/tuple_size.h"
|
|
|
|
#if defined(ETL_IN_UNIT_TEST) || ETL_USING_STL
|
|
#if ETL_USING_CPP11
|
|
#include <utility>
|
|
#else
|
|
#include <algorithm>
|
|
#endif
|
|
#endif
|
|
|
|
///\defgroup utility utility
|
|
///\ingroup utilities
|
|
|
|
namespace etl
|
|
{
|
|
#if ETL_USING_CPP11
|
|
//******************************************************************************
|
|
template <typename T>
|
|
constexpr typename etl::remove_reference<T>::type&& move(T&& t) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<typename etl::remove_reference<T>::type&&>(t);
|
|
}
|
|
|
|
//******************************************************************************
|
|
template <typename T>
|
|
constexpr T&& forward(typename etl::remove_reference<T>::type& t) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<T&&>(t);
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr T&& forward(typename etl::remove_reference<T>::type&& t) ETL_NOEXCEPT
|
|
{
|
|
ETL_STATIC_ASSERT(!etl::is_lvalue_reference<T>::value, "Invalid rvalue to lvalue conversion");
|
|
return static_cast<T&&>(t);
|
|
}
|
|
|
|
//******************************************************************************
|
|
/// See std::forward_like
|
|
/// https://en.cppreference.com/w/cpp/utility/forward_like Returns a reference
|
|
/// to x which has similar properties to T&&.
|
|
///\return
|
|
/// If etl::remove_reference_t<T> is const then returns a const reference if U
|
|
/// is an lvalue, otherwise a const rvalue reference. If
|
|
/// etl::remove_reference_t<T> is not const then returns a reference if U is
|
|
/// an lvalue, otherwise an rvalue reference.
|
|
//******************************************************************************
|
|
//***********************************
|
|
/// T is const & lvalue.
|
|
//***********************************
|
|
template <typename T, typename U>
|
|
ETL_NODISCARD
|
|
ETL_CONSTEXPR etl::enable_if_t<etl::is_const<etl::remove_reference_t<T>>::value && etl::is_lvalue_reference<T>::value,
|
|
const etl::remove_reference_t<U>&> forward_like(U&& u) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<const etl::remove_reference_t<U>&>(u);
|
|
}
|
|
|
|
//***********************************
|
|
/// T is const & rvalue.
|
|
//***********************************
|
|
template <typename T, typename U>
|
|
ETL_NODISCARD
|
|
ETL_CONSTEXPR etl::enable_if_t<etl::is_const<etl::remove_reference_t<T>>::value && !etl::is_lvalue_reference<T>::value,
|
|
const etl::remove_reference_t<U>&&> forward_like(U&& u) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<const etl::remove_reference_t<U>&&>(u);
|
|
}
|
|
|
|
//***********************************
|
|
/// T is not const & lvalue.
|
|
//***********************************
|
|
template <typename T, typename U>
|
|
ETL_NODISCARD
|
|
ETL_CONSTEXPR etl::enable_if_t<!etl::is_const<etl::remove_reference_t<T>>::value && etl::is_lvalue_reference<T>::value, etl::remove_reference_t<U>&>
|
|
forward_like(U&& u) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<etl::remove_reference_t<U>&>(u);
|
|
}
|
|
|
|
//***********************************
|
|
/// T is not const & rvalue.
|
|
//***********************************
|
|
template <typename T, typename U>
|
|
ETL_NODISCARD
|
|
ETL_CONSTEXPR etl::enable_if_t<!etl::is_const<etl::remove_reference_t<T>>::value && !etl::is_lvalue_reference<T>::value, etl::remove_reference_t<U>&&>
|
|
forward_like(U&& u) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<etl::remove_reference_t<U>&&>(u);
|
|
}
|
|
|
|
//***********************************
|
|
// Defines the type that forward_like would cast to.
|
|
//***********************************
|
|
template <typename T, typename U>
|
|
using forward_like_t = decltype(etl::forward_like<T>(etl::declval<U&>()));
|
|
#endif
|
|
|
|
//***********************************
|
|
// Gets the underlying type of an enum.
|
|
//***********************************
|
|
template <typename T>
|
|
ETL_CONSTEXPR typename underlying_type<T>::type to_underlying(T value) ETL_NOEXCEPT
|
|
{
|
|
return static_cast<typename underlying_type<T>::type>(value);
|
|
}
|
|
|
|
// We can't have std::swap and etl::swap templates coexisting in the unit
|
|
// tests as the compiler will be unable to decide which one to use, due to
|
|
// ADL.
|
|
#if ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)
|
|
//***************************************************************************
|
|
// swap
|
|
template <typename T>
|
|
ETL_CONSTEXPR14 void swap(T& a, T& b) ETL_NOEXCEPT
|
|
{
|
|
T temp(ETL_MOVE(a));
|
|
a = ETL_MOVE(b);
|
|
b = ETL_MOVE(temp);
|
|
}
|
|
|
|
template < class T, size_t Size >
|
|
ETL_CONSTEXPR14 void swap(T (&a)[Size], T (&b)[Size]) ETL_NOEXCEPT
|
|
{
|
|
for (size_t i = 0UL; i < Size; ++i)
|
|
{
|
|
swap(a[i], b[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
///\brief pair holds two objects of arbitrary type
|
|
///
|
|
///\tparam T1, T2 The types of the elements that the pair stores
|
|
//***************************************************************************
|
|
template <typename T1, typename T2>
|
|
struct pair
|
|
{
|
|
typedef T1 first_type; ///< @c first_type is the first bound type
|
|
typedef T2 second_type; ///< @c second_type is the second bound type
|
|
|
|
T1 first; ///< @c first is a copy of the first object
|
|
T2 second; ///< @c second is a copy of the second object
|
|
|
|
//***************************************************************************
|
|
///\brief Default constructor
|
|
///
|
|
/// The default constructor creates @c first and @c second using their
|
|
/// respective default constructors.
|
|
//***************************************************************************
|
|
ETL_CONSTEXPR pair()
|
|
: first(T1())
|
|
, second(T2())
|
|
{
|
|
}
|
|
|
|
//***************************************************************************
|
|
///\brief Constructor from parameters
|
|
///
|
|
/// Two objects may be passed to a @c pair constructor to be copied.
|
|
//***************************************************************************
|
|
ETL_CONSTEXPR14 pair(const T1& a, const T2& b)
|
|
: first(a)
|
|
, second(b)
|
|
{
|
|
}
|
|
|
|
#if ETL_USING_CPP11
|
|
//***************************************************************************
|
|
///\brief Move constructor from parameters.
|
|
//***************************************************************************
|
|
template <typename U1, typename U2>
|
|
ETL_CONSTEXPR14 pair(U1&& a, U2&& b)
|
|
: first(etl::forward<U1>(a))
|
|
, second(etl::forward<U2>(b))
|
|
{
|
|
}
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
///\brief Copy constructor
|
|
///
|
|
/// There is also a templated copy constructor for the @c pair class itself.
|
|
//***************************************************************************
|
|
template <typename U1, typename U2>
|
|
ETL_CONSTEXPR14 pair(const pair<U1, U2>& other)
|
|
: first(other.first)
|
|
, second(other.second)
|
|
{
|
|
}
|
|
|
|
/// Copy constructor
|
|
pair(const pair<T1, T2>& other)
|
|
: first(other.first)
|
|
, second(other.second)
|
|
{
|
|
}
|
|
|
|
#if ETL_USING_CPP11
|
|
/// Move constructor
|
|
template <typename U1, typename U2>
|
|
ETL_CONSTEXPR14 pair(pair<U1, U2>&& other)
|
|
: first(etl::forward<U1>(other.first))
|
|
, second(etl::forward<U2>(other.second))
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#if defined(ETL_IN_UNIT_TEST) || ETL_USING_STL
|
|
/// Converting to std::pair
|
|
template <typename U1, typename U2>
|
|
operator std::pair<U1, U2>()
|
|
{
|
|
return std::make_pair(first, second);
|
|
}
|
|
|
|
/// Constructing from std::pair
|
|
template <typename U1, typename U2>
|
|
pair(const std::pair<U1, U2>& other)
|
|
: first(other.first)
|
|
, second(other.second)
|
|
{
|
|
}
|
|
|
|
#if ETL_USING_CPP11
|
|
/// Constructing to etl::pair
|
|
template <typename U1, typename U2>
|
|
pair(std::pair<U1, U2>&& other)
|
|
: first(etl::forward<U1>(other.first))
|
|
, second(etl::forward<U2>(other.second))
|
|
{
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void swap(pair<T1, T2>& other)
|
|
{
|
|
using ETL_OR_STD::swap;
|
|
|
|
swap(first, other.first);
|
|
swap(second, other.second);
|
|
}
|
|
|
|
pair<T1, T2>& operator=(const pair<T1, T2>& other)
|
|
{
|
|
first = other.first;
|
|
second = other.second;
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <typename U1, typename U2>
|
|
pair<U1, U2>& operator=(const pair<U1, U2>& other)
|
|
{
|
|
first = other.first;
|
|
second = other.second;
|
|
|
|
return *this;
|
|
}
|
|
|
|
#if ETL_USING_CPP11
|
|
pair<T1, T2>& operator=(pair<T1, T2>&& other)
|
|
{
|
|
first = etl::forward<T1>(other.first);
|
|
second = etl::forward<T2>(other.second);
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <typename U1, typename U2>
|
|
pair<U1, U2>& operator=(pair<U1, U2>&& other)
|
|
{
|
|
first = etl::forward<U1>(other.first);
|
|
second = etl::forward<U2>(other.second);
|
|
|
|
return *this;
|
|
}
|
|
#endif
|
|
};
|
|
|
|
//***************************************************************************
|
|
///\brief A convenience wrapper for creating a @ref pair from two objects.
|
|
///
|
|
///\param a The first object.
|
|
///\param b The second object.
|
|
///
|
|
///\return A newly-constructed @ref pair object of the appropriate type.
|
|
//***************************************************************************
|
|
#if ETL_USING_CPP11
|
|
template <typename T1, typename T2>
|
|
inline pair<T1, T2> make_pair(T1&& a, T2&& b)
|
|
{
|
|
return pair<T1, T2>(etl::forward<T1>(a), etl::forward<T2>(b));
|
|
}
|
|
#else
|
|
template <typename T1, typename T2>
|
|
inline pair<T1, T2> make_pair(T1 a, T2 b)
|
|
{
|
|
return pair<T1, T2>(a, b);
|
|
}
|
|
#endif
|
|
|
|
#if ETL_USING_CPP11
|
|
//******************************************************************************
|
|
template <size_t Index, typename T1, typename T2>
|
|
struct tuple_element<Index, ETL_OR_STD::pair<T1, T2> >
|
|
{
|
|
ETL_STATIC_ASSERT(Index < 2U, "pair has only 2 elements");
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
struct tuple_element<0U, ETL_OR_STD::pair<T1, T2> >
|
|
{
|
|
typedef T1 type;
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
struct tuple_element<1U, ETL_OR_STD::pair<T1, T2> >
|
|
{
|
|
typedef T2 type;
|
|
};
|
|
|
|
//******************************************************************************
|
|
template <typename T1, typename T2>
|
|
struct tuple_size<ETL_OR_STD::pair<T1, T2>> : public etl::integral_constant<size_t, 2U>
|
|
{
|
|
};
|
|
#endif
|
|
|
|
//******************************************************************************
|
|
template <typename T1, typename T2>
|
|
inline void swap(pair<T1, T2>& a, pair<T1, T2>& b)
|
|
{
|
|
a.swap(b);
|
|
}
|
|
|
|
/// Two pairs of the same type are equal if their members are equal.
|
|
template <typename T1, typename T2>
|
|
inline bool operator==(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
#include "private/diagnostic_float_equal_push.h"
|
|
return (a.first == b.first) && !(a.second < b.second) && !(a.second > b.second);
|
|
#include "private/diagnostic_pop.h"
|
|
}
|
|
|
|
/// Uses @c operator== to find the result.
|
|
template <typename T1, typename T2>
|
|
inline bool operator!=(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
return !(a == b);
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
inline bool operator<(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
return (a.first < b.first) || (!(b.first < a.first) && (a.second < b.second));
|
|
}
|
|
|
|
/// Uses @c operator< to find the result.
|
|
template <typename T1, typename T2>
|
|
inline bool operator>(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
return (b < a);
|
|
}
|
|
|
|
/// Uses @c operator< to find the result.
|
|
template <typename T1, typename T2>
|
|
inline bool operator<=(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
return !(b < a);
|
|
}
|
|
|
|
/// Uses @c operator< to find the result.
|
|
template <typename T1, typename T2>
|
|
inline bool operator>=(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
|
{
|
|
return !(a < b);
|
|
}
|
|
|
|
//***************************************************************************
|
|
///\brief Functor to select @ref pair::first
|
|
///
|
|
///\ref select1st is a functor object that takes a single argument, a @ref
|
|
/// pair, and returns the @ref pair::first
|
|
/// element.
|
|
///
|
|
///\b Example
|
|
///\snippet test_utility.cpp test_select1st_example
|
|
///
|
|
///\tparam TPair The function object's argument type.
|
|
///
|
|
///\see select2nd
|
|
//***************************************************************************
|
|
template <typename TPair>
|
|
struct select1st
|
|
{
|
|
typedef typename TPair::first_type type; ///< type of member @ref pair::first.
|
|
|
|
//***************************************************************************
|
|
///\brief Function call that return @c p.first.
|
|
///\return a reference to member @ref pair::first of the @c pair `p`
|
|
//***************************************************************************
|
|
type& operator()(TPair& p) const
|
|
{
|
|
return p.first;
|
|
}
|
|
|
|
//***************************************************************************
|
|
///\copydoc operator()(TPair&)const
|
|
//
|
|
const type& operator()(const TPair& p) const
|
|
{
|
|
return p.first;
|
|
}
|
|
};
|
|
|
|
//***************************************************************************
|
|
///\brief Functor to select @ref pair::second
|
|
///
|
|
///\ref select2nd is a functor object that takes a single argument, a @ref
|
|
/// pair, and returns the @ref pair::second
|
|
/// element.
|
|
///
|
|
///\b Example
|
|
///\snippet test_utility.cpp test_select2nd_example
|
|
///
|
|
///\tparam TPair The function object's argument type.
|
|
///
|
|
///\see select1st
|
|
//***************************************************************************
|
|
template <typename TPair>
|
|
struct select2nd
|
|
{
|
|
typedef typename TPair::second_type type; ///< type of member @ref pair::second.
|
|
|
|
//***************************************************************************
|
|
///\brief Function call. The return value is `p.second`.
|
|
///\return a reference to member `second` of the pair `p`.
|
|
//***************************************************************************
|
|
type& operator()(TPair& p) const
|
|
{
|
|
return p.second;
|
|
}
|
|
|
|
//***************************************************************************
|
|
///\copydoc operator()(TPair&)const
|
|
//***************************************************************************
|
|
const type& operator()(const TPair& p) const
|
|
{
|
|
return p.second;
|
|
}
|
|
};
|
|
|
|
#if ETL_NOT_USING_STL || ETL_CPP14_NOT_SUPPORTED
|
|
//***************************************************************************
|
|
/// exchange (const)
|
|
//***************************************************************************
|
|
template <typename T>
|
|
T exchange(T& object, const T& new_value)
|
|
{
|
|
T old_value = object;
|
|
object = new_value;
|
|
return old_value;
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
T exchange(T& object, const U& new_value)
|
|
{
|
|
T old_value = object;
|
|
object = new_value;
|
|
return old_value;
|
|
}
|
|
#else
|
|
//***************************************************************************
|
|
/// exchange (const)
|
|
//***************************************************************************
|
|
template <typename T, typename U = T>
|
|
T exchange(T& object, const U& new_value)
|
|
{
|
|
return std::exchange(object, new_value);
|
|
}
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
/// as_const
|
|
//***************************************************************************
|
|
template <typename T>
|
|
typename etl::add_const<T>::type& as_const(T& t)
|
|
{
|
|
return t;
|
|
}
|
|
|
|
//***************************************************************************
|
|
/// integer_sequence
|
|
//***************************************************************************
|
|
#if ETL_USING_CPP11
|
|
template <typename T, T... Integers>
|
|
class integer_sequence
|
|
{
|
|
public:
|
|
|
|
ETL_STATIC_ASSERT(etl::is_integral<T>::value, "Integral types only");
|
|
|
|
typedef T value_type;
|
|
|
|
static ETL_CONSTEXPR size_t size() ETL_NOEXCEPT
|
|
{
|
|
return sizeof...(Integers);
|
|
}
|
|
};
|
|
|
|
namespace private_integer_sequence
|
|
{
|
|
template <size_t Count, typename IndexSeq>
|
|
struct make_index_sequence;
|
|
|
|
template <size_t Count, size_t... Indices>
|
|
struct make_index_sequence<Count, etl::integer_sequence<size_t, Indices...>>
|
|
{
|
|
using type = typename make_index_sequence< Count - 1, etl::integer_sequence<size_t, Count - 1, Indices...>>::type;
|
|
};
|
|
|
|
template <size_t... Indices>
|
|
struct make_index_sequence<0, etl::integer_sequence<size_t, Indices...>>
|
|
{
|
|
using type = etl::integer_sequence<size_t, Indices...>;
|
|
};
|
|
|
|
template <size_t Offset, typename IndexSeq>
|
|
struct offset_index_sequence;
|
|
|
|
template <size_t Offset, size_t... Indices>
|
|
struct offset_index_sequence<Offset, etl::integer_sequence<size_t, Indices...>>
|
|
{
|
|
using type = etl::integer_sequence<size_t, (Offset + Indices)...>;
|
|
};
|
|
} // namespace private_integer_sequence
|
|
|
|
//***********************************
|
|
/// Make an integer sequence.
|
|
//***********************************
|
|
template <size_t Count>
|
|
using make_index_sequence = typename private_integer_sequence::make_index_sequence< Count, etl::integer_sequence<size_t>>::type;
|
|
|
|
//***********************************
|
|
/// Make an integer sequence with an offset.
|
|
//***********************************
|
|
template <size_t Offset, size_t Count>
|
|
using make_index_sequence_with_offset = typename private_integer_sequence::offset_index_sequence< Offset, etl::make_index_sequence<Count>>::type;
|
|
|
|
//***********************************
|
|
// Helper to support both parameter packs and etl::type_list<T...>
|
|
// Forward declare etl::type_list to allow use without including type_list.h
|
|
template <typename... TTypes>
|
|
struct type_list;
|
|
|
|
namespace private_make_index_sequence_for
|
|
{
|
|
// Generic pack form
|
|
template <typename... TTypes>
|
|
struct impl
|
|
{
|
|
using type = typename private_integer_sequence::make_index_sequence< sizeof...(TTypes), etl::integer_sequence<size_t>>::type;
|
|
};
|
|
|
|
// etl::type_list form
|
|
template <typename... TTypes>
|
|
struct impl<etl::type_list<TTypes...>> : impl<TTypes...>
|
|
{
|
|
};
|
|
} // namespace private_make_index_sequence_for
|
|
|
|
//***********************************
|
|
/// Make an index sequence for a parameter pack of types or an
|
|
/// etl::type_list<T...>. Accepts either a parameter pack of types or a single
|
|
/// etl::type_list<T...>
|
|
//***********************************
|
|
template <typename... TTypes>
|
|
using make_index_sequence_for = typename private_make_index_sequence_for::impl<TTypes...>::type;
|
|
|
|
//***********************************
|
|
/// An index sequence.
|
|
//***********************************
|
|
template <size_t... Indices>
|
|
using index_sequence = etl::integer_sequence<size_t, Indices...>;
|
|
|
|
//************************************
|
|
/// Alias for make_index_sequence_for.
|
|
//************************************
|
|
template <typename... TTypes>
|
|
using index_sequence_for = typename etl::make_index_sequence_for<TTypes...>;
|
|
|
|
//************************************
|
|
/// Concatenates two index_sequences.
|
|
//************************************
|
|
template <typename TIndexSequence1, typename TIndexSequence2>
|
|
struct index_sequence_cat;
|
|
|
|
template <size_t... Indices1, size_t... Indices2>
|
|
struct index_sequence_cat<etl::index_sequence<Indices1...>, etl::index_sequence<Indices2...>>
|
|
{
|
|
using type = etl::index_sequence<Indices1..., Indices2...>;
|
|
};
|
|
|
|
template <typename TIndexSequence1, typename TIndexSequence2>
|
|
using index_sequence_cat_t = typename index_sequence_cat<TIndexSequence1, TIndexSequence2>::type;
|
|
|
|
//************************************
|
|
/// Pushes an index to the front of an index_sequence.
|
|
//************************************
|
|
template <typename TIndexSequence, size_t Index>
|
|
struct index_sequence_push_front;
|
|
|
|
template <size_t... Indices, size_t Index>
|
|
struct index_sequence_push_front<etl::index_sequence<Indices...>, Index>
|
|
{
|
|
// Adds the new index to the front of the sequence.
|
|
using type = etl::index_sequence<Index, Indices...>;
|
|
};
|
|
|
|
template <typename TIndexSequence, size_t Index>
|
|
using index_sequence_push_front_t = typename index_sequence_push_front<TIndexSequence, Index>::type;
|
|
|
|
//************************************
|
|
/// Pop an index from the front of an index_sequence.
|
|
//************************************
|
|
template <typename TIndexSequence>
|
|
struct index_sequence_pop_front;
|
|
|
|
template <>
|
|
struct index_sequence_pop_front<etl::index_sequence<>>
|
|
{
|
|
using type = etl::index_sequence<>;
|
|
};
|
|
|
|
template <size_t Index, size_t... Indices>
|
|
struct index_sequence_pop_front<etl::index_sequence<Index, Indices...>>
|
|
{
|
|
// Removes the front index by declaring the type to be the tail of the
|
|
// sequence.
|
|
using type = etl::index_sequence<Indices...>;
|
|
};
|
|
|
|
template <typename TIndexSequence>
|
|
using index_sequence_pop_front_t = typename index_sequence_pop_front<TIndexSequence>::type;
|
|
|
|
//************************************
|
|
/// Pushes an index to the back of an index_sequence.
|
|
//************************************
|
|
template <typename TIndexSequence, size_t Index>
|
|
struct index_sequence_push_back;
|
|
|
|
template <size_t... Indices, size_t Index>
|
|
struct index_sequence_push_back<etl::index_sequence<Indices...>, Index>
|
|
{
|
|
// Adds the new index to the back of the sequence by concatenating the new
|
|
// index with the sequence.
|
|
using type = etl::index_sequence<Indices..., Index>;
|
|
};
|
|
|
|
template <typename TIndexSequence, size_t Index>
|
|
using index_sequence_push_back_t = typename index_sequence_push_back<TIndexSequence, Index>::type;
|
|
|
|
//************************************
|
|
/// Pop an index from the back of an index_sequence.
|
|
//************************************
|
|
template <typename TIndexSequence>
|
|
struct index_sequence_pop_back;
|
|
|
|
// Pop back of and empty sequence is an empty sequence.
|
|
template <>
|
|
struct index_sequence_pop_back<etl::index_sequence<>>
|
|
{
|
|
using type = etl::index_sequence<>;
|
|
};
|
|
|
|
// Pop back of a single element sequence is an empty sequence.
|
|
// The single element is never added to the result, so is effectively removed.
|
|
// This is the terminating specialisation for the general case.
|
|
template <size_t Index>
|
|
struct index_sequence_pop_back<etl::index_sequence<Index>>
|
|
{
|
|
using type = etl::index_sequence<>;
|
|
};
|
|
|
|
// Multi element sequence. Pop back is the front element concatenated with the
|
|
// pop back of the tail.
|
|
template <size_t Index, size_t... Indices>
|
|
struct index_sequence_pop_back<etl::index_sequence<Index, Indices...>>
|
|
{
|
|
// Removes the last index by concatenating the front index with the pop back
|
|
// of the tail. The last index is never added to the result, so is
|
|
// effectively removed.
|
|
using type = etl::index_sequence_cat_t< etl::index_sequence<Index>, typename index_sequence_pop_back<etl::index_sequence<Indices...>>::type>;
|
|
};
|
|
|
|
template <typename TIndexSequence>
|
|
using index_sequence_pop_back_t = typename index_sequence_pop_back<TIndexSequence>::type;
|
|
|
|
//************************************
|
|
/// Gets the index at the Nth position in an index_sequence.
|
|
//************************************
|
|
template <typename TIndexSequence, size_t Nth>
|
|
struct index_sequence_at;
|
|
|
|
template <size_t Nth>
|
|
struct index_sequence_at<etl::index_sequence<>, Nth>
|
|
{
|
|
template <size_t>
|
|
struct dependent_false : etl::false_type
|
|
{
|
|
};
|
|
|
|
static_assert(dependent_false<Nth>::value, "Nth out of range for index_sequence_at");
|
|
};
|
|
|
|
// When Nth is 0, the index at the Nth position is the front index of the
|
|
// sequence.
|
|
template <size_t Index, size_t... Indices>
|
|
struct index_sequence_at<etl::index_sequence<Index, Indices...>, 0>
|
|
{
|
|
static constexpr size_t value = Index;
|
|
};
|
|
|
|
// When Nth is greater than 0, recurse with the tail of the sequence and Nth
|
|
// - 1.
|
|
template <size_t Index, size_t... Indices, size_t Nth>
|
|
struct index_sequence_at<etl::index_sequence<Index, Indices...>, Nth>
|
|
{
|
|
static_assert(Nth < sizeof...(Indices) + 1U, "Nth out of range for index_sequence_at");
|
|
|
|
static constexpr size_t value = index_sequence_at<etl::index_sequence<Indices...>, Nth - 1U>::value;
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <typename TIndexSequence, size_t Nth>
|
|
inline constexpr size_t index_sequence_at_v = index_sequence_at<TIndexSequence, Nth>::value;
|
|
#endif
|
|
|
|
//************************************
|
|
/// Checks if an index_sequence contains a value.
|
|
//************************************
|
|
template <typename TIndexSequence, size_t Value>
|
|
struct index_sequence_contains;
|
|
|
|
// An empty sequence does not contain any value.
|
|
template <size_t Value>
|
|
struct index_sequence_contains<etl::index_sequence<>, Value> : etl::false_type
|
|
{
|
|
};
|
|
|
|
// When the front index of the sequence is the value, the sequence contains
|
|
// the value. When the front index of the sequence is not the value, recurse
|
|
// with the tail of the sequence.
|
|
template <size_t Index, size_t... Indices, size_t Value>
|
|
struct index_sequence_contains<etl::index_sequence<Index, Indices...>, Value>
|
|
: etl::integral_constant< bool, (Index == Value) || index_sequence_contains<etl::index_sequence<Indices...>, Value>::value>
|
|
{
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <typename TIndexSequence, size_t Value>
|
|
inline constexpr bool index_sequence_contains_v = index_sequence_contains<TIndexSequence, Value>::value;
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
/// Defines a new index_sequence by removing duplicate indexes from a given
|
|
/// index_sequence, preserving the first occurrence.
|
|
//***************************************************************************
|
|
namespace private_index_sequence
|
|
{
|
|
template <typename TIndexSequence, typename TUniqueIndices>
|
|
struct type_index_sequence_impl;
|
|
|
|
// When the front index of the sequence is not in the unique sequence, add
|
|
// it to the back of the unique sequence and recurse with the tail of the
|
|
// sequence.
|
|
template <size_t Index, size_t... Indices, size_t... UniqueIndices>
|
|
struct type_index_sequence_impl<etl::index_sequence<Index, Indices...>, etl::index_sequence<UniqueIndices...>>
|
|
{
|
|
// If the index is already in the unique sequence, do not add it again.
|
|
// Otherwise, add it to the back of the unique sequence.
|
|
using type =
|
|
typename etl::conditional_t< etl::index_sequence_contains<etl::index_sequence<UniqueIndices...>, Index>::value,
|
|
type_index_sequence_impl<etl::index_sequence<Indices...>, etl::index_sequence<UniqueIndices...>>,
|
|
type_index_sequence_impl< etl::index_sequence<Indices...>,
|
|
etl::index_sequence_push_back_t<etl::index_sequence<UniqueIndices...>, Index>>>::type;
|
|
};
|
|
|
|
// When the sequence is empty, the unique sequence is the result.
|
|
template <size_t... UniqueIndices>
|
|
struct type_index_sequence_impl<etl::index_sequence<>, etl::index_sequence<UniqueIndices...>>
|
|
{
|
|
using type = etl::index_sequence<UniqueIndices...>;
|
|
};
|
|
} // namespace private_index_sequence
|
|
|
|
template <typename T>
|
|
struct index_sequence_unique;
|
|
|
|
template <size_t... Indices>
|
|
struct index_sequence_unique<etl::index_sequence<Indices...>>
|
|
{
|
|
using type = typename private_index_sequence::type_index_sequence_impl< etl::index_sequence<Indices...>, etl::index_sequence<>>::type;
|
|
};
|
|
|
|
#if ETL_USING_CPP11
|
|
template <typename TIndexSequence>
|
|
using index_sequence_unique_t = typename etl::index_sequence_unique<TIndexSequence>::type;
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
/// Checks that all of the indices in an index_sequence are unique.
|
|
//***************************************************************************
|
|
template <typename T>
|
|
struct index_sequence_is_unique;
|
|
|
|
template <size_t... Indices>
|
|
struct index_sequence_is_unique<etl::index_sequence<Indices...>>
|
|
: etl::bool_constant< etl::is_same< etl::index_sequence<Indices...>, etl::index_sequence_unique_t<etl::index_sequence<Indices...>>>::value>
|
|
{
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <typename TIndexSequence>
|
|
inline constexpr bool index_sequence_is_unique_v = index_sequence_is_unique<TIndexSequence>::type::value;
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
/// Checks if the index_sequence is empty.
|
|
//***************************************************************************
|
|
template <typename T>
|
|
struct index_sequence_is_empty;
|
|
|
|
template <>
|
|
struct index_sequence_is_empty<etl::index_sequence<>> : etl::true_type
|
|
{
|
|
};
|
|
|
|
template <size_t... Indices>
|
|
struct index_sequence_is_empty<etl::index_sequence<Indices...>> : etl::false_type
|
|
{
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <typename... TTypes>
|
|
inline constexpr bool index_sequence_is_empty_v = index_sequence_is_empty<TTypes...>::value;
|
|
#endif
|
|
#endif
|
|
|
|
//***************************************************************************
|
|
/// 2D coordinate type.
|
|
//***************************************************************************
|
|
template <typename T>
|
|
struct coordinate_2d
|
|
{
|
|
coordinate_2d()
|
|
: x(T(0))
|
|
, y(T(0))
|
|
{
|
|
}
|
|
|
|
coordinate_2d(T x_, T y_)
|
|
: x(x_)
|
|
, y(y_)
|
|
{
|
|
}
|
|
|
|
friend bool operator==(const coordinate_2d& lhs, const coordinate_2d& rhs)
|
|
{
|
|
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
|
|
}
|
|
|
|
friend bool operator!=(const coordinate_2d& lhs, const coordinate_2d& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
T x;
|
|
T y;
|
|
};
|
|
|
|
//***************************************************************************
|
|
/// in_place disambiguation tags.
|
|
//***************************************************************************
|
|
|
|
//*************************
|
|
struct in_place_t
|
|
{
|
|
explicit ETL_CONSTEXPR in_place_t() {}
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
inline constexpr in_place_t in_place{};
|
|
#endif
|
|
|
|
//*************************
|
|
template <typename T>
|
|
struct in_place_type_t
|
|
{
|
|
explicit ETL_CONSTEXPR in_place_type_t() {}
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <typename T>
|
|
inline constexpr in_place_type_t<T> in_place_type{};
|
|
#endif
|
|
|
|
//*************************
|
|
template <size_t Index>
|
|
struct in_place_index_t
|
|
{
|
|
explicit ETL_CONSTEXPR in_place_index_t() {}
|
|
};
|
|
|
|
#if ETL_USING_CPP17
|
|
template <size_t Index>
|
|
inline constexpr in_place_index_t<Index> in_place_index{};
|
|
#endif
|
|
|
|
#if ETL_USING_CPP11
|
|
//*************************************************************************
|
|
// A function wrapper for free/global functions.
|
|
// Deprecated.
|
|
// See etl::function_ptr_as_functor for a runtime time wrapper option.
|
|
// See etl::function_as_functor for a compile time wrapper option.
|
|
//*************************************************************************
|
|
template <typename TReturn, typename... TParams>
|
|
class ETL_DEPRECATED functor
|
|
{
|
|
public:
|
|
|
|
//*********************************
|
|
/// Constructor.
|
|
//*********************************
|
|
constexpr functor(TReturn (*ptr_)(TParams...))
|
|
: ptr(ptr_)
|
|
{
|
|
}
|
|
|
|
//*********************************
|
|
/// Const function operator.
|
|
//*********************************
|
|
constexpr TReturn operator()(TParams... args) const
|
|
{
|
|
return ptr(etl::forward<TParams>(args)...);
|
|
}
|
|
|
|
private:
|
|
|
|
/// The pointer to the function.
|
|
TReturn (*ptr)(TParams...);
|
|
};
|
|
|
|
//*****************************************************************************
|
|
// Wrap a member function with a static free function.
|
|
// Creates a static member function that calls the specified member function.
|
|
// Deprecated
|
|
// See etl::member_function_as_static
|
|
//*****************************************************************************
|
|
template <typename T>
|
|
class member_function_wrapper;
|
|
|
|
template <typename TReturn, typename... TParams>
|
|
class ETL_DEPRECATED member_function_wrapper<TReturn(TParams...)>
|
|
{
|
|
public:
|
|
|
|
template <typename T, T& Instance, TReturn (T::*Method)(TParams...)>
|
|
static constexpr TReturn function(TParams... params)
|
|
{
|
|
return (Instance.*Method)(etl::forward<TParams>(params)...);
|
|
}
|
|
};
|
|
|
|
//*****************************************************************************
|
|
// Wrap a functor with a static free function.
|
|
// Creates a static member function that calls the specified functor.
|
|
// Deprecated
|
|
// See etl::functor_as_static
|
|
//*****************************************************************************
|
|
template <typename T>
|
|
class functor_wrapper;
|
|
|
|
template <typename TReturn, typename... TParams>
|
|
class functor_wrapper<TReturn(TParams...)>
|
|
{
|
|
public:
|
|
|
|
template <typename TFunctor, TFunctor& Instance>
|
|
static constexpr TReturn function(TParams... params)
|
|
{
|
|
return Instance(etl::forward<TParams>(params)...);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if ETL_USING_CPP17
|
|
//*****************************************************************************
|
|
// Wraps a functor with a static free function at compile time.
|
|
// Creates a static member 'call' that calls the specified functor.
|
|
//*****************************************************************************
|
|
template <auto& Instance>
|
|
struct functor_as_static
|
|
{
|
|
template <typename... TArgs>
|
|
static constexpr auto call(TArgs&&... args)
|
|
{
|
|
return (Instance.operator())(etl::forward<TArgs>(args)...);
|
|
}
|
|
};
|
|
|
|
//*****************************************************************************
|
|
// Wraps a member function with a static free function at compile time.
|
|
// Creates a static member 'call' that calls the specified member function.
|
|
//*****************************************************************************
|
|
template <auto Method, auto& Instance>
|
|
struct member_function_as_static
|
|
{
|
|
template <typename... TArgs>
|
|
static constexpr auto call(TArgs&&... args)
|
|
{
|
|
return (Instance.*Method)(etl::forward<TArgs>(args)...);
|
|
}
|
|
};
|
|
|
|
//*****************************************************************************
|
|
// Wraps a member function with a functor at compile time.
|
|
// Creates a functor that calls the specified member function.
|
|
//*****************************************************************************
|
|
template <auto Method, auto& Instance>
|
|
class member_function_as_functor
|
|
{
|
|
public:
|
|
|
|
template <typename... TArgs>
|
|
constexpr auto operator()(TArgs&&... args) const -> decltype((Instance.*Method)(etl::forward<TArgs>(args)...))
|
|
{
|
|
return (Instance.*Method)(etl::forward<TArgs>(args)...);
|
|
}
|
|
};
|
|
|
|
//*****************************************************************************
|
|
// Wraps a function with a functor at compile time.
|
|
// Creates a functor that calls the specified free function.
|
|
//*****************************************************************************
|
|
template <auto Function>
|
|
class function_as_functor
|
|
{
|
|
public:
|
|
|
|
template <typename... TArgs>
|
|
constexpr auto operator()(TArgs&&... args) const -> decltype(Function(etl::forward<TArgs>(args)...))
|
|
{
|
|
return Function(etl::forward<TArgs>(args)...);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if ETL_USING_CPP11
|
|
//*****************************************************************************
|
|
// Wraps a function pointer with a functor at run time.
|
|
// Creates a functor that calls the specified free function.
|
|
//*****************************************************************************
|
|
template <typename T>
|
|
class function_ptr_as_functor;
|
|
|
|
template <typename TReturn, typename... TArgs>
|
|
class function_ptr_as_functor<TReturn(TArgs...)>
|
|
{
|
|
public:
|
|
|
|
//*********************************
|
|
/// Constructor.
|
|
//*********************************
|
|
constexpr function_ptr_as_functor(TReturn (*ptr_)(TArgs...))
|
|
: ptr(ptr_)
|
|
{
|
|
}
|
|
|
|
//*********************************
|
|
/// Const function operator.
|
|
//*********************************
|
|
constexpr TReturn operator()(TArgs... args) const
|
|
{
|
|
return ptr(etl::forward<TArgs>(args)...);
|
|
}
|
|
|
|
private:
|
|
|
|
/// The pointer to the function.
|
|
TReturn (*ptr)(TArgs...);
|
|
};
|
|
#endif
|
|
|
|
#if ETL_USING_CPP17 && !defined(ETL_FORCE_CPP11_NONTYPE)
|
|
//*****************************************************************************
|
|
// Wraps a non-type template parameter as a type.
|
|
//*****************************************************************************
|
|
template <auto Value>
|
|
struct nontype_t
|
|
{
|
|
static constexpr decltype(Value) value = Value;
|
|
};
|
|
#elif ETL_USING_CPP11
|
|
//*****************************************************************************
|
|
// Wraps a non-type template parameter as a type.
|
|
//*****************************************************************************
|
|
template <typename T, T Value>
|
|
struct nontype_t
|
|
{
|
|
static constexpr T value = Value;
|
|
};
|
|
#endif
|
|
} // namespace etl
|
|
|
|
#endif
|