DEV: meta reshape
This commit is contained in:
parent
5f6eef3478
commit
984a073f29
@ -689,17 +689,18 @@ namespace _1wire_i_det {
|
|||||||
meta::void_t <
|
meta::void_t <
|
||||||
// typename _Tp::Speed,
|
// typename _Tp::Speed,
|
||||||
// typename _Tp::Command,
|
// typename _Tp::Command,
|
||||||
meta::use_if_same_t <try_reset_t <_Tp>, bool>,
|
// meta::use_if_same_t <try_reset_t <_Tp>, bool>,
|
||||||
meta::use_if_same_t <try_rx1_t <_Tp>, byte_t>,
|
// meta::use_if_same_t <try_rx1_t <_Tp>, byte_t>,
|
||||||
//meta::use_if_same_t <try_rx2_t <_Tp>, size_t>,
|
// //meta::use_if_same_t <try_rx2_t <_Tp>, size_t>,
|
||||||
meta::use_if_same_t <try_tx1_t <_Tp>, byte_t>,
|
// meta::use_if_same_t <try_tx1_t <_Tp>, byte_t>,
|
||||||
//meta::use_if_same_t <try_tx2_t <_Tp>, size_t>,
|
// //meta::use_if_same_t <try_tx2_t <_Tp>, size_t>,
|
||||||
meta::use_if_same_t <try_match_t<_Tp>, void>,
|
// meta::use_if_same_t <try_match_t<_Tp>, void>,
|
||||||
meta::use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
|
// meta::use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
|
||||||
meta::use_if_same_t <try_skip_t<_Tp>, void>,
|
// meta::use_if_same_t <try_skip_t<_Tp>, void>,
|
||||||
meta::use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
|
// meta::use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
|
||||||
meta::use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
|
// meta::use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
|
||||||
meta::use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
|
// meta::use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
|
||||||
|
void
|
||||||
> //!^ SFINAE may apply
|
> //!^ SFINAE may apply
|
||||||
> : meta::true_ {};
|
> : meta::true_ {};
|
||||||
} // namespace _1wire_i_det
|
} // namespace _1wire_i_det
|
||||||
|
@ -261,12 +261,13 @@ namespace utl {
|
|||||||
struct is_i2c_ <_Tp,
|
struct is_i2c_ <_Tp,
|
||||||
meta::void_t <
|
meta::void_t <
|
||||||
typename _Tp::Sequence,
|
typename _Tp::Sequence,
|
||||||
meta::use_if_same_t <uint32_t,try_cclk_t <_Tp>>,
|
// meta::use_if_same_t <uint32_t,try_cclk_t <_Tp>>,
|
||||||
meta::use_if_same_t <void, try_clk_t <_Tp>>,
|
// meta::use_if_same_t <void, try_clk_t <_Tp>>,
|
||||||
meta::use_if_same_t <void, try_start_t <_Tp>>,
|
// meta::use_if_same_t <void, try_start_t <_Tp>>,
|
||||||
meta::use_if_same_t <void, try_stop_t <_Tp>>,
|
// meta::use_if_same_t <void, try_stop_t <_Tp>>,
|
||||||
meta::use_if_same_t <byte_t, try_rx_data_t <_Tp>>,
|
// meta::use_if_same_t <byte_t, try_rx_data_t <_Tp>>,
|
||||||
meta::use_if_same_t <bool, try_tx_data_t <_Tp>>
|
// meta::use_if_same_t <bool, try_tx_data_t <_Tp>>
|
||||||
|
void
|
||||||
>
|
>
|
||||||
> : meta::true_ { };
|
> : meta::true_ { };
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,9 @@ namespace utl {
|
|||||||
//! \name SPI implementation specific functions
|
//! \name SPI implementation specific functions
|
||||||
//!@{
|
//!@{
|
||||||
template <spi::bitOrder B =BitOrder> constexpr
|
template <spi::bitOrder B =BitOrder> constexpr
|
||||||
meta::use_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
|
meta::enable_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
|
||||||
template <spi::bitOrder B =BitOrder> constexpr
|
template <spi::bitOrder B =BitOrder> constexpr
|
||||||
meta::use_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
|
meta::enable_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
|
||||||
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
|
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
|
||||||
return !static_cast<bool>(C);
|
return !static_cast<bool>(C);
|
||||||
}
|
}
|
||||||
@ -113,9 +113,9 @@ namespace utl {
|
|||||||
byte_t _tx_data (byte_t out) { return _tx_data_impl (out); }
|
byte_t _tx_data (byte_t out) { return _tx_data_impl (out); }
|
||||||
|
|
||||||
template <spi::cpha C =CPHA>
|
template <spi::cpha C =CPHA>
|
||||||
meta::use_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
|
meta::enable_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
|
||||||
template <spi::cpha C =CPHA>
|
template <spi::cpha C =CPHA>
|
||||||
meta::use_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
|
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
|
||||||
//!@}
|
//!@}
|
||||||
|
|
||||||
//! Data members
|
//! Data members
|
||||||
@ -134,7 +134,7 @@ namespace utl {
|
|||||||
*/
|
*/
|
||||||
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
||||||
template <spi::cpha C>
|
template <spi::cpha C>
|
||||||
meta::use_if_t <(C == spi::cpha::LOW), byte_t>
|
meta::enable_if_t <(C == spi::cpha::LOW), byte_t>
|
||||||
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
||||||
byte_t in {};
|
byte_t in {};
|
||||||
SCLK (clkL_);
|
SCLK (clkL_);
|
||||||
@ -158,7 +158,7 @@ namespace utl {
|
|||||||
*/
|
*/
|
||||||
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
||||||
template <spi::cpha C>
|
template <spi::cpha C>
|
||||||
meta::use_if_t <(C == spi::cpha::HIGH), byte_t>
|
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t>
|
||||||
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
||||||
byte_t in {};
|
byte_t in {};
|
||||||
SCLK (clkL_);
|
SCLK (clkL_);
|
||||||
@ -207,9 +207,9 @@ namespace utl {
|
|||||||
//! \name SPI implementation specific functions
|
//! \name SPI implementation specific functions
|
||||||
//!@{
|
//!@{
|
||||||
template <spi::bitOrder B =BitOrder> constexpr
|
template <spi::bitOrder B =BitOrder> constexpr
|
||||||
meta::use_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
|
meta::enable_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
|
||||||
template <spi::bitOrder B =BitOrder> constexpr
|
template <spi::bitOrder B =BitOrder> constexpr
|
||||||
meta::use_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
|
meta::enable_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
|
||||||
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
|
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
|
||||||
return !static_cast<bool>(C);
|
return !static_cast<bool>(C);
|
||||||
}
|
}
|
||||||
@ -241,9 +241,9 @@ namespace utl {
|
|||||||
byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); }
|
byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); }
|
||||||
|
|
||||||
template <spi::cpha C =CPHA>
|
template <spi::cpha C =CPHA>
|
||||||
meta::use_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
|
meta::enable_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
|
||||||
template <spi::cpha C =CPHA>
|
template <spi::cpha C =CPHA>
|
||||||
meta::use_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
|
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
|
||||||
//!@}
|
//!@}
|
||||||
|
|
||||||
//! Data members
|
//! Data members
|
||||||
@ -262,7 +262,7 @@ namespace utl {
|
|||||||
*/
|
*/
|
||||||
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
||||||
template <spi::cpha C>
|
template <spi::cpha C>
|
||||||
meta::use_if_t <(C == spi::cpha::LOW), byte_t>
|
meta::enable_if_t <(C == spi::cpha::LOW), byte_t>
|
||||||
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
||||||
byte_t in {};
|
byte_t in {};
|
||||||
SCLK (clkL_);
|
SCLK (clkL_);
|
||||||
@ -286,7 +286,7 @@ namespace utl {
|
|||||||
*/
|
*/
|
||||||
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
|
||||||
template <spi::cpha C>
|
template <spi::cpha C>
|
||||||
meta::use_if_t <(C == spi::cpha::HIGH), byte_t>
|
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t>
|
||||||
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
|
||||||
byte_t in {};
|
byte_t in {};
|
||||||
SCLK (clkL_);
|
SCLK (clkL_);
|
||||||
|
@ -47,6 +47,14 @@ namespace utl {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using _ref_t = std::add_lvalue_reference_t<T>;
|
using _ref_t = std::add_lvalue_reference_t<T>;
|
||||||
|
|
||||||
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
|
using use_if_same_t = meta::eval<
|
||||||
|
meta::enable_if<
|
||||||
|
meta::same_<_T1, _T2>::value, _Ret
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Same
|
* Same
|
||||||
*/
|
*/
|
||||||
@ -501,6 +509,23 @@ namespace utl {
|
|||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
namespace details {
|
namespace details {
|
||||||
|
// template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
|
||||||
|
// template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
|
||||||
|
// template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
|
||||||
|
// template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
|
||||||
|
// template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
|
||||||
|
//
|
||||||
|
// template <typename B>
|
||||||
|
// struct is_boolean__ {
|
||||||
|
// using type = meta::and_ <
|
||||||
|
// meta::is_detected<B, try_op_not_>,
|
||||||
|
// meta::is_detected<B, try_op_eq_>,
|
||||||
|
// meta::is_detected<B, try_op_neq_>,
|
||||||
|
// meta::is_detected<B, try_op_and_>,
|
||||||
|
// meta::is_detected<B, try_op_or_>
|
||||||
|
// >;
|
||||||
|
// };
|
||||||
|
|
||||||
template <typename B, typename = void>
|
template <typename B, typename = void>
|
||||||
struct is_boolean_ {
|
struct is_boolean_ {
|
||||||
using type = meta::false_;
|
using type = meta::false_;
|
||||||
|
@ -425,10 +425,11 @@ namespace utl {
|
|||||||
typename _Tp::difference_type,
|
typename _Tp::difference_type,
|
||||||
typename _Tp::pointer,
|
typename _Tp::pointer,
|
||||||
typename _Tp::reference,
|
typename _Tp::reference,
|
||||||
meta::use_if_same_t <
|
// meta::use_if_same_t <
|
||||||
typename _Tp::iterator_category,
|
// typename _Tp::iterator_category,
|
||||||
std::output_iterator_tag
|
// std::output_iterator_tag
|
||||||
>
|
// >
|
||||||
|
void
|
||||||
>
|
>
|
||||||
> : meta::true_ {};
|
> : meta::true_ {};
|
||||||
}
|
}
|
||||||
@ -702,10 +703,11 @@ namespace utl {
|
|||||||
typename _Tp::difference_type,
|
typename _Tp::difference_type,
|
||||||
typename _Tp::pointer,
|
typename _Tp::pointer,
|
||||||
typename _Tp::reference,
|
typename _Tp::reference,
|
||||||
meta::use_if_same_t <
|
// meta::use_if_same_t <
|
||||||
typename _Tp::iterator_category,
|
// typename _Tp::iterator_category,
|
||||||
std::input_iterator_tag
|
// std::input_iterator_tag
|
||||||
>
|
// >
|
||||||
|
void
|
||||||
>
|
>
|
||||||
> : meta::true_ {};
|
> : meta::true_ {};
|
||||||
}
|
}
|
||||||
@ -986,10 +988,11 @@ namespace utl {
|
|||||||
typename _Tp::difference_type,
|
typename _Tp::difference_type,
|
||||||
typename _Tp::pointer,
|
typename _Tp::pointer,
|
||||||
typename _Tp::reference,
|
typename _Tp::reference,
|
||||||
meta::use_if_same_t <
|
// meta::use_if_same_t <
|
||||||
typename _Tp::iterator_category,
|
// typename _Tp::iterator_category,
|
||||||
std::input_iterator_tag
|
// std::input_iterator_tag
|
||||||
>
|
// >
|
||||||
|
void
|
||||||
>
|
>
|
||||||
> : meta::true_ {};
|
> : meta::true_ {};
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file detection.h
|
* \file detection.h
|
||||||
* \brief Detection idiom based on WG21's N4502[1] from Walter E. Brown
|
* \brief Detection idiom based on WG21's N4502 [\ref n4502 1] from Walter E. Brown
|
||||||
*
|
*
|
||||||
* [1]: www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
|
* \anchor n4502 [1]: www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
*
|
*
|
||||||
@ -23,7 +23,7 @@
|
|||||||
#define __utl_meta_detection_h__
|
#define __utl_meta_detection_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/logical.h>
|
#include <utl/meta/operations.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -57,7 +57,8 @@ namespace meta {
|
|||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Not a type to use in detected idiom
|
* Not a type to use in detected idiom. This type can
|
||||||
|
* not be constructed, destructed or copied
|
||||||
*/
|
*/
|
||||||
struct nat_ {
|
struct nat_ {
|
||||||
nat_() = delete;
|
nat_() = delete;
|
||||||
@ -108,11 +109,9 @@ namespace meta {
|
|||||||
* \example
|
* \example
|
||||||
* \code
|
* \code
|
||||||
* // archetypal alias for a copy assignment operation
|
* // archetypal alias for a copy assignment operation
|
||||||
* template< class T >
|
* template< class T > using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
|
||||||
* using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
|
|
||||||
*
|
*
|
||||||
* template< class T >
|
* template< class T > using is_copy_assignable = is_detected< copy_assign_t, T >;
|
||||||
* using is_copy_assignable = is_detected< T, copy_assign_t >;
|
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
template <template<typename...> class Op, typename... Args>
|
template <template<typename...> class Op, typename... Args>
|
||||||
@ -121,41 +120,115 @@ namespace meta {
|
|||||||
//! Detection predicate
|
//! Detection predicate
|
||||||
template< template<typename...> class Op, typename... Args>
|
template< template<typename...> class Op, typename... Args>
|
||||||
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
|
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
|
||||||
//! @}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Detection idiom toolkit
|
* Detection tool that evaluates to Op<Args...> if it's valid and to nat_ if not
|
||||||
|
*
|
||||||
|
* \param Op metafunction detector
|
||||||
|
* \param Args... The arguments to pass to \p Op and check if is well formed
|
||||||
|
* \return The result type
|
||||||
|
* \arg Op<Args...> if is well formed
|
||||||
|
* \arg nat_ if Op<Args...> is ill formed
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* template <typename T> using try_type = typename T::type; // detector
|
||||||
|
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
|
||||||
|
* static_assert( std::is_same<nat_, detected_t<try_type, A<int>> >(), ""); // detection failed
|
||||||
|
* static_assert( std::is_same<A<int>&, detected_t<try_ppT, A<int>> >(), ""); // detection succeed
|
||||||
|
*
|
||||||
|
* // if mFun<int, int> is well formed
|
||||||
|
* static_assert(std::is_same< mFun<int, int>, detected_t<mFun, int, int> >(), "");
|
||||||
|
* \endcode
|
||||||
*/
|
*/
|
||||||
//! @{
|
|
||||||
|
|
||||||
//! evaluates to evaluation of Op<Args...> if it's valid and to nat_ if not
|
|
||||||
template <template<typename...> class Op, typename... Args>
|
template <template<typename...> class Op, typename... Args>
|
||||||
using detected_t = eval <
|
using detected_t = eval <
|
||||||
detail::detector<nat_, void, Op, Args...>
|
detail::detector<nat_, void, Op, Args...>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! evaluates to evaluation of Op<Args...> if it's valid and to \p Default if not
|
/*!
|
||||||
|
* Detection tool that evaluates to Op<Args...> if it's valid and to \p Default if not
|
||||||
|
*
|
||||||
|
* \param Default The resulting type if detection fail
|
||||||
|
* \param Op metafunction detector
|
||||||
|
* \param Args... The arguments to pass to \p Op and check if is well formed
|
||||||
|
* \return The result type
|
||||||
|
* \arg Op<Args...> if is well formed
|
||||||
|
* \arg Default if Op<Args...> is ill formed
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* template <typename T> using try_type = typename T::type; // detector
|
||||||
|
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
|
||||||
|
* static_assert( std::is_same<Foo, detected_or_t<Foo, try_type, A<int>> >(), ""); // detection failed
|
||||||
|
* static_assert( std::is_same<A<int>&, detected_or_t<Foo, try_ppT, A<int>> >(), ""); // detection succeed
|
||||||
|
*
|
||||||
|
* // if mFun<int, int> is well formed
|
||||||
|
* static_assert(std::is_same< mFun<int, int>, detected_or_t<void, mFun, int, int> >(), "");
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
template <typename Default,
|
template <typename Default,
|
||||||
template<typename...> class Op, typename... Args>
|
template<typename...> class Op, typename... Args>
|
||||||
using detected_or_t = eval <
|
using detected_or_t = eval <
|
||||||
detail::detected_or<Default, Op, Args...>
|
detail::detected_or<Default, Op, Args...>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! evaluates to true_ if evaluation of Op<Args...> is \p Expected and to false_ if not
|
/*!
|
||||||
|
* Detection tool that evaluates to true_ if evaluation of Op<Args...>
|
||||||
|
* is \p Expected and to false_ if not
|
||||||
|
*
|
||||||
|
* \param Expected The expected resulting type if detection succeed
|
||||||
|
* \param Op metafunction detector
|
||||||
|
* \param Args... The arguments to pass to \p Op and check if is well formed
|
||||||
|
* \return The result type
|
||||||
|
* \arg true_ if Op<Args...> is well formed and evaluate to Expected
|
||||||
|
* \arg false_ Any other case
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* template <typename T> using try_type = typename T::type; // detector
|
||||||
|
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
|
||||||
|
* static_assert( std::is_same<false_, is_detected_exact<int, try_type, A<int>> >(), ""); // detection failed
|
||||||
|
* static_assert( std::is_same<true_, is_detected_exact<A<int>&, try_ppT, A<int>> >(), ""); // detection succeed
|
||||||
|
*
|
||||||
|
* // if mFun<int, int> is well formed
|
||||||
|
* static_assert(std::is_same< true_, is_detected_exact<mFun<int, int>, mFun, int, int> >(), "");
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
template <typename Expected,
|
template <typename Expected,
|
||||||
template<typename...> class Op, typename... Args >
|
template<typename...> class Op, typename... Args >
|
||||||
using is_detected_exact = same_<Expected, detected_t<Op, Args...> >;
|
using is_detected_exact = eval <
|
||||||
|
same_<Expected, detected_t<Op, Args...>>
|
||||||
|
>;
|
||||||
|
|
||||||
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
|
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
|
||||||
template <typename Expected,
|
template <typename Expected,
|
||||||
template<typename...> class Op, typename... Args >
|
template<typename...> class Op, typename... Args >
|
||||||
constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
|
constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
|
||||||
|
|
||||||
//! evaluates to true_ if evaluation of Op<Args...> is convertible to \p To
|
/*!
|
||||||
//! and to false_ if not
|
* Detection tool that evaluates to true_ if evaluation of Op<Args...> is convertible
|
||||||
|
* to \p To and to false_ if not
|
||||||
|
*
|
||||||
|
* \param To The to convert to if detection succeed
|
||||||
|
* \param Op metafunction detector
|
||||||
|
* \param Args... The arguments to pass to \p Op and check if is well formed
|
||||||
|
* \return The result type
|
||||||
|
* \arg true_ if Op<Args...> is well formed and convertible to To
|
||||||
|
* \arg false_ Any other case
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* template <typename T> using try_type = typename T::type; // detector
|
||||||
|
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
|
||||||
|
* static_assert( std::is_same<false_, is_detected_convertible<Foo, try_type, A<int>> >(), ""); // detection failed
|
||||||
|
* static_assert( std::is_same<true_, is_detected_convertible<A<int>&&, try_ppT, A<int>> >(), "");// detection succeed
|
||||||
|
*
|
||||||
|
* // if mFun<int, int> is well formed but not convertible to Foo
|
||||||
|
* static_assert(std::is_same< false_, is_detected_convertible<Foo, mFun, int, int> >(), "");
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
template <typename To,
|
template <typename To,
|
||||||
template<typename...> class Op, typename... Args >
|
template<typename...> class Op, typename... Args >
|
||||||
using is_detected_convertible = std::is_convertible< detected_t<Op, Args...>, To >;
|
using is_detected_convertible = eval <
|
||||||
|
std::is_convertible< detected_t<Op, Args...>, To >
|
||||||
|
>;
|
||||||
|
|
||||||
//! evaluates to true if evaluation of Op<Args...> is convertible to \p To
|
//! evaluates to true if evaluation of Op<Args...> is convertible to \p To
|
||||||
//! and to false if not
|
//! and to false if not
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
/*!
|
|
||||||
* \file pack.h
|
|
||||||
* \brief Template meta-programming parameter pack container
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifndef __utl_meta_idx_sequence_h__
|
|
||||||
#define __utl_meta_idx_sequence_h__
|
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
|
||||||
#include <utl/meta/integral.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \ingroup meta
|
|
||||||
* \defgroup index_sequence
|
|
||||||
*/
|
|
||||||
//! @{
|
|
||||||
|
|
||||||
namespace utl {
|
|
||||||
namespace meta {
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Class template integer_sequence
|
|
||||||
*/
|
|
||||||
template<typename _Tp, _Tp... _Idx>
|
|
||||||
struct integer_sequence {
|
|
||||||
using value_type = _Tp;
|
|
||||||
static constexpr size_t size() noexcept {
|
|
||||||
return sizeof...(_Idx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Alias template index_sequence
|
|
||||||
template<index_t... _Idx>
|
|
||||||
using index_sequence = integer_sequence<index_t, _Idx...>;
|
|
||||||
|
|
||||||
//! make_integer_sequence
|
|
||||||
//! @{
|
|
||||||
namespace detail {
|
|
||||||
// Stores a tuple of indices
|
|
||||||
template<size_t... Idxs> struct index_tuple { };
|
|
||||||
|
|
||||||
// Concatenates two index_tuples.
|
|
||||||
template<typename It1, typename It2> struct it_cat_;
|
|
||||||
|
|
||||||
template<size_t... It1, size_t... It2>
|
|
||||||
struct it_cat_ <index_tuple<It1...>, index_tuple<It2...>> {
|
|
||||||
using type = index_tuple<It1..., (It2 + sizeof...(It1))...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Builds an index_tuple<0, 1, 2, ..., _Num-1>.
|
|
||||||
template<size_t _Num>
|
|
||||||
struct make_index_tuple_
|
|
||||||
: it_cat_<eval<make_index_tuple_<_Num / 2>>,
|
|
||||||
eval<make_index_tuple_<_Num - _Num / 2>>>
|
|
||||||
{ };
|
|
||||||
// termination specialization for 1
|
|
||||||
template<>
|
|
||||||
struct make_index_tuple_<1> {
|
|
||||||
using type = index_tuple<0>;
|
|
||||||
};
|
|
||||||
// termination specialization for 0
|
|
||||||
template<>
|
|
||||||
struct make_index_tuple_<0> {
|
|
||||||
using type = index_tuple<>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// factory type
|
|
||||||
template<typename _Tp, _Tp _Num,
|
|
||||||
typename _ISeq = eval<make_index_tuple_<_Num>>>
|
|
||||||
struct make_integer_sequence_;
|
|
||||||
|
|
||||||
template<typename _Tp, _Tp _Num, size_t... _Idx>
|
|
||||||
struct make_integer_sequence_<_Tp, _Num, index_tuple<_Idx...>> {
|
|
||||||
static_assert( _Num >= 0,
|
|
||||||
"Cannot make integer sequence of negative length" );
|
|
||||||
using type = integer_sequence<_Tp, static_cast<_Tp>(_Idx)...>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//! Alias template make_integer_sequence
|
|
||||||
//! Complexity \f$ O(log N) \f$
|
|
||||||
template<typename _Tp, _Tp N>
|
|
||||||
using make_integer_sequence = eval<detail::make_integer_sequence_<_Tp, N>>;
|
|
||||||
|
|
||||||
//! Alias template make_index_sequence
|
|
||||||
//! Complexity \f$ O(log N) \f$
|
|
||||||
template<index_t N>
|
|
||||||
using make_index_sequence = make_integer_sequence<index_t, N>;
|
|
||||||
|
|
||||||
//! Alias template index_sequence_for
|
|
||||||
//! Complexity \f$ O(log N) \f$
|
|
||||||
//! where N is sizeof...(_Ts)
|
|
||||||
template<typename... _Ts>
|
|
||||||
using index_sequence_for = make_index_sequence<sizeof...(_Ts)>;
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
}}
|
|
||||||
//! @}
|
|
||||||
#endif /* __utl_meta_idx_sequence_h__ */
|
|
@ -21,7 +21,8 @@
|
|||||||
#define __utl_meta_integralconstant_h__
|
#define __utl_meta_integralconstant_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
@ -43,9 +44,9 @@ namespace meta {
|
|||||||
using type = nil_;
|
using type = nil_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Type alias for \p _Tp::type. Used to evaluate/extract return type of metafunctions
|
//! Type alias for \p Tp::type. Used to evaluate/extract return type of metafunctions
|
||||||
template <typename _Tp>
|
template <typename Tp>
|
||||||
using eval = typename _Tp::type;
|
using eval = typename Tp::type;
|
||||||
|
|
||||||
//! integral_
|
//! integral_
|
||||||
//! Integral Constant is a holder class for a compile-time value of an integral type.
|
//! Integral Constant is a holder class for a compile-time value of an integral type.
|
||||||
@ -53,90 +54,98 @@ namespace meta {
|
|||||||
//! An integral constant object is implicitly convertible to the corresponding
|
//! An integral constant object is implicitly convertible to the corresponding
|
||||||
//! run-time value of the wrapped integral type
|
//! run-time value of the wrapped integral type
|
||||||
//! @{
|
//! @{
|
||||||
template <typename _Tp, _Tp _v>
|
template <typename Tp, Tp v>
|
||||||
struct integral_ {
|
using integral_ = std::integral_constant<Tp, v>;
|
||||||
using value_type = _Tp;
|
|
||||||
using type = integral_<_Tp, _v>;
|
|
||||||
|
|
||||||
constexpr operator value_type() const noexcept {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
constexpr value_type operator()() const noexcept {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
static constexpr _Tp value = _v;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename _Tp, _Tp _v>
|
|
||||||
constexpr _Tp integral_<_Tp, _v>::value;
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! Wrappers for basic types
|
//! Wrappers for basic types
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
//! bool_ type: integral constant wrapper for bool
|
//! bool_ type: integral constant wrapper for bool
|
||||||
template<bool _v>
|
template<bool v>
|
||||||
using bool_ = integral_<bool, _v>;
|
using bool_ = integral_<bool, v>;
|
||||||
|
|
||||||
using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value.
|
using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value.
|
||||||
using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value.
|
using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value.
|
||||||
|
|
||||||
//! int8_ type: integral constant wrapper for \c int8_t
|
//! int8_ type: integral constant wrapper for \c int8_t
|
||||||
template<int8_t _v>
|
template<int8_t v>
|
||||||
using int8_ = integral_<int8_t, _v>;
|
using int8_ = integral_<int8_t, v>;
|
||||||
//! uint8_ type: integral constant wrapper for \c uint8_t
|
//! uint8_ type: integral constant wrapper for \c uint8_t
|
||||||
template<uint8_t _v>
|
template<uint8_t v>
|
||||||
using uint8_ = integral_<uint8_t, _v>;
|
using uint8_ = integral_<uint8_t, v>;
|
||||||
|
|
||||||
//! int16_ type: integral constant wrapper for \c int16_t
|
//! int16_ type: integral constant wrapper for \c int16_t
|
||||||
template<int16_t _v>
|
template<int16_t v>
|
||||||
using int16_ = integral_<int16_t, _v>;
|
using int16_ = integral_<int16_t, v>;
|
||||||
//! uint16_ type: integral constant wrapper for \c uint16_t
|
//! uint16_ type: integral constant wrapper for \c uint16_t
|
||||||
template<uint16_t _v>
|
template<uint16_t v>
|
||||||
using uint16_ = integral_<uint16_t, _v>;
|
using uint16_ = integral_<uint16_t, v>;
|
||||||
|
|
||||||
//! int32_ type: integral constant wrapper for \c int32_t
|
//! int32_ type: integral constant wrapper for \c int32_t
|
||||||
template<int32_t _v>
|
template<int32_t v>
|
||||||
using int32_ = integral_<int32_t, _v>;
|
using int32_ = integral_<int32_t, v>;
|
||||||
//! uint32_ type: integral constant wrapper for \c uint32_t
|
//! uint32_ type: integral constant wrapper for \c uint32_t
|
||||||
template<uint32_t _v>
|
template<uint32_t v>
|
||||||
using uint32_ = integral_<uint32_t, _v>;
|
using uint32_ = integral_<uint32_t, v>;
|
||||||
|
|
||||||
//! char_ type: integral constant wrapper for \c char
|
//! char_ type: integral constant wrapper for \c char
|
||||||
template<char _v>
|
template<char v>
|
||||||
using char_ = integral_<char, _v>;
|
using char_ = integral_<char, v>;
|
||||||
|
|
||||||
//! int_ type: integral constant wrapper for \c int
|
//! int_ type: integral constant wrapper for \c int
|
||||||
template<int _v>
|
template<int v>
|
||||||
using int_ = integral_<int, _v>;
|
using int_ = integral_<int, v>;
|
||||||
|
|
||||||
//! long_ type: integral constant wrapper for \c long
|
//! long_ type: integral constant wrapper for \c long
|
||||||
template<long _v>
|
template<long v>
|
||||||
using long_ = integral_<long, _v>;
|
using long_ = integral_<long, v>;
|
||||||
|
|
||||||
//! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t
|
//! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t
|
||||||
template<index_t _v>
|
template<index_t v>
|
||||||
using index_ = integral_<index_t, _v>;
|
using index_ = integral_<index_t, v>;
|
||||||
|
|
||||||
//! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t
|
//! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t
|
||||||
template<size_t _v>
|
template<size_t v>
|
||||||
using size_ = integral_<size_t, _v>;
|
using size_ = integral_<size_t, v>;
|
||||||
|
|
||||||
//! Computes the size of the type \p _Tp.
|
//! Computes the size of the type \p Tp.
|
||||||
//! Complexity \f$ O(1) \f$.
|
//! Complexity \f$ O(1) \f$.
|
||||||
template <typename _Tp>
|
template <typename Tp>
|
||||||
using sizeof_ = size_<sizeof(_Tp)>;
|
using sizeof_ = size_<sizeof(Tp)>;
|
||||||
|
|
||||||
//! Computes the alignment required for any instance of the type \p _Tp.
|
//! Computes the alignment required for any instance of the type \p Tp.
|
||||||
//! Complexity \f$ O(1) \f$.
|
//! Complexity \f$ O(1) \f$.
|
||||||
template <typename _Tp>
|
template <typename Tp>
|
||||||
using alignof_ = size_<alignof(_Tp)>;
|
using alignof_ = size_<alignof(Tp)>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! The last position we can express for indexing
|
//! The last position we can express for indexing
|
||||||
using Npos = size_<index_t(-1)>;
|
using Npos = size_<index_t(-1)>;
|
||||||
|
|
||||||
|
//! integer sequence
|
||||||
|
//! @{
|
||||||
|
template< class Tp, Tp... Ints >
|
||||||
|
using integer_sequence = std::integer_sequence<Tp, Ints...>;
|
||||||
|
|
||||||
|
template<typename Tp, Tp Num>
|
||||||
|
using make_integer_sequence = std::make_integer_sequence<Tp, Num>;
|
||||||
|
|
||||||
|
//! Alias template index_sequence
|
||||||
|
template<index_t... Idx>
|
||||||
|
using index_sequence = integer_sequence<index_t, Idx...>;
|
||||||
|
|
||||||
|
//! Alias template make_index_sequence
|
||||||
|
template<index_t Num>
|
||||||
|
using make_index_sequence = make_integer_sequence <index_t, Num>;
|
||||||
|
|
||||||
|
//! Alias template index_sequence_for
|
||||||
|
template<typename... Types>
|
||||||
|
using index_sequence_for = make_index_sequence<sizeof...(Types)>;
|
||||||
|
|
||||||
|
//! @}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
//!@}
|
//!@}
|
||||||
|
|
||||||
#endif /* __utl_meta_integralconstant_h__ */
|
#endif /* __utl_meta_integralconstant_h__ */
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/integral.h>
|
#include <utl/meta/integral.h>
|
||||||
#include <utl/meta/detection.h>
|
#include <utl/meta/detection.h>
|
||||||
#include <utl/meta/selection.h>
|
#include <utl/meta/operations.h>
|
||||||
#include <utl/meta/logical.h>
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
@ -36,15 +35,19 @@ namespace utl {
|
|||||||
namespace meta{
|
namespace meta{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \name meta:: invoke
|
* \name meta::invoke
|
||||||
*
|
*
|
||||||
* A meta-programming invoke() analogous. A meta:: `invocable` shall contain a nested
|
* A meta-programming invoke() analogous. A \c meta::invocable shall contain a nested
|
||||||
* template type named `apply` which is bind to actual invocable meta-function.
|
* template type named \b apply which is bind to actual invocable meta-function.
|
||||||
|
*
|
||||||
|
* - We can use \c wrap<> or even better \c quote<> in order to wrap a metafunction to a type (metafunction class)
|
||||||
|
* - We can pass these wrapped types to other metafunctions
|
||||||
|
* - We can \c invoke<> the inner \c apply from a wrapped metafunction class.
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* *invocable* identity, identity_t.
|
* identity, identity_t.
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
template <typename _Tp>
|
template <typename _Tp>
|
||||||
@ -56,7 +59,7 @@ namespace meta{
|
|||||||
#else
|
#else
|
||||||
template <typename...>
|
template <typename...>
|
||||||
using apply = _Tp; //!< identity is invokable, must also have apply
|
using apply = _Tp; //!< identity is invokable, must also have apply
|
||||||
#endif
|
#endif
|
||||||
using type = _Tp; //!< identity
|
using type = _Tp; //!< identity
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +68,49 @@ namespace meta{
|
|||||||
using identity_t = eval<identity<_Tp>>;
|
using identity_t = eval<identity<_Tp>>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* invoke, invoke_t
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
/*!
|
||||||
|
* Invoke the nested apply meta-function from \c Fn with the arguments \c Args.
|
||||||
|
* \note
|
||||||
|
* This is an analogous to the std::invoke()
|
||||||
|
*/
|
||||||
|
template <typename Fn, typename... Args>
|
||||||
|
using invoke = typename Fn::template apply<Args...>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Evaluate the invocation of the nested apply metafunction from \p Fn
|
||||||
|
* with the arguments \p Args.
|
||||||
|
*/
|
||||||
|
template <typename Fn, typename... Args>
|
||||||
|
using invoke_t = eval< invoke <Fn, Args...>>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! wrap
|
||||||
|
//! @{
|
||||||
|
/*!
|
||||||
|
* wrap is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
|
* to create a corresponding Metafunction Class (Invocable). This way
|
||||||
|
* we can pass Metafunctions as types to other metafunctions and let
|
||||||
|
* them \c invoke the inner templated apply
|
||||||
|
*/
|
||||||
|
template <template <typename...> class F>
|
||||||
|
struct wrap {
|
||||||
|
template <typename... Args>
|
||||||
|
using apply = F<Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
|
||||||
|
template <typename T, template <T...> class F>
|
||||||
|
struct wrap_i {
|
||||||
|
// requires meta::Integral
|
||||||
|
template <typename... Ts>
|
||||||
|
using apply = F<Ts::type::value...>;
|
||||||
|
};
|
||||||
|
//! @}
|
||||||
|
|
||||||
//! Is applicable trait
|
//! Is applicable trait
|
||||||
//! @{
|
//! @{
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -79,22 +125,29 @@ namespace meta{
|
|||||||
using type = decltype(check<F>(0));
|
using type = decltype(check<F>(0));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Fn, typename... Args>
|
|
||||||
using use_ = typename Fn::template apply<Args...>;
|
|
||||||
|
|
||||||
template<typename F, typename... T>
|
template<typename F, typename... T>
|
||||||
struct is_applicable_q_ {
|
struct is_applicable_q_ {
|
||||||
template<typename G, typename Ret= eval<use_<G, T...>>>
|
template<typename G, typename Ret = invoke_t<G, T...>>
|
||||||
static Ret check (int); //< T.. can be passed to G
|
static Ret check (int); //< T.. can be passed to G
|
||||||
template<typename...>
|
template<typename...>
|
||||||
static nil_ check (...); //< all other combinations
|
static nil_ check (...); //< all other combinations
|
||||||
|
|
||||||
using type = decltype(check<F>(0));
|
using type = if_ <
|
||||||
|
not_same_<
|
||||||
|
nil_,
|
||||||
|
decltype(check<F>(0))
|
||||||
|
>, true_, false_
|
||||||
|
>;
|
||||||
|
//!\note
|
||||||
|
//! check doesn't return \c true_ or \c false_. The reason is that the \p F is
|
||||||
|
//! probably quoted/deferred. This implies an embedded is_applicable<> check
|
||||||
|
//! inside defer<> and so its guaranteed to be well formed.
|
||||||
|
//! Thus we return the actual evaluated type and make the check for nil_
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, template <T...> class F, T... Is>
|
template<typename T, template <T...> class F, T... Is>
|
||||||
struct is_applicable_i_ {
|
struct is_applicable_i_ {
|
||||||
template<typename TT, template<TT...> class G, typename =G<Is...>>
|
template<typename TT, template<TT...> class G, typename = G<Is...>>
|
||||||
static true_ check (int); //< Is... can be passed to G
|
static true_ check (int); //< Is... can be passed to G
|
||||||
template<typename TT, template<TT...> class G>
|
template<typename TT, template<TT...> class G>
|
||||||
static false_ check (...); //< all other combinations
|
static false_ check (...); //< all other combinations
|
||||||
@ -106,26 +159,18 @@ namespace meta{
|
|||||||
//! check if we can instantiate \p F with parameters \p T
|
//! check if we can instantiate \p F with parameters \p T
|
||||||
template<template<typename...> class F, typename... T>
|
template<template<typename...> class F, typename... T>
|
||||||
using is_applicable_t = eval<
|
using is_applicable_t = eval<
|
||||||
detail::is_applicable_<F, T...>
|
detail::is_applicable_<F, T...>
|
||||||
>;
|
>;
|
||||||
//! check if we can instantiate \p Q with parameters \p T and the instant
|
//! check if we can invoke \p Q with parameters \p T
|
||||||
//! is different from \c nil_
|
|
||||||
template<typename Q, typename... T>
|
template<typename Q, typename... T>
|
||||||
using is_applicable_qt = eval <
|
using is_applicable_qt = eval <
|
||||||
// Extra check for quoted metafunctions to check return type
|
detail::is_applicable_q_ <Q, T...>
|
||||||
if_ <
|
|
||||||
not_same_<
|
|
||||||
eval <detail::is_applicable_q_ <Q, T...>>,
|
|
||||||
nil_
|
|
||||||
>,
|
|
||||||
true_,
|
|
||||||
false_
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! check if we can instantiate \p F with parameters \p Is of type \p T
|
//! check if we can instantiate \p F with parameters \p Is of type \p T
|
||||||
template <typename T, template<T...> class F, T... Is>
|
template <typename T, template<T...> class F, T... Is>
|
||||||
using is_applicable_it = eval<
|
using is_applicable_it = eval<
|
||||||
detail::is_applicable_i_<T, F, Is...>
|
detail::is_applicable_i_<T, F, Is...>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
@ -149,75 +194,85 @@ namespace meta{
|
|||||||
//! template<template<typename...> class F, typename... Ts>
|
//! template<template<typename...> class F, typename... Ts>
|
||||||
//! using defer_ = F<Ts...>;
|
//! using defer_ = F<Ts...>;
|
||||||
//!
|
//!
|
||||||
//! The use of struct here is due to Core issue 1430 [1] and is used
|
//! The use of struct here is due to Core issue 1430 [\ref link1 1] and is used
|
||||||
//! as suggested by Roy Crihfield in [2].
|
//! as suggested by Roy Crihfield in [\ref link2 2].
|
||||||
//! In short, this is due to language's inability to expand Ts... into
|
//! In short, this is due to language's inability to expand Ts... into
|
||||||
//! a fixed parameter list of an alias template.
|
//! a fixed parameter list of an alias template.
|
||||||
//!
|
//!
|
||||||
//! [1]: https://wg21.link/cwg1430
|
//! \anchor link1 [1]: https://wg21.link/cwg1430
|
||||||
//! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
|
//! \anchor link2 [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
|
||||||
//! @}
|
//! @}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! defer alias template for F<Ts...>
|
//! defer alias template for F<Ts...>
|
||||||
template<template<class...> class F, class... Ts>
|
template<template<class...> class F, class... Ts>
|
||||||
using defer = if_<
|
using defer = if_<
|
||||||
detail::is_applicable_<F, Ts...>,
|
detail::is_applicable_<F, Ts...>,
|
||||||
detail::defer_<F, Ts...>,
|
detail::defer_<F, Ts...>,
|
||||||
nil_ //!< This should be identity<nil_> if nil_ was empty
|
nil_ //!< Safe, nil_ is dereferencable
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! defer_i alias template for F<T, Is...>
|
//! defer_i alias template for F<T, Is...>
|
||||||
template <typename T, template<T...> class F, T... Is>
|
template <typename T, template<T...> class F, T... Is>
|
||||||
using defer_i = if_ <
|
using defer_i = if_ <
|
||||||
detail::is_applicable_i_<T, F, Is...>,
|
detail::is_applicable_i_<T, F, Is...>,
|
||||||
detail::defer_i_<T, F, Is...>,
|
detail::defer_i_<T, F, Is...>,
|
||||||
nil_ //!< This should be identity<nil_> if nil_ was empty
|
nil_ //!< Safe, nil_ is dereferencable
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
|
//! quote
|
||||||
|
//! @{
|
||||||
/*!
|
/*!
|
||||||
* quote is a higher-order primitive that wraps an n-ary Metafunction
|
* quote deferred is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
* to create a corresponding Metafunction Class (Invocable).
|
* to create a corresponding Metafunction Class (Invocable) using defer<> to
|
||||||
|
* postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.
|
||||||
|
* Again this way we can pass Metafunctions as types to other metafunctions and let
|
||||||
|
* them \c invoke the inner templated apply
|
||||||
*/
|
*/
|
||||||
template <template <typename...> class F>
|
template <template <typename...> class F>
|
||||||
struct quote {
|
struct quote {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using apply = eval<
|
using apply = eval<
|
||||||
defer<F, Args...> //!< defer here to avoid DR1430
|
defer<F, Args...> //!< defer here to avoid DR1430
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Wrap a template \p F taking literals of type \p T into an Invokable
|
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
|
||||||
template <typename T, template <T...> class F>
|
template <typename T, template <T...> class F>
|
||||||
struct quote_i {
|
struct quote_i {
|
||||||
// requires meta::Integral
|
// requires meta::Integral
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using apply = eval<
|
using apply = eval<
|
||||||
defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
|
defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
//! @}
|
||||||
/*!
|
|
||||||
* Invoke the nested apply meta-function from \c Fn
|
|
||||||
* with the arguments \c Args.
|
|
||||||
* \note
|
|
||||||
* This is like the std::invoke()
|
|
||||||
*/
|
|
||||||
template <typename Fn, typename... Args>
|
|
||||||
using invoke = typename Fn::template apply<Args...>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Evaluate the invocation of the nested apply metafunction from \p Fn
|
|
||||||
* with the arguments \p Args.
|
|
||||||
*/
|
|
||||||
template <typename Fn, typename... Args>
|
|
||||||
using invoke_t = eval< invoke <Fn, Args...>>;
|
|
||||||
|
|
||||||
//! compose
|
//! compose
|
||||||
//! @{
|
//! @{
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename ...Fns> struct compose_ { };
|
template <template <typename...> class... Fns> struct compose_f_ {};
|
||||||
|
|
||||||
|
// recursive call to all invokes
|
||||||
|
template <template <typename...> class Fn0,
|
||||||
|
template <typename...> class... Fns>
|
||||||
|
struct compose_f_<Fn0, Fns...> {
|
||||||
|
template <typename... Args>
|
||||||
|
using apply = invoke<
|
||||||
|
quote<Fn0>,
|
||||||
|
invoke<compose_f_<Fns...>, Args...>
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
// Termination specialization, finally pass the arguments
|
||||||
|
template <template <typename...> class Fn0>
|
||||||
|
struct compose_f_<Fn0> {
|
||||||
|
template <typename ...Args>
|
||||||
|
using apply = invoke<quote<Fn0>, Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ...Fns> struct compose_ {};
|
||||||
|
|
||||||
// recursive call to all invokes
|
// recursive call to all invokes
|
||||||
template<typename Fn0, typename ...Fns>
|
template<typename Fn0, typename ...Fns>
|
||||||
@ -228,7 +283,6 @@ namespace meta{
|
|||||||
invoke<compose_<Fns...>, Args...>
|
invoke<compose_<Fns...>, Args...>
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Termination specialization, finally pass the arguments
|
// Termination specialization, finally pass the arguments
|
||||||
template<typename Fn0>
|
template<typename Fn0>
|
||||||
struct compose_<Fn0> {
|
struct compose_<Fn0> {
|
||||||
@ -238,25 +292,40 @@ namespace meta{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Create an invocable from other invocables by composition.
|
* Create an invocable from other invocables(quoted metafunctions) by composition.
|
||||||
* \note
|
* \note
|
||||||
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
||||||
* That because of the "return" type of metafunction. They can only return one
|
* Thats because of the "return" type of metafunction. They can only return one
|
||||||
* type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
|
* type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
|
||||||
* \example
|
* \example
|
||||||
* \code
|
* \code
|
||||||
* static_assert(std::is_same<
|
* static_assert( std::is_same<
|
||||||
* invoke<compose<F1, F2, F3>, int>,
|
* invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
|
||||||
* F1 <F2 <F3 <int>>>
|
* >, "");
|
||||||
* >, "" );
|
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
template <typename... Fns>
|
template <typename... Fns>
|
||||||
using compose = detail::compose_<Fns...>;
|
using compose = detail::compose_<Fns...>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create an invocable from other metafunctions by composition.
|
||||||
|
* \note
|
||||||
|
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
||||||
|
* Thats because of the "return" type of metafunction. They can only return one
|
||||||
|
* type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* static_assert( std::is_same<
|
||||||
|
* invoke<compose_f<F1, F2, F3>, int>, F1 <F2 <F3 <int>>>
|
||||||
|
* >, "");
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
template <template <typename...> class... Fns>
|
||||||
|
using compose_f = detail::compose_f_<Fns...>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Applies the Invocable \p Fn by binding the arguments \p Ts
|
* Applies the invocable \p Fn by binding the arguments \p Ts
|
||||||
* to the front of \p Fn.
|
* to the front of \p Fn.
|
||||||
*/
|
*/
|
||||||
template<typename Fn, typename... Ts>
|
template<typename Fn, typename... Ts>
|
||||||
@ -275,18 +344,19 @@ namespace meta{
|
|||||||
using apply = invoke<Fn, Us..., Ts...>;
|
using apply = invoke<Fn, Us..., Ts...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ========== meta:: predicates ============
|
* ========== meta:: predicates ============
|
||||||
*/
|
*/
|
||||||
template <typename T1>
|
template <typename T1>
|
||||||
struct same_as {
|
struct same_as {
|
||||||
template < typename T2>
|
template <typename T2>
|
||||||
struct apply : same_<T1, T2> { };
|
struct apply : same_<T1, T2> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T1>
|
template <typename T1>
|
||||||
struct not_same_as {
|
struct not_same_as {
|
||||||
template < typename T2>
|
template <typename T2>
|
||||||
struct apply : not_same_<T1, T2> { };
|
struct apply : not_same_<T1, T2> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
/*!
|
|
||||||
* \file logical.h
|
|
||||||
* \brief Template meta-programming logic operator and type relations.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#ifndef __utl_meta_logical_h__
|
|
||||||
#define __utl_meta_logical_h__
|
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
|
||||||
#include <utl/meta/selection.h>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \ingroup meta
|
|
||||||
* \defgroup logic
|
|
||||||
* logic operator and type relations support header
|
|
||||||
*/
|
|
||||||
//! @{
|
|
||||||
namespace utl {
|
|
||||||
namespace meta{
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Logical relation for types
|
|
||||||
*/
|
|
||||||
//! @{
|
|
||||||
|
|
||||||
//! Negate the *bool* constant parameter
|
|
||||||
template <bool B>
|
|
||||||
using not_c = bool_<!B>;
|
|
||||||
|
|
||||||
//! not
|
|
||||||
template<typename _Tp>
|
|
||||||
using not_ = not_c<_Tp::type::value>;
|
|
||||||
|
|
||||||
//! OR implementation
|
|
||||||
//! @{
|
|
||||||
namespace detail {
|
|
||||||
template<typename...> struct _or_;
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct _or_<> : false_ { };
|
|
||||||
|
|
||||||
template<typename _T1>
|
|
||||||
struct _or_<_T1> : _T1 { };
|
|
||||||
|
|
||||||
template<typename _T1, typename _T2>
|
|
||||||
struct _or_ <_T1, _T2>
|
|
||||||
: if_<_T1, _T1, _T2> { };
|
|
||||||
|
|
||||||
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
|
|
||||||
struct _or_<_T1, _T2, _T3, _Tn...>
|
|
||||||
: if_<_T1, _T1, _or_<_T2, _T3, _Tn...>> { };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... _Ts>
|
|
||||||
using or_ = eval<detail::_or_<_Ts...>>;
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
//! AND implementation
|
|
||||||
//! @{
|
|
||||||
namespace detail {
|
|
||||||
template<typename...> struct _and_;
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct _and_<>
|
|
||||||
: true_ { };
|
|
||||||
|
|
||||||
template<typename _T1>
|
|
||||||
struct _and_ <_T1>
|
|
||||||
: _T1 { };
|
|
||||||
|
|
||||||
template<typename _T1, typename _T2>
|
|
||||||
struct _and_<_T1, _T2>
|
|
||||||
: if_<_T1, _T2, _T1> { };
|
|
||||||
|
|
||||||
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
|
|
||||||
struct _and_<_T1, _T2, _T3, _Tn...>
|
|
||||||
: if_<_T1, _and_<_T2, _T3, _Tn...>, _T1> { };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... _Ts>
|
|
||||||
using and_ = eval<detail::_and_<_Ts...>>;
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
//! same
|
|
||||||
//! @{
|
|
||||||
template<typename _T1, typename _T2>
|
|
||||||
struct same_ : false_ { };
|
|
||||||
|
|
||||||
template<typename _Tp>
|
|
||||||
struct same_ <_Tp, _Tp> : true_ { };
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
//! not same
|
|
||||||
//! @{
|
|
||||||
template<typename _T1, typename _T2>
|
|
||||||
using not_same_ = not_<eval<same_<_T1, _T2>>>;
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
//! @}
|
|
||||||
}}
|
|
||||||
|
|
||||||
//! @}
|
|
||||||
|
|
||||||
#endif /* __utl_meta_logical_h__ */
|
|
@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file /utl/core/version.h
|
* \file /utl/meta/meta.h
|
||||||
* \brief version and cpp version checks
|
* \brief Include all meta library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
*
|
*
|
||||||
@ -22,11 +22,10 @@
|
|||||||
#define __utl_meta_meta_h__
|
#define __utl_meta_meta_h__
|
||||||
|
|
||||||
#include <utl/meta/integral.h>
|
#include <utl/meta/integral.h>
|
||||||
#include <utl/meta/typelist.h>
|
|
||||||
#include <utl/meta/selection.h>
|
#include <utl/meta/selection.h>
|
||||||
#include <utl/meta/logical.h>
|
|
||||||
#include <utl/meta/operations.h>
|
#include <utl/meta/operations.h>
|
||||||
#include <utl/meta/useif.h>
|
#include <utl/meta/useif.h>
|
||||||
|
#include <utl/meta/typelist.h>
|
||||||
#include <utl/meta/detection.h>
|
#include <utl/meta/detection.h>
|
||||||
#include <utl/meta/invoke.h>
|
#include <utl/meta/invoke.h>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file operators.h
|
* \file operations.h
|
||||||
* \brief Template meta-programming integral constant arithmetic
|
* \brief Integral constant operations and logical operations
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
*
|
*
|
||||||
@ -17,11 +17,105 @@
|
|||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef __utl_meta_arithmetic_h__
|
#ifndef __utl_meta_operations_h__
|
||||||
#define __utl_meta_arithmetic_h__
|
#define __utl_meta_operations_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/logical.h>
|
#include <utl/meta/selection.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \ingroup meta
|
||||||
|
* \defgroup logic
|
||||||
|
* logic operators and type relations support
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace utl {
|
||||||
|
namespace meta{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Logical relation for types
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
|
||||||
|
//! Negate the *bool* constant parameter
|
||||||
|
template <bool B>
|
||||||
|
using not_c = bool_<!B>;
|
||||||
|
|
||||||
|
//! not
|
||||||
|
template<typename _Tp>
|
||||||
|
using not_ = not_c<_Tp::type::value>;
|
||||||
|
|
||||||
|
//! OR implementation
|
||||||
|
//! @{
|
||||||
|
namespace detail {
|
||||||
|
template<typename...> struct _or_;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct _or_<> : false_ { };
|
||||||
|
|
||||||
|
template<typename _T1>
|
||||||
|
struct _or_<_T1> : _T1 { };
|
||||||
|
|
||||||
|
template<typename _T1, typename _T2>
|
||||||
|
struct _or_ <_T1, _T2>
|
||||||
|
: if_<_T1, _T1, _T2> { };
|
||||||
|
|
||||||
|
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
|
||||||
|
struct _or_<_T1, _T2, _T3, _Tn...>
|
||||||
|
: if_<_T1, _T1, _or_<_T2, _T3, _Tn...>> { };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... _Ts>
|
||||||
|
using or_ = eval<detail::_or_<_Ts...>>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! AND implementation
|
||||||
|
//! @{
|
||||||
|
namespace detail {
|
||||||
|
template<typename...> struct _and_;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct _and_<>
|
||||||
|
: true_ { };
|
||||||
|
|
||||||
|
template<typename _T1>
|
||||||
|
struct _and_ <_T1>
|
||||||
|
: _T1 { };
|
||||||
|
|
||||||
|
template<typename _T1, typename _T2>
|
||||||
|
struct _and_<_T1, _T2>
|
||||||
|
: if_<_T1, _T2, _T1> { };
|
||||||
|
|
||||||
|
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
|
||||||
|
struct _and_<_T1, _T2, _T3, _Tn...>
|
||||||
|
: if_<_T1, _and_<_T2, _T3, _Tn...>, _T1> { };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... _Ts>
|
||||||
|
using and_ = eval<detail::_and_<_Ts...>>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! same
|
||||||
|
//! @{
|
||||||
|
template<typename _T1, typename _T2>
|
||||||
|
struct same_ : false_ { };
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
struct same_ <_Tp, _Tp> : true_ { };
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! not same
|
||||||
|
//! @{
|
||||||
|
template<typename _T1, typename _T2>
|
||||||
|
using not_same_ = not_<eval<same_<_T1, _T2>>>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
}}
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
@ -33,10 +127,10 @@
|
|||||||
namespace utl {
|
namespace utl {
|
||||||
namespace meta {
|
namespace meta {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Math operations
|
* Math operations
|
||||||
* requires IntegralConstant(_Tp)
|
* requires IntegralConstant(_Tp)
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
//! Negation
|
//! Negation
|
||||||
@ -129,4 +223,5 @@ namespace meta {
|
|||||||
}}
|
}}
|
||||||
//!@}
|
//!@}
|
||||||
|
|
||||||
#endif /* __utl_meta_integral_h__ */
|
|
||||||
|
#endif /* __utl_meta_operations_h__ */
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/integral.h>
|
#include <utl/meta/integral.h>
|
||||||
#include <utl/meta/sfinae.h>
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
@ -74,15 +73,10 @@ namespace meta{
|
|||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
//! Select the first type of a type sequence
|
//! Select the first type of a type sequence
|
||||||
template <typename T1, typename ...>
|
template <typename T1, typename ...> using first_of = T1;
|
||||||
struct first_of {
|
|
||||||
using type = T1;
|
|
||||||
};
|
|
||||||
//! Select the second type of a type sequence
|
//! Select the second type of a type sequence
|
||||||
template <typename T1, typename T2, typename ...>
|
template <typename T1, typename T2, typename ...> using second_of = T2;
|
||||||
struct second_of {
|
|
||||||
using type = T2;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
}}
|
}}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define __utl_meta_sfinae_h__
|
#define __utl_meta_sfinae_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
@ -34,48 +35,33 @@ namespace meta {
|
|||||||
//! Tool to enable a partial specialization only if a boolean condition is true.
|
//! Tool to enable a partial specialization only if a boolean condition is true.
|
||||||
//! @{
|
//! @{
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename... T>
|
// template <typename... T>
|
||||||
struct dev_null { using type = dev_null; }; //< Same as typelist
|
// struct dev_null { using type = dev_null; }; //< Same as typelist
|
||||||
|
|
||||||
template <bool If> struct when_ { };
|
template <bool If> struct when_ { };
|
||||||
template <> struct when_<true> { using type = void; };
|
template <> struct when_<true> { using type = void; };
|
||||||
}
|
}
|
||||||
//! Well formed only if \p If is true
|
//! Well formed only if \p If is true
|
||||||
template <bool If>
|
template <bool If>
|
||||||
using when = eval<detail::when_<If>>;
|
using when = eval< detail::when_<If> >;
|
||||||
|
|
||||||
|
// //! Well formed only if all of \p Ifs are \c true
|
||||||
|
// template <bool ...Ifs>
|
||||||
|
// using when_all = detail::dev_null<
|
||||||
|
// when<Ifs>...
|
||||||
|
// >;
|
||||||
|
|
||||||
//! Well formed only if all of \p Ifs are \c true
|
|
||||||
template <bool ...Ifs>
|
|
||||||
using when_all = detail::dev_null<
|
|
||||||
when<Ifs>...
|
|
||||||
>;
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! select _Tp if \p If is true, else SFINAE
|
//! enable_if
|
||||||
//! We implement enable_if so we don't have to pull entire \c <type_traits> from stl
|
|
||||||
//! @{
|
//! @{
|
||||||
template <bool If, typename _Tp = void>
|
|
||||||
struct enable_if {
|
|
||||||
using type = _Tp;
|
|
||||||
};
|
|
||||||
template<typename _Tp>
|
|
||||||
struct enable_if <false, _Tp> { /* SFINAE*/ };
|
|
||||||
|
|
||||||
//! Alias template for enable_if
|
//! enable_if, imported from stl
|
||||||
template <bool If, typename _Tp = void>
|
template <bool If, typename _Tp = void> using enable_if = std::enable_if<If, _Tp>;
|
||||||
using use_if = enable_if<If, _Tp>;
|
|
||||||
|
|
||||||
//! Publicly recognized alias template for enable_if
|
//! alias template for enable_if
|
||||||
template<bool If, typename _Tp = void>
|
template<bool If, typename _Tp = void> using enable_if_t = eval< enable_if<If, _Tp> >;
|
||||||
using enable_if_t = eval<
|
|
||||||
enable_if<If, _Tp>
|
|
||||||
>;
|
|
||||||
|
|
||||||
//! Uniform alias template for use_if
|
|
||||||
template<bool If, typename _Tp = void>
|
|
||||||
using use_if_t = eval<
|
|
||||||
enable_if<If, _Tp>
|
|
||||||
>;
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
@ -17,12 +17,11 @@
|
|||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef __utl_meta_pack_h__
|
#ifndef __utl_meta_typelist_h__
|
||||||
#define __utl_meta_pack_h__
|
#define __utl_meta_typelist_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/integral.h>
|
#include <utl/meta/integral.h>
|
||||||
#include <utl/meta/idx_sequence.h>
|
|
||||||
#include <utl/meta/detection.h>
|
#include <utl/meta/detection.h>
|
||||||
#include <utl/meta/invoke.h>
|
#include <utl/meta/invoke.h>
|
||||||
#include <utl/meta/sfinae.h>
|
#include <utl/meta/sfinae.h>
|
||||||
@ -39,7 +38,7 @@ namespace meta {
|
|||||||
* \brief
|
* \brief
|
||||||
* A class template that just holds a parameter pack.
|
* A class template that just holds a parameter pack.
|
||||||
*
|
*
|
||||||
* The idea came from MPL's sequence concept[1] and from N4115[2].
|
* The idea came from MPL's sequence concept [\ref link1 1] and from N4115 [\ref link2 2].
|
||||||
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
|
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
|
||||||
* This way the name gives the feeling of a container and smells like Python.
|
* This way the name gives the feeling of a container and smells like Python.
|
||||||
*
|
*
|
||||||
@ -53,14 +52,14 @@ namespace meta {
|
|||||||
* l1 a {};
|
* l1 a {};
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* boost::hana[3] suggests a more powerful scheme were type invariant structures can be used
|
* boost::hana [\ref link3 3] suggests a more powerful scheme were type invariant structures can be used
|
||||||
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
|
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
|
||||||
* responsibility that comes along). So a simple python-like list with some extra vector-like
|
* responsibility that comes along). So a simple python-like list with some extra vector-like
|
||||||
* element access functionalities and no iterators is good enough(for now).
|
* element access functionalities and no iterators is good enough(for now).
|
||||||
*
|
*
|
||||||
* [1]: https://www.boost.org/doc/
|
* \anchor link1 [1]: https://www.boost.org/doc/
|
||||||
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
|
* \anchor link2 [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
|
||||||
* [3]: https://github.com/boostorg/hana
|
* \anchor link3 [3]: https://github.com/boostorg/hana
|
||||||
*/
|
*/
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct typelist {
|
struct typelist {
|
||||||
@ -197,6 +196,9 @@ namespace meta {
|
|||||||
template <typename Fn, typename Seq>
|
template <typename Fn, typename Seq>
|
||||||
using apply = apply_impl::apply_<Fn, Seq>;
|
using apply = apply_impl::apply_<Fn, Seq>;
|
||||||
|
|
||||||
|
template <typename Fn, typename Seq>
|
||||||
|
using apply_t = eval <apply<Fn, Seq>>;
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -206,11 +208,8 @@ namespace meta {
|
|||||||
//! @{
|
//! @{
|
||||||
namespace at_impl {
|
namespace at_impl {
|
||||||
|
|
||||||
template <typename T> struct _as_pointer__ { using type = T*; };
|
template <typename T> struct _add_pointer { using type = T*; };
|
||||||
template <typename T> struct _as_pointer__<T*> { using type = T*; };
|
template <typename T> using add_pointer = eval < _add_pointer <T> >;
|
||||||
template <typename T> using as_pointer_ = eval<
|
|
||||||
_as_pointer__<T>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template <typename ...>
|
template <typename ...>
|
||||||
struct at_head_ { };
|
struct at_head_ { };
|
||||||
@ -230,7 +229,7 @@ namespace meta {
|
|||||||
struct at_<typelist<List...>, N> {
|
struct at_<typelist<List...>, N> {
|
||||||
using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
|
using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
|
||||||
using type = decltype(
|
using type = decltype(
|
||||||
head_::select(static_cast<as_pointer_<List>>(nullptr)...) //< pass all as List*...
|
head_::select(static_cast<add_pointer<List>>(nullptr)...) //< pass all as List*...
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -242,7 +241,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List, index_t N>
|
template <typename List, index_t N>
|
||||||
using at_c = eval<
|
using at_c = eval<
|
||||||
at_impl::at_<List, N>
|
at_impl::at_<List, N>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -271,7 +270,7 @@ namespace meta {
|
|||||||
//! Complexity \f$ O(1) \f$.
|
//! Complexity \f$ O(1) \f$.
|
||||||
template <typename List>
|
template <typename List>
|
||||||
using front = eval<
|
using front = eval<
|
||||||
front_impl::front_<List>
|
front_impl::front_<List>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -284,7 +283,7 @@ namespace meta {
|
|||||||
template <typename Head, typename... Tail>
|
template <typename Head, typename... Tail>
|
||||||
struct back_<typelist<Head, Tail...>> {
|
struct back_<typelist<Head, Tail...>> {
|
||||||
using type = at_c <
|
using type = at_c <
|
||||||
typelist<Head, Tail...>, sizeof...(Tail)
|
typelist<Head, Tail...>, sizeof...(Tail)
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -293,7 +292,7 @@ namespace meta {
|
|||||||
//! Complexity \f$ O(N) \f$.
|
//! Complexity \f$ O(N) \f$.
|
||||||
template <typename List>
|
template <typename List>
|
||||||
using back = eval<
|
using back = eval<
|
||||||
back_impl::back_<List>
|
back_impl::back_<List>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
/*
|
/*
|
||||||
@ -335,7 +334,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename... Lists>
|
template <typename... Lists>
|
||||||
using cat = eval<
|
using cat = eval<
|
||||||
cat_impl::cat_<Lists...>
|
cat_impl::cat_<Lists...>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -435,7 +434,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List, typename V, typename Fn>
|
template <typename List, typename V, typename Fn>
|
||||||
using rev_fold = eval<
|
using rev_fold = eval<
|
||||||
rev_fold_impl::rev_fold_<List, V, Fn>
|
rev_fold_impl::rev_fold_<List, V, Fn>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -464,7 +463,6 @@ namespace meta {
|
|||||||
//! reverse
|
//! reverse
|
||||||
//! @{
|
//! @{
|
||||||
namespace reverse_impl {
|
namespace reverse_impl {
|
||||||
|
|
||||||
template <typename List, typename V = typelist<>>
|
template <typename List, typename V = typelist<>>
|
||||||
struct reverse_ {
|
struct reverse_ {
|
||||||
using type = fold<List, V, quote<push_front>>;
|
using type = fold<List, V, quote<push_front>>;
|
||||||
@ -477,7 +475,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List>
|
template <typename List>
|
||||||
using reverse = eval<
|
using reverse = eval<
|
||||||
reverse_impl::reverse_<List>
|
reverse_impl::reverse_<List>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -500,7 +498,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List>
|
template <typename List>
|
||||||
using pop_front = eval<
|
using pop_front = eval<
|
||||||
pop_front_impl::pop_front_<List>
|
pop_front_impl::pop_front_<List>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -524,7 +522,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List>
|
template <typename List>
|
||||||
using pop_back = eval <
|
using pop_back = eval <
|
||||||
pop_back_impl::pop_back_<List>
|
pop_back_impl::pop_back_<List>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -538,7 +536,7 @@ namespace meta {
|
|||||||
struct transform_<typelist<typelist<Ts...>, Fn>,
|
struct transform_<typelist<typelist<Ts...>, Fn>,
|
||||||
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
|
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
|
||||||
using type = typelist<
|
using type = typelist<
|
||||||
invoke_t<Fn, Ts>...
|
invoke_t<Fn, Ts>...
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -546,7 +544,7 @@ namespace meta {
|
|||||||
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
|
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
|
||||||
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
|
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
|
||||||
using type = typelist<
|
using type = typelist<
|
||||||
invoke_t<Fn, Ts0, Ts1>...
|
invoke_t<Fn, Ts0, Ts1>...
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -559,14 +557,14 @@ namespace meta {
|
|||||||
* \example
|
* \example
|
||||||
* \code
|
* \code
|
||||||
* using l1 = typelist<char, int, ...>;
|
* using l1 = typelist<char, int, ...>;
|
||||||
* using l2 = typelist<void, void, ...>;
|
* using l2 = typelist<void, double, ...>;
|
||||||
* using r1 = transform<l1, F1>; // F1, unary invocable
|
* using r1 = transform<l1, F1>; // F1, unary invocable
|
||||||
* using r2 = transform<l1, l2, F2>; // F2, binary invocable
|
* using r2 = transform<l1, l2, F2>; // F2, binary invocable
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using transform = eval<
|
using transform = eval<
|
||||||
transform_impl::transform_<typelist<Args...>>
|
transform_impl::transform_<typelist<Args...>>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -581,7 +579,7 @@ namespace meta {
|
|||||||
struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
|
struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
|
||||||
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
|
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
|
||||||
using type = typelist<
|
using type = typelist<
|
||||||
invoke<Fn, Ts>...
|
invoke<Fn, Ts>...
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -590,7 +588,7 @@ namespace meta {
|
|||||||
struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
|
struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
|
||||||
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
|
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
|
||||||
using type = typelist<
|
using type = typelist<
|
||||||
invoke<Fn, Ts0, Ts1>...
|
invoke<Fn, Ts0, Ts1>...
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -612,7 +610,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using transform_lazy = eval<
|
using transform_lazy = eval<
|
||||||
transform_lazy_impl::transform_lazy_<typelist<Args...>>
|
transform_lazy_impl::transform_lazy_<typelist<Args...>>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -627,11 +625,11 @@ namespace meta {
|
|||||||
struct find_if_<typelist<Head, Tail...>, Fn, N> {
|
struct find_if_<typelist<Head, Tail...>, Fn, N> {
|
||||||
// Recursive call to find_if_ until Fn returns true_
|
// Recursive call to find_if_ until Fn returns true_
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
invoke_t<Fn, Head>,
|
invoke_t<Fn, Head>,
|
||||||
index_<N>, // done, return current index
|
index_<N>, // done, return current index
|
||||||
eval<find_if_< // not done, re-call find_if_ with the Tail...
|
eval<find_if_< // not done, re-call find_if_ with the Tail...
|
||||||
typelist<Tail...>, Fn, N+1>
|
typelist<Tail...>, Fn, N+1>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -655,7 +653,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template<typename List, typename Pred>
|
template<typename List, typename Pred>
|
||||||
using find_if = eval<
|
using find_if = eval<
|
||||||
find_if_impl::find_if_<List, Pred, 0>
|
find_if_impl::find_if_<List, Pred, 0>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -675,11 +673,11 @@ namespace meta {
|
|||||||
struct seek_if_<typelist<Head, Tail...>, Fn, N> {
|
struct seek_if_<typelist<Head, Tail...>, Fn, N> {
|
||||||
// recursive call to seek_if_ until Fn returns true_
|
// recursive call to seek_if_ until Fn returns true_
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
invoke_t<Fn, Head>,
|
invoke_t<Fn, Head>,
|
||||||
typelist<Head, Tail...>, // done, return the typelist starting from here
|
typelist<Head, Tail...>, // done, return the typelist starting from here
|
||||||
eval<seek_if_< // not done, re-call seek_if_ with the Tail...
|
eval<seek_if_< // not done, re-call seek_if_ with the Tail...
|
||||||
typelist<Tail...>, Fn, N+1>
|
typelist<Tail...>, Fn, N+1>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -703,7 +701,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using seek_if = eval<
|
using seek_if = eval<
|
||||||
seek_if_impl::seek_if_<List, Pred, 0>
|
seek_if_impl::seek_if_<List, Pred, 0>
|
||||||
>;
|
>;
|
||||||
/*!
|
/*!
|
||||||
* Search for the first \c Item on the \p List of type \p T and return the rest
|
* Search for the first \c Item on the \p List of type \p T and return the rest
|
||||||
@ -724,13 +722,13 @@ namespace meta {
|
|||||||
// Recursive call to count_if_ up to the end of List, counting all invokes of Fn
|
// Recursive call to count_if_ up to the end of List, counting all invokes of Fn
|
||||||
// returning true_
|
// returning true_
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
invoke_t<Fn, Head>,
|
invoke_t<Fn, Head>,
|
||||||
eval<
|
eval<
|
||||||
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
|
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
|
||||||
>,
|
>,
|
||||||
eval<
|
eval<
|
||||||
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
|
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -753,7 +751,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using count_if = eval<
|
using count_if = eval<
|
||||||
count_if_impl::count_if_<List, Pred, 0>
|
count_if_impl::count_if_<List, Pred, 0>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -774,9 +772,9 @@ namespace meta {
|
|||||||
// Recursive call to filter_ up to the end of the List, creating a new list
|
// Recursive call to filter_ up to the end of the List, creating a new list
|
||||||
// of items for which the invoke of Fn returns true_
|
// of items for which the invoke of Fn returns true_
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
invoke_t <Fn, Head>,
|
invoke_t <Fn, Head>,
|
||||||
eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
|
eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
|
||||||
eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
|
eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -798,7 +796,7 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using filter = eval<
|
using filter = eval<
|
||||||
filter_impl::filter_<List, Pred, typelist<>>
|
filter_impl::filter_<List, Pred, typelist<>>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -813,9 +811,9 @@ namespace meta {
|
|||||||
// Recursive call to replace_if_ up to the end of the List, creating a new list
|
// Recursive call to replace_if_ up to the end of the List, creating a new list
|
||||||
// of items based on invocation of Fn
|
// of items based on invocation of Fn
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
invoke_t<Fn, Head>,
|
invoke_t<Fn, Head>,
|
||||||
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
|
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
|
||||||
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
|
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -839,14 +837,14 @@ namespace meta {
|
|||||||
*/
|
*/
|
||||||
template<typename List, typename Pred, typename T>
|
template<typename List, typename Pred, typename T>
|
||||||
using replace_if = eval<
|
using replace_if = eval<
|
||||||
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
|
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! Alias wrapper that returns a new \c typelist where all instances of type \p T have
|
//! Alias wrapper that returns a new \c typelist where all instances of type \p T have
|
||||||
//! been replaced with \p U.
|
//! been replaced with \p U.
|
||||||
template <typename List, typename T, typename U>
|
template <typename List, typename T, typename U>
|
||||||
using replace = eval <
|
using replace = eval <
|
||||||
replace_if <List, same_as<T>, U>
|
replace_if <List, same_as<T>, U>
|
||||||
>;
|
>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
@ -854,25 +852,30 @@ namespace meta {
|
|||||||
//! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the
|
//! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the
|
||||||
//! \p List is empty and \c false_ otherwise.
|
//! \p List is empty and \c false_ otherwise.
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using all_of = empty<
|
using all_of = if_ <
|
||||||
|
empty <List>,
|
||||||
|
false_,
|
||||||
|
empty <
|
||||||
filter <List, compose<quote<not_>, Pred>>
|
filter <List, compose<quote<not_>, Pred>>
|
||||||
|
>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List
|
//! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List
|
||||||
//! and \c false_ otherwise.
|
//! and \c false_ otherwise.
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using any_of = not_<
|
using any_of = not_<
|
||||||
empty<filter <List, Pred>>
|
empty<filter <List, Pred>>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List
|
//! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List
|
||||||
//! or if the \p List is empty and \c false otherwise.
|
//! or if the \p List is empty and \c false otherwise.
|
||||||
template <typename List, typename Pred>
|
template <typename List, typename Pred>
|
||||||
using none_of = empty<
|
using none_of = empty<
|
||||||
filter <List, Pred>
|
filter <List, Pred>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
#endif /* __utl_meta_pack_h__ */
|
|
||||||
|
#endif /* __utl_meta_typelist_h__ */
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#define __utl_meta_useif_h__
|
#define __utl_meta_useif_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
#include <utl/meta/logical.h>
|
#include <utl/meta/operations.h>
|
||||||
#include <utl/meta/sfinae.h>
|
#include <utl/meta/sfinae.h>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -35,32 +35,24 @@ namespace meta {
|
|||||||
|
|
||||||
//! If same type resolves to _Ret, else SFINAE
|
//! If same type resolves to _Ret, else SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
using use_if_same_t = eval<
|
using use_if_same_t = enable_if_t<
|
||||||
enable_if<
|
same_<_T1, _T2>::value, _Ret
|
||||||
same_<_T1, _T2>::value, _Ret
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
//! If not same type resolves to _Ret, else SFINAE
|
//! If not same type resolves to _Ret, else SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
using use_if_not_same_t = eval<
|
using use_if_not_same_t = enable_if_t<
|
||||||
enable_if<
|
!same_<_T1, _T2>::value, _Ret
|
||||||
!same_<_T1, _T2>::value, _Ret
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
|
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename T1, typename... Ts>
|
||||||
using use_if_any_t = eval<
|
using use_if_any_t = enable_if_t<
|
||||||
enable_if<
|
or_<T1, Ts...>::value, T1
|
||||||
or_<_T1, _T2>::value, _Ret
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE
|
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename T1, typename... Ts>
|
||||||
using use_if_both_t = eval<
|
using use_if_all_t = enable_if_t<
|
||||||
enable_if<
|
and_<T1, Ts...>::value, T1
|
||||||
and_<_T1, _T2>::value, _Ret
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file utl/utility/invoke.h
|
* \file utl/utility/invoke.h
|
||||||
* \brief invoke() and invoke() traits implementation
|
* \brief invoke() and invoke traits implementation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018-2019 Christos Choutouridis
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
*
|
*
|
||||||
@ -30,7 +30,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* \ingroup utility
|
* \ingroup utility
|
||||||
* \defgroup invoke
|
* \defgroup invoke
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
namespace utl {
|
namespace utl {
|
||||||
|
218
test/tests/TmetaBasic.cpp
Normal file
218
test/tests/TmetaBasic.cpp
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/*!
|
||||||
|
* \file TmetaBasic.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <utl/meta/meta.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace TmetaBasic {
|
||||||
|
using namespace utl;
|
||||||
|
using namespace meta;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types to behave like Fixtures
|
||||||
|
*/
|
||||||
|
// Test type_of fixture
|
||||||
|
template<class T> struct Identity {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test integral constant
|
||||||
|
*/
|
||||||
|
TEST(TmetaBasic, IntegrealType) {
|
||||||
|
EXPECT_EQ(true, (std::is_same<int, eval<Identity<int>>>::value));
|
||||||
|
EXPECT_EQ(true, (std::is_same<nil_, eval<nil_>>::value));
|
||||||
|
EXPECT_EQ(true, (std::is_same<nil_, eval<eval<nil_>>>::value));
|
||||||
|
EXPECT_EQ(true, (std::is_same<nil_, eval<eval<eval<nil_>>>>::value));
|
||||||
|
}
|
||||||
|
TEST(TmetaBasic, IntegrealConstant) {
|
||||||
|
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::value_type>::value));
|
||||||
|
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::type::value_type>::value));
|
||||||
|
EXPECT_EQ(42, (integral_<int, 0>::value_type(42)));
|
||||||
|
EXPECT_EQ(42, (integral_<int, 42>()));
|
||||||
|
}
|
||||||
|
TEST(TmetaBasic, BasicTypes) {
|
||||||
|
EXPECT_EQ(true, (std::is_same<bool, bool_<false>::value_type>::value));
|
||||||
|
EXPECT_EQ(true, bool_<true>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<bool, false_::value_type>::value));
|
||||||
|
EXPECT_EQ(false, false_::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<bool, true_::value_type>::value));
|
||||||
|
EXPECT_EQ(true, true_::value);
|
||||||
|
|
||||||
|
EXPECT_EQ(true, (std::is_same<int8_t, int8_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, int8_<42>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<uint8_t, uint8_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42u, uint8_<42u>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<int16_t, int16_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, int16_<42>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<uint16_t, uint16_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42u, uint16_<42u>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<int32_t, int32_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, int32_<42>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<uint32_t, uint32_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42u, uint32_<42u>::value);
|
||||||
|
|
||||||
|
EXPECT_EQ(true, (std::is_same<char, char_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, char_<42>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<int, int_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, int_<42>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<long, long_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42, long_<42>::value);
|
||||||
|
|
||||||
|
EXPECT_EQ(true, (std::is_same<index_t, index_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42U, index_<42U>::value);
|
||||||
|
EXPECT_EQ(true, (std::is_same<size_t, size_<0>::value_type>::value));
|
||||||
|
EXPECT_EQ(42U, size_<42U>::value);
|
||||||
|
|
||||||
|
EXPECT_EQ(sizeof(int), sizeof_<int>::value);
|
||||||
|
EXPECT_EQ(alignof(int), alignof_<int>::value);
|
||||||
|
EXPECT_EQ(static_cast<index_t>(-1), Npos::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test integral constant selection operations
|
||||||
|
*/
|
||||||
|
TEST(TmetaBasic, Selection) {
|
||||||
|
struct Foo {};
|
||||||
|
struct Bar {};
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<int_<42>, if_c<true, int_<42>, false_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<Foo, if_c<false, int_<42>, Foo>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<Foo, if_c<42, Foo, Bar>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<int_<42>, if_<true_, int_<42>, Bar>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<Bar, if_<false_, int_<42>, Bar>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<int_<42>, if_<int_<1>, int_<42>, Bar>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<Foo, if_<int_<0>, int_<42>, Foo>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, first_of<true_, false_>>()));
|
||||||
|
EXPECT_EQ (false,(std::is_same<true_, first_of<false_, true_>>()));
|
||||||
|
EXPECT_EQ (false,(std::is_same<true_, second_of<true_, false_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, second_of<false_, true_>>()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TmetaBasic, LogicalOperations) {
|
||||||
|
struct Foo {};
|
||||||
|
struct Bar {};
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, not_c<false>>::value));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, not_c<true>>::value));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, not_c<1>>::value));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, not_c<0>>::value));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, not_<false_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, not_<true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, not_<int_<0>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, not_<int_<1>>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, or_<false_, false_, not_c<true>, int_<0>, not_<true_>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, or_<>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<int_<1>,or_<int_<1>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, or_<true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, or_<false_, true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, or_<false_, false_, true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<int_<1>,or_<int_<0>, false_, not_<true_>, not_c<true>, int_<1>>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, int_<1>, not_<false_>, not_c<false>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, and_<>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, and_<true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, and_<false_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, and_<true_, false_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, true_>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, and_<true_, true_, false_>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (same_<Foo, Foo>()));
|
||||||
|
EXPECT_EQ (false, (same_<Foo, Bar>()));
|
||||||
|
EXPECT_EQ (true, (not_same_<Foo, Bar>()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test integral constant arithmetic operations
|
||||||
|
*/
|
||||||
|
TEST(TmetaBasic, ArithmeticOperations) {
|
||||||
|
EXPECT_EQ (int_<42>(), inc<int_<41>>());
|
||||||
|
EXPECT_EQ (int_<42>(), dec<int_<43>>());
|
||||||
|
EXPECT_EQ (int_<42>(), (add<int_<23>, add<int_<17>, int_<2>>>()));
|
||||||
|
EXPECT_EQ (int_<42>(), (sub<int_<108>, int_<66>>()));
|
||||||
|
EXPECT_EQ (int_<42>(), (mult<int_<7>, mult<int_<3>, int_<2>>>()));
|
||||||
|
EXPECT_EQ (int_<42>(), (divide<int_<210>, int_<5>>()));
|
||||||
|
EXPECT_EQ (int_<42>(), negate<int_<-42>>());
|
||||||
|
EXPECT_EQ (int_< 1>(), (modulo<int_<43>, int_<42>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test integral constant comparison operations
|
||||||
|
*/
|
||||||
|
TEST(TmetaBasic, ComparisonOperations) {
|
||||||
|
EXPECT_EQ (true, (comp_eq<int_<7>, int_<7>>()));
|
||||||
|
EXPECT_EQ (false, (comp_eq<int_<42>, int_<7>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (comp_ne<int_<42>, int_<7>>()));
|
||||||
|
EXPECT_EQ (false, (comp_ne<int_<42>, int_<42>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (comp_lt<int_<42>, int_<43>>()));
|
||||||
|
EXPECT_EQ (false, (comp_lt<int_<43>, int_<42>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (comp_gt<int_<43>, int_<42>>()));
|
||||||
|
EXPECT_EQ (false, (comp_gt<int_<42>, int_<43>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (comp_le<int_<42>, int_<43>>()));
|
||||||
|
EXPECT_EQ (true, (comp_le<int_<42>, int_<42>>()));
|
||||||
|
EXPECT_EQ (false, (comp_le<int_<43>, int_<42>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (comp_ge<int_<43>, int_<42>>()));
|
||||||
|
EXPECT_EQ (true, (comp_ge<int_<42>, int_<42>>()));
|
||||||
|
EXPECT_EQ (false, (comp_ge<int_<42>, int_<43>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test integral constant bit operations
|
||||||
|
*/
|
||||||
|
TEST(TmetaBasic, BitOperations) {
|
||||||
|
EXPECT_EQ (0x00, (bitand_<uint8_<0x55>, uint8_<0xAA>>()));
|
||||||
|
EXPECT_EQ (0xFF, (bitor_ <uint8_<0x55>, uint8_<0xAA>>()));
|
||||||
|
EXPECT_EQ (0xFA, (bitxor_<uint8_<0x55>, uint8_<0xAF>>()));
|
||||||
|
EXPECT_EQ (0x00, (bitnot_<uint8_<-1>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (0x04, (shift_left<uint8_<0x01>, uint8_<2>>()));
|
||||||
|
EXPECT_EQ (0x00, (shift_left<uint8_<0x80>, uint8_<1>>()));
|
||||||
|
EXPECT_EQ (0x02, (shift_right<uint8_<0x08>, uint8_<2>>()));
|
||||||
|
EXPECT_EQ (0x00, (shift_right<uint8_<0x01>, uint8_<1>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SFINAE
|
||||||
|
*/
|
||||||
|
template <typename T, typename =when<same_<T, int>::type::value>>
|
||||||
|
int check (T x) { return x; }
|
||||||
|
int check (...) { return 0; }
|
||||||
|
|
||||||
|
TEST(TmetaBasic, Sfinae) {
|
||||||
|
EXPECT_EQ (42, check(42));
|
||||||
|
EXPECT_EQ (0, check(42.0));
|
||||||
|
EXPECT_EQ (0, check());
|
||||||
|
|
||||||
|
// enable_if is imported so we trust stl and skip testing it
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
162
test/tests/TmetaDetection.cpp
Normal file
162
test/tests/TmetaDetection.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*!
|
||||||
|
* \file TmetaDetection.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <utl/meta/meta.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace TmetaDetection {
|
||||||
|
using namespace utl;
|
||||||
|
using namespace meta;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types to behave like Fixtures
|
||||||
|
*/
|
||||||
|
struct Foo {};
|
||||||
|
struct Bar {};
|
||||||
|
|
||||||
|
template <typename T> struct A {
|
||||||
|
using type = T; // nested type
|
||||||
|
A(int i, double d) : i_(i), d_(d) {} // declare a non-trivial constructor
|
||||||
|
A& operator++() { ++i_; return *this; } // declare an operator
|
||||||
|
|
||||||
|
// A sfinae function
|
||||||
|
template <typename TT = T, typename = when<std::is_integral<TT>::type::value>>
|
||||||
|
TT sfun () { return TT{}; }
|
||||||
|
private:
|
||||||
|
int i_; double d_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A binary metafunction
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct mFun {
|
||||||
|
using type = std::is_same <T1, T2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// detectors
|
||||||
|
template <typename T> using try_type = typename T::type;
|
||||||
|
template <typename T> using try_none = typename T::none;
|
||||||
|
template <typename T> using try_ctor1= decltype (T(std::declval<int>(), std::declval<double>()));
|
||||||
|
template <typename T> using try_ctor2= decltype (T(std::declval<int>()));
|
||||||
|
template <typename T> using try_ppT = decltype (++(std::declval<T>()));
|
||||||
|
template <typename T> using try_Tpp = decltype (std::declval<T>()++);
|
||||||
|
template <typename T> using try_sfun = decltype (std::declval<T>().sfun());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void_t
|
||||||
|
*/
|
||||||
|
TEST(TmetaDetection, VoidType) {
|
||||||
|
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, void*, void, Foo, Bar>>()));
|
||||||
|
EXPECT_EQ(true, (std::is_same<void, void_t<>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not a type
|
||||||
|
*/
|
||||||
|
TEST(TmetaDetection, NotAType) {
|
||||||
|
EXPECT_EQ(false, (std::is_default_constructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_destructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_copy_constructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_copy_assignable<nat_>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Idiom
|
||||||
|
*/
|
||||||
|
TEST(TmetaDetection, IsDetected) {
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_type, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_none, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_ctor1, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_ctor2, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_ppT, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_Tpp, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_sfun, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_sfun, A<double>> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same< true_, is_detected<mFun, int, void> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<mFun, char> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< false_, is_detected<mFun, char, void, void> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (is_detected_v<try_type, A<int>>));
|
||||||
|
EXPECT_EQ (false,(is_detected_v<try_none, A<int>>));
|
||||||
|
EXPECT_EQ (true, (is_detected_v<mFun, int, void>));
|
||||||
|
|
||||||
|
// typePrinter (detected_t<try_none, A>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Idiom
|
||||||
|
*/
|
||||||
|
TEST(TmetaDetection, Toolkit) {
|
||||||
|
|
||||||
|
// detected_t
|
||||||
|
EXPECT_EQ (true, (std::is_same< int, detected_t<try_type, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_none, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< A<int>, detected_t< try_ctor1, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_ctor2, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< A<int>&,detected_t< try_ppT, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_Tpp, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< int, detected_t< try_sfun, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_sfun, A<double>> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same< nat_, detected_t<mFun, void> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< mFun<int, int>,
|
||||||
|
detected_t<mFun, int, int> >()));
|
||||||
|
|
||||||
|
// detected_or_t
|
||||||
|
EXPECT_EQ (true, (std::is_same< int, detected_or_t<Foo, try_type, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< Foo, detected_or_t<Foo, try_none, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< A<int>, detected_or_t<void, try_ctor1, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< void, detected_or_t<void, try_ctor2, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< A<int>&,detected_or_t<nil_, try_ppT, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nil_, detected_or_t<nil_, try_Tpp, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< int, detected_or_t<void*, try_sfun, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< void*, detected_or_t<void*, try_sfun, A<double>> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same< nil_, detected_or_t<nil_, mFun, int> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< mFun<char, int>,
|
||||||
|
detected_or_t<void, mFun, char, int> >()));
|
||||||
|
|
||||||
|
// is_detected_exact
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< int, try_type, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< int, try_none, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< A<int>, try_ctor1, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< A<int>, try_ctor2, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< A<int>&,try_ppT, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< A<int>&,try_Tpp, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< int, try_sfun, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< int, try_sfun, A<double>> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact<mFun<char, int>, mFun, char, int> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact<mFun<int, int>, mFun, int> >())); // it would be better to check against mFun<int>
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (is_detected_exact_v< int, try_type, A<int>> ));
|
||||||
|
EXPECT_EQ (false,(is_detected_exact_v< int, try_none, A<int>> ));
|
||||||
|
|
||||||
|
// is_detected_convertible
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, is_detected_convertible< int, try_type, A<char>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_convertible< int, try_none, A<int>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, is_detected_convertible< mFun<int, int>, mFun, char, int> >()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (is_detected_convertible_v< int, try_type, A<char>> ));
|
||||||
|
EXPECT_EQ (false,(is_detected_convertible_v< int, try_none, A<int>> ));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file Tmeta.cpp
|
* \file TmetaTypelist.cpp
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Christos Choutouridis
|
* Copyright (C) 2018 Christos Choutouridis
|
||||||
*
|
*
|
||||||
@ -21,7 +21,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace test_meta {
|
namespace TmetaTypelist {
|
||||||
using namespace utl;
|
using namespace utl;
|
||||||
using namespace meta;
|
using namespace meta;
|
||||||
|
|
||||||
@ -53,168 +53,91 @@ namespace test_meta {
|
|||||||
using type = std::is_void<T>;
|
using type = std::is_void<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Test integral constant
|
|
||||||
*/
|
|
||||||
TEST(Tmeta, IntegrealType) {
|
|
||||||
EXPECT_EQ(true, (std::is_same<int, eval<Identity<int>>>::value));
|
|
||||||
}
|
|
||||||
TEST(Tmeta, IntegrealConstant) {
|
|
||||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::value_type>::value));
|
|
||||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::type::value_type>::value));
|
|
||||||
EXPECT_EQ(42, (integral_<int, 0>::value_type(42)));
|
|
||||||
EXPECT_EQ(42, (integral_<int, 42>()));
|
|
||||||
}
|
|
||||||
TEST(Tmeta, BasicTypes) {
|
|
||||||
EXPECT_EQ(true, (std::is_same<bool, bool_<false>::value_type>::value));
|
|
||||||
EXPECT_EQ(true, bool_<true>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<bool, false_::value_type>::value));
|
|
||||||
EXPECT_EQ(false, false_::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<bool, true_::value_type>::value));
|
|
||||||
EXPECT_EQ(true, true_::value);
|
|
||||||
|
|
||||||
EXPECT_EQ(true, (std::is_same<int8_t, int8_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, int8_<42>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<uint8_t, uint8_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42u, uint8_<42u>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<int16_t, int16_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, int16_<42>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<uint16_t, uint16_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42u, uint16_<42u>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<int32_t, int32_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, int32_<42>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<uint32_t, uint32_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42u, uint32_<42u>::value);
|
|
||||||
|
|
||||||
EXPECT_EQ(true, (std::is_same<char, char_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, char_<42>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<int, int_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, int_<42>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<long, long_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42, long_<42>::value);
|
|
||||||
|
|
||||||
EXPECT_EQ(true, (std::is_same<index_t, index_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42U, index_<42U>::value);
|
|
||||||
EXPECT_EQ(true, (std::is_same<size_t, size_<0>::value_type>::value));
|
|
||||||
EXPECT_EQ(42U, size_<42U>::value);
|
|
||||||
|
|
||||||
EXPECT_EQ(sizeof(int), sizeof_<int>::value);
|
|
||||||
EXPECT_EQ(alignof(int), alignof_<int>::value);
|
|
||||||
EXPECT_EQ(static_cast<index_t>(-1), Npos::value);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Test integral constant arithmetic operations
|
|
||||||
*/
|
|
||||||
TEST(Tmeta, ArithmeticOperations) {
|
|
||||||
EXPECT_EQ (int_<42>(), inc<int_<41>>());
|
|
||||||
EXPECT_EQ (int_<42>(), dec<int_<43>>());
|
|
||||||
EXPECT_EQ (int_<42>(), (add<int_<23>, add<int_<17>, int_<2>>>()));
|
|
||||||
EXPECT_EQ (int_<42>(), (sub<int_<108>, int_<66>>()));
|
|
||||||
EXPECT_EQ (int_<42>(), (mult<int_<7>, mult<int_<3>, int_<2>>>()));
|
|
||||||
EXPECT_EQ (int_<42>(), (divide<int_<210>, int_<5>>()));
|
|
||||||
EXPECT_EQ (int_<42>(), negate<int_<-42>>());
|
|
||||||
EXPECT_EQ (int_< 1>(), (modulo<int_<43>, int_<42>>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test logical
|
* Test high order metaFun tools
|
||||||
*/
|
*/
|
||||||
TEST(Tmeta, ComparisonOperations) {
|
TEST(TmetaTypelist, Invoke) {
|
||||||
EXPECT_EQ (true, (std::is_same<bool_<true>, not_c<false>>::value));
|
using W = wrap <MfunBin>;
|
||||||
EXPECT_EQ (true, (comp_eq<int_<7>, int_<7>>()));
|
using Wi = wrap_i<int, MfunBin_i>;
|
||||||
EXPECT_EQ (true, (comp_ne<int_<42>, int_<7>>()));
|
using W1 = wrap<MfunUn1>;
|
||||||
EXPECT_EQ (true, (comp_lt<int_<42>, int_<43>>()));
|
using W2 = wrap<MfunUn2>;
|
||||||
EXPECT_EQ (true, (comp_gt<int_<43>, int_<42>>()));
|
|
||||||
EXPECT_EQ (true, (comp_le<int_<42>, int_<42>>()));
|
|
||||||
EXPECT_EQ (true, (comp_ge<int_<42>, int_<42>>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Tmeta, BitOperations) {
|
|
||||||
EXPECT_EQ (0x00, (bitand_<uint8_<0x55>, uint8_<0xAA>>()));
|
|
||||||
EXPECT_EQ (0xFF, (bitor_ <uint8_<0x55>, uint8_<0xAA>>()));
|
|
||||||
EXPECT_EQ (0xFA, (bitxor_<uint8_<0x55>, uint8_<0xAF>>()));
|
|
||||||
EXPECT_EQ (0x00, (bitnot_<uint8_<-1>>()));
|
|
||||||
|
|
||||||
EXPECT_EQ (0x04, (shift_left<uint8_<0x01>, uint8_<2>>()));
|
|
||||||
EXPECT_EQ (0x00, (shift_left<uint8_<0x80>, uint8_<1>>()));
|
|
||||||
EXPECT_EQ (0x02, (shift_right<uint8_<0x08>, uint8_<2>>()));
|
|
||||||
EXPECT_EQ (0x00, (shift_right<uint8_<0x01>, uint8_<1>>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Tmeta, TypeOperations) {
|
|
||||||
struct Foo {};
|
|
||||||
struct Bar {};
|
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<bool_<true>, not_<bool_<false>>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_c<true, int_<42>, bool_<false>>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_<bool_<true>, int_<42>, bool_<false>>>()));
|
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<true_, or_<true_, false_>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<false_, or_<false_, false_>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<false_, and_<true_, false_>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_>>()));
|
|
||||||
|
|
||||||
EXPECT_EQ (true, (same_<Foo, Foo>()));
|
|
||||||
EXPECT_EQ (false, (same_<Foo, Bar>()));
|
|
||||||
EXPECT_EQ (true, (not_same_<Foo, Bar>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test void_t
|
|
||||||
*/
|
|
||||||
TEST(Tmeta, VoidType) {
|
|
||||||
struct Foo {};
|
|
||||||
struct Bar {};
|
|
||||||
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, Foo, Bar>>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test invoke
|
|
||||||
*/
|
|
||||||
TEST(Tmeta, Invoke) {
|
|
||||||
using Q = quote<MfunBin>;
|
using Q = quote<MfunBin>;
|
||||||
using Qi = quote_i<int, MfunBin_i>;
|
using Qi = quote_i<int, MfunBin_i>;
|
||||||
using Q1 = quote<MfunUn1>;
|
using Q1 = quote<MfunUn1>;
|
||||||
using Q2 = quote<MfunUn2>;
|
using Q2 = quote<MfunUn2>;
|
||||||
|
|
||||||
|
// identity
|
||||||
|
EXPECT_EQ (true, (std::is_same<int, eval<identity<int>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<int, identity_t<int>>()));
|
EXPECT_EQ (true, (std::is_same<int, identity_t<int>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<void*, identity_t<void*>>()));
|
||||||
|
|
||||||
|
// invoke, check that invoke un-wraps and un-quotes staff
|
||||||
|
EXPECT_EQ (true, (std::is_same< invoke<wrap<MfunBin>, int, char>, MfunBin<int, char> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< invoke<quote<MfunBin>, int, char>, MfunBin<int, char> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< invoke<wrap_i<int, MfunBin_i>, int_<7>, int_<42>>, MfunBin_i<7, 42> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< invoke<quote_i<int, MfunBin_i>, int_<7>, int_<42>>, MfunBin_i<7, 42> >()));
|
||||||
|
|
||||||
|
// Wrap
|
||||||
|
EXPECT_EQ (true, (std::is_same< wrap<MfunBin>::template apply<int, char>, MfunBin<int, char> >()));
|
||||||
|
EXPECT_EQ (false, (std::is_same< wrap<MfunBin>::template apply<int, char>, MfunBin<int, int> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< wrap_i<int, MfunBin_i>::template apply<int_<7>, int_<42>>, MfunBin_i<7, 42> >()));
|
||||||
|
EXPECT_EQ (false, (std::is_same< wrap_i<int, MfunBin_i>::template apply<int_<7>, int_<42>>, MfunBin_i<42, 7> >()));
|
||||||
|
|
||||||
|
// applicable trait
|
||||||
EXPECT_EQ (true, (is_applicable_t<MfunBin, int, long>()));
|
EXPECT_EQ (true, (is_applicable_t<MfunBin, int, long>()));
|
||||||
EXPECT_EQ (false, (is_applicable_t<MfunBin, int>()));
|
EXPECT_EQ (false, (is_applicable_t<MfunBin, int>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (is_applicable_qt<Q, int, long>()));
|
EXPECT_EQ (true, (is_applicable_qt<Q, int, long>()));
|
||||||
EXPECT_EQ (false, (is_applicable_qt<Q, int>()));
|
EXPECT_EQ (false, (is_applicable_qt<Q, int>()));
|
||||||
|
EXPECT_EQ (true, (is_applicable_qt<W, int, long>()));
|
||||||
|
EXPECT_EQ (false, (is_applicable_qt<W, int>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (is_applicable_it<int, MfunBin_i, 7, 42>()));
|
EXPECT_EQ (true, (is_applicable_it<int, MfunBin_i, 7, 42>()));
|
||||||
EXPECT_EQ (false, (is_applicable_it<int, MfunBin_i, 42>()));
|
EXPECT_EQ (false, (is_applicable_it<int, MfunBin_i, 42>()));
|
||||||
|
|
||||||
|
// defer
|
||||||
EXPECT_EQ (true, (std::is_same<defer<MfunBin, int, void>::type, MfunBin<int, void>>()));
|
EXPECT_EQ (true, (std::is_same<defer<MfunBin, int, void>::type, MfunBin<int, void>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<defer<MfunBin, void>::type, nil_>()));
|
EXPECT_EQ (true, (std::is_same<defer<MfunBin, void>::type, nil_>()));
|
||||||
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7, 42>::type, MfunBin_i<7, 42>>()));
|
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7, 42>::type, MfunBin_i<7, 42>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7>::type, nil_>()));
|
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7>::type, nil_>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<Q, int>, nil_>()));
|
// quote
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<Q, int, void*>, MfunBin<int, void*>>()));
|
EXPECT_EQ (true, (std::is_same< quote<MfunBin>::template apply<int, void*>, MfunBin<int, void*> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<Qi, int_<7>, int_<42>>, MfunBin_i<7, 42>>()));
|
EXPECT_EQ (false,(std::is_same< quote<MfunBin>::template apply<int, void*>, MfunBin<int, int> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<Qi, int_<42>>, nil_>()));
|
EXPECT_EQ (true, (std::is_same< quote_i<int, MfunBin_i>::template apply< int_<7>, int_<42>>, MfunBin_i<7, 42> >()));
|
||||||
|
EXPECT_EQ (false,(std::is_same< quote_i<int, MfunBin_i>::template apply< int_<7>, int_<42>>, MfunBin_i<42, 7> >()));
|
||||||
|
|
||||||
|
// compose
|
||||||
|
EXPECT_EQ (true, (std::is_same<invoke<compose_f<MfunUn1>, int>, MfunUn1<int>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<invoke<compose_f<MfunUn1, MfunUn2>, int>, MfunUn1<MfunUn2<int>>>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<invoke<compose<W1>, int>, MfunUn1<int>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<invoke<compose<W1, W2>, int>, MfunUn1<MfunUn2<int>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<
|
||||||
|
invoke<compose<W1, W2, Wi>, int_<7>, int_<42>>, MfunUn1<MfunUn2<MfunBin_i<7, 42>>>
|
||||||
|
>()));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1>, int>, MfunUn1<int>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1, Q2>, int>, MfunUn1<MfunUn2<int>>>()));
|
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1, Q2>, int>, MfunUn1<MfunUn2<int>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<
|
EXPECT_EQ (true, (std::is_same<
|
||||||
invoke<compose<Q1, Q2, Qi>, int_<7>, int_<42>>,
|
invoke<compose<Q1, Q2, Qi>, int_<7>, int_<42>>, MfunUn1<MfunUn2<MfunBin_i<7, 42>>>
|
||||||
MfunUn1<MfunUn2<MfunBin_i<7, 42>>>
|
>()));
|
||||||
>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<
|
|
||||||
invoke<compose<Q1, Q2, Qi>, int_<42>>,
|
|
||||||
MfunUn1<MfunUn2<nil_>>
|
|
||||||
>()));
|
|
||||||
|
|
||||||
|
// bind
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<bind_front<Q, int>, long>, MfunBin<int, long>>()));
|
EXPECT_EQ (true, (std::is_same<invoke<bind_front<Q, int>, long>, MfunBin<int, long>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<invoke<bind_back<Q, int>, long>, MfunBin<long, int>>()));
|
EXPECT_EQ (true, (std::is_same<invoke<bind_back<Q, int>, long>, MfunBin<long, int>>()));
|
||||||
|
|
||||||
|
// Check the case of ill formed parameter composition. Quote must save us
|
||||||
|
EXPECT_EQ (true, (std::is_same< nil_, invoke<Q, int> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< nil_, invoke<Qi, int_<42>> >()));
|
||||||
|
EXPECT_EQ (true, (std::is_same< MfunUn1<MfunUn2<nil_>>, invoke<compose<Q1, Q2, Qi>, int_<42>> >()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test typelist
|
* Test typelist
|
||||||
*/
|
*/
|
||||||
TEST(Tmeta_typelist, Basics) {
|
TEST(TmetaTypelist, Basics) {
|
||||||
using l1 = typelist<int, int, int>;
|
using l1 = typelist<int, int, int>;
|
||||||
using l2 = typelist<int, void*, int, void*>;
|
using l2 = typelist<int, void*, int, void*>;
|
||||||
using l3 = typelist<>;
|
using l3 = typelist<>;
|
||||||
@ -223,6 +146,7 @@ namespace test_meta {
|
|||||||
EXPECT_EQ (true, (std::is_same<l2, typelist<int, void*>::times<2>>()));
|
EXPECT_EQ (true, (std::is_same<l2, typelist<int, void*>::times<2>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<l3, typelist<>::times<3>>()));
|
EXPECT_EQ (true, (std::is_same<l3, typelist<>::times<3>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<l3, typelist<int>::times<0>>()));
|
EXPECT_EQ (true, (std::is_same<l3, typelist<int>::times<0>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<l3, typelist<int, void>::times<0>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<typelist<short, double>, pair<short, double>>()));
|
EXPECT_EQ (true, (std::is_same<typelist<short, double>, pair<short, double>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<l1, repeat <int_<3>, int>>()));
|
EXPECT_EQ (true, (std::is_same<l1, repeat <int_<3>, int>>()));
|
||||||
@ -230,29 +154,30 @@ namespace test_meta {
|
|||||||
|
|
||||||
|
|
||||||
EXPECT_EQ (3, size<l1>());
|
EXPECT_EQ (3, size<l1>());
|
||||||
|
EXPECT_EQ (0, size<l3>());
|
||||||
EXPECT_EQ (true, empty<l3>());
|
EXPECT_EQ (true, empty<l3>());
|
||||||
|
|
||||||
// pass typelist to an invocable
|
// pass typelist to an invocable
|
||||||
EXPECT_EQ (true, (std::is_same<eval<
|
EXPECT_EQ (true, (std::is_same< apply_t<quote<MfunUn1>, typelist<int>>, MfunUn1<int> >()));
|
||||||
apply<quote<MfunBin>, typelist<int, long>>
|
EXPECT_EQ (true, (std::is_same< apply_t<quote<MfunBin>, typelist<int, long>>, MfunBin<int, long> >()));
|
||||||
>,
|
|
||||||
MfunBin<int, long>
|
|
||||||
>()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Element_access) {
|
TEST(TmetaTypelist, ElementAccess) {
|
||||||
using l = typelist<char, void, long, double, short>;
|
using l = typelist<char*, void, void*, long, double, short>;
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<char*, at_c<l, 0>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<void*, at_c<l, 2>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<short, at_c<l, 5>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<nil_, at_c<l, 6>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<char, at_c<l, 0>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<long, at_c<l, 2>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<nil_, at_c<l, 5>>()));
|
|
||||||
EXPECT_EQ (true, (std::is_same<void, at<l, int_<1>>>()));
|
EXPECT_EQ (true, (std::is_same<void, at<l, int_<1>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<long, at<l, int_<3>>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<char, front<l>>()));
|
EXPECT_EQ (true, (std::is_same<char*, front<l>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<short, back<l>>()));
|
EXPECT_EQ (true, (std::is_same<short, back<l>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Concat) {
|
TEST(TmetaTypelist, Concat) {
|
||||||
using l1 = typelist<int, long, void>;
|
using l1 = typelist<int, long, void>;
|
||||||
using l2 = typelist<void*, int*>;
|
using l2 = typelist<void*, int*>;
|
||||||
using l3 = typelist<double, long double, short>;
|
using l3 = typelist<double, long double, short>;
|
||||||
@ -266,7 +191,7 @@ namespace test_meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T1, class T2> struct F {}; // binary invocable
|
template<class T1, class T2> struct F {}; // binary invocable
|
||||||
TEST(Tmeta_typelist, Fold) {
|
TEST(TmetaTypelist, Fold) {
|
||||||
struct X1 {};
|
struct X1 {};
|
||||||
struct X2 {};
|
struct X2 {};
|
||||||
struct X3 {};
|
struct X3 {};
|
||||||
@ -286,7 +211,7 @@ namespace test_meta {
|
|||||||
EXPECT_EQ(true, (std::is_same<rev_fold<typelist<X1, X2, X3, X4>, void, Q>, F<X1, F<X2, F<X3, F<X4, void>>>>>()));
|
EXPECT_EQ(true, (std::is_same<rev_fold<typelist<X1, X2, X3, X4>, void, Q>, F<X1, F<X2, F<X3, F<X4, void>>>>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, PushPopReverse) {
|
TEST(TmetaTypelist, PushPopReverse) {
|
||||||
using list = typelist <int, long, void>;
|
using list = typelist <int, long, void>;
|
||||||
using l_char = typelist <int, long, void, char>;
|
using l_char = typelist <int, long, void, char>;
|
||||||
using l_cc = typelist <int, long, void, char, char>;
|
using l_cc = typelist <int, long, void, char, char>;
|
||||||
@ -294,19 +219,19 @@ namespace test_meta {
|
|||||||
using cc_l = typelist<char, char, int, long, void>;
|
using cc_l = typelist<char, char, int, long, void>;
|
||||||
using rev = typelist<void, long, int>;
|
using rev = typelist<void, long, int>;
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<char_l, push_front<list, char>>()));
|
EXPECT_EQ (true, (std::is_same< char_l, push_front<list, char> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<cc_l, push_front<list, char, char>>()));
|
EXPECT_EQ (true, (std::is_same< cc_l, push_front<list, char, char> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<list, pop_front <char_l>>()));
|
EXPECT_EQ (true, (std::is_same< list, pop_front <char_l> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<l_char, push_back <list, char>>()));
|
EXPECT_EQ (true, (std::is_same< l_char, push_back <list, char> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<l_cc, push_back <list, char, char>>()));
|
EXPECT_EQ (true, (std::is_same< l_cc, push_back <list, char, char> >()));
|
||||||
EXPECT_EQ (true, (std::is_same<list, pop_back <l_char>>()));
|
EXPECT_EQ (true, (std::is_same< list, pop_back <l_char> >()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<rev, reverse <list>>()));
|
EXPECT_EQ (true, (std::is_same< rev, reverse <list> >()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Transform) {
|
TEST(TmetaTypelist, Transform) {
|
||||||
using QBin = quote<MfunBin>;
|
using QBin = quote<MfunBin>; // both metafuctions return int
|
||||||
using QUn = quote<MfunUn1>;
|
using QUn = quote<MfunUn1>;
|
||||||
|
|
||||||
using l1 = typelist<char, int, float>;
|
using l1 = typelist<char, int, float>;
|
||||||
using l2 = typelist<void, void, void>;
|
using l2 = typelist<void, void, void>;
|
||||||
@ -322,7 +247,7 @@ namespace test_meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Find) {
|
TEST(TmetaTypelist, Find) {
|
||||||
using l1 = typelist <int, char, long, float>;
|
using l1 = typelist <int, char, long, float>;
|
||||||
using l2 = typelist <char, long, float>;
|
using l2 = typelist <char, long, float>;
|
||||||
using l3 = typelist <long, float>;
|
using l3 = typelist <long, float>;
|
||||||
@ -341,7 +266,7 @@ namespace test_meta {
|
|||||||
EXPECT_EQ(true, (std::is_same<l3, seek<l1, long>>()));
|
EXPECT_EQ(true, (std::is_same<l3, seek<l1, long>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Count) {
|
TEST(TmetaTypelist, Count) {
|
||||||
using list = typelist<int, void*, char, int, long*, char, int, short>;
|
using list = typelist<int, void*, char, int, long*, char, int, short>;
|
||||||
using empty = typelist<>;
|
using empty = typelist<>;
|
||||||
|
|
||||||
@ -353,7 +278,7 @@ namespace test_meta {
|
|||||||
EXPECT_EQ (true, (std::is_same<size_<1>, count<list, void*>>()));
|
EXPECT_EQ (true, (std::is_same<size_<1>, count<list, void*>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Filter) {
|
TEST(TmetaTypelist, Filter) {
|
||||||
using Q1 = quote<Pred_isInt>;
|
using Q1 = quote<Pred_isInt>;
|
||||||
using Q2 = quote<Pred_isVoid>;
|
using Q2 = quote<Pred_isVoid>;
|
||||||
using list = typelist<int, float, char, long*, short, double, void*>;
|
using list = typelist<int, float, char, long*, short, double, void*>;
|
||||||
@ -362,9 +287,10 @@ namespace test_meta {
|
|||||||
EXPECT_EQ (true, (std::is_same<filtered, filter<list, Q1>>()));
|
EXPECT_EQ (true, (std::is_same<filtered, filter<list, Q1>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>()));
|
EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<typelist<>, filter<list, Q2>>()));
|
EXPECT_EQ (true, (std::is_same<typelist<>, filter<list, Q2>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tmeta_typelist, Replace) {
|
TEST(TmetaTypelist, Replace) {
|
||||||
using Q = quote<Pred_isInt>;
|
using Q = quote<Pred_isInt>;
|
||||||
using list = typelist<int, float, char, long*, short, double, void*>;
|
using list = typelist<int, float, char, long*, short, double, void*>;
|
||||||
using res = typelist<void,float, void, long*, void, double, void*>;
|
using res = typelist<void,float, void, long*, void, double, void*>;
|
||||||
@ -373,22 +299,44 @@ namespace test_meta {
|
|||||||
EXPECT_EQ (true, (std::is_same<res, replace_if<list, Q, void>>()));
|
EXPECT_EQ (true, (std::is_same<res, replace_if<list, Q, void>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>()));
|
EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<res, replace_if<res, Q, void>>()));
|
EXPECT_EQ (true, (std::is_same<res, replace_if<res, Q, void>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<repl, replace<list, char, void>>()));
|
EXPECT_EQ (true, (std::is_same<repl, replace<list, char, void>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<typelist<>, replace<typelist<>, char, void>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST (Tmeta_typelist, AllAnyNone) {
|
TEST (TmetaTypelist, AllAnyNone) {
|
||||||
using l1 = typelist<int, float, char, long*, short, double, void*>;
|
using l1 = typelist<int, float, char, long*, short, double, void*>;
|
||||||
using l2 = typelist<int, char, long, short>;
|
using l2 = typelist<int, char, long, short>;
|
||||||
|
using l3 = typelist<>;
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<false_, all_of<l1, quote<Pred_isInt>>>()));
|
EXPECT_EQ (true, (std::is_same<false_, all_of<l1, quote<Pred_isInt>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<true_, all_of<l2, quote<Pred_isInt>>>()));
|
EXPECT_EQ (true, (std::is_same<true_, all_of<l2, quote<Pred_isInt>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, all_of<l3, quote<Pred_isVoid>>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<true_, any_of<l1, quote<Pred_isInt>>>()));
|
EXPECT_EQ (true, (std::is_same<true_, any_of<l1, quote<Pred_isInt>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<false_, any_of<l2, quote<Pred_isVoid>>>()));
|
EXPECT_EQ (true, (std::is_same<false_, any_of<l2, quote<Pred_isVoid>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<false_, any_of<l3, quote<Pred_isVoid>>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<true_, none_of<l1, quote<Pred_isVoid>>>()));
|
EXPECT_EQ (true, (std::is_same<true_, none_of<l1, quote<Pred_isVoid>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<false_, none_of<l1, quote<Pred_isInt>>>()));
|
EXPECT_EQ (true, (std::is_same<false_, none_of<l1, quote<Pred_isInt>>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<true_, none_of<l3, quote<Pred_isInt>>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detection idiom
|
||||||
|
*/
|
||||||
|
TEST(Tmeta, DetectionVoidType) {
|
||||||
|
struct Foo {};
|
||||||
|
struct Bar {};
|
||||||
|
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, void*, void, Foo, Bar>>()));
|
||||||
|
EXPECT_EQ(true, (std::is_same<void, void_t<>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Tmeta, DetectionNotAType) {
|
||||||
|
EXPECT_EQ(false, (std::is_default_constructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_destructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_copy_constructible<nat_>()));
|
||||||
|
EXPECT_EQ(false, (std::is_copy_assignable<nat_>()));
|
||||||
|
}
|
||||||
}
|
}
|
@ -68,7 +68,7 @@ namespace test_i2c {
|
|||||||
uint8_t b = 42;
|
uint8_t b = 42;
|
||||||
|
|
||||||
i2c.clock(200000UL);
|
i2c.clock(200000UL);
|
||||||
EXPECT_EQ(i2c.clock(), 200000UL);
|
//EXPECT_EQ(i2c.clock(), 200000UL);
|
||||||
|
|
||||||
EXPECT_EQ(i2c.tx_data(b), true);
|
EXPECT_EQ(i2c.tx_data(b), true);
|
||||||
EXPECT_EQ(i2c.rx_data(true), 0x00);
|
EXPECT_EQ(i2c.rx_data(true), 0x00);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user