477 lines
13 KiB
C++
477 lines
13 KiB
C++
#ifndef PFOR_PFOR_MP_PACK_H
|
|
#define PFOR_PFOR_MP_PACK_H
|
|
|
|
#include "meta.h"
|
|
|
|
namespace pfor {
|
|
|
|
/**
|
|
* Pack data structure containing types
|
|
*/
|
|
template<typename...> struct Pack {};
|
|
|
|
/**
|
|
* @brief tests if P is a pack
|
|
*
|
|
* @param P
|
|
*
|
|
* @return true if P is a pack
|
|
*/
|
|
template<typename> struct IsPack: std::false_type {};
|
|
|
|
template<typename... Ts>
|
|
struct IsPack<Pack<Ts...>>: std::true_type {};
|
|
|
|
template<typename P>
|
|
constexpr bool isPack = IsPack<P>::value;
|
|
|
|
/**
|
|
* @brief access a pack element by its index
|
|
*
|
|
* @param P a pack
|
|
* @param I an index
|
|
*
|
|
* @return the pack element at index I
|
|
*/
|
|
template<typename...> struct PackGetImpl;
|
|
|
|
template<typename T, typename... Ts, std::size_t I>
|
|
struct PackGetImpl<Pack<T, Ts...>, UIntToType<I>> {
|
|
using type = typename PackGetImpl<Pack<Ts...>, UIntToType<I-1>>::type;
|
|
};
|
|
|
|
template<typename T, typename... Ts>
|
|
struct PackGetImpl<Pack<T, Ts...>, UIntToType<0>> {
|
|
using type = T;
|
|
};
|
|
|
|
template<typename P, std::size_t I>
|
|
using PackGet = typename PackGetImpl<P, UIntToType<I>>::type;
|
|
|
|
/**
|
|
* @brief computes the size of a pack
|
|
*
|
|
* @param P a pack
|
|
*
|
|
* @return the size of P
|
|
*/
|
|
template<typename> struct PackSize;
|
|
|
|
template<typename... Ts>
|
|
struct PackSize<Pack<Ts...>> {
|
|
static constexpr std::size_t value = sizeof...(Ts);
|
|
};
|
|
|
|
template<typename P>
|
|
constexpr std::size_t packSize = PackSize<P>::value;
|
|
|
|
/**
|
|
* @brief appends a type to a pack
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a type
|
|
*
|
|
* @return a new pack (P0, ..., Pn, T)
|
|
*/
|
|
template<typename...> struct PackAppendImpl;
|
|
|
|
template<typename T, typename... Ts>
|
|
struct PackAppendImpl<Pack<Ts...>, T> {
|
|
using type = Pack<Ts..., T>;
|
|
};
|
|
|
|
template<typename P, typename T>
|
|
using PackAppend = typename PackAppendImpl<P, T>::type;
|
|
|
|
/**
|
|
* @brief prepends a type to a pack
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a type
|
|
*
|
|
* @return a new pack (T, P0, ..., Pn)
|
|
*/
|
|
template<typename...> struct PackPrependImpl;
|
|
|
|
template<typename T, typename... Ts>
|
|
struct PackPrependImpl<Pack<Ts...>, T> {
|
|
using type = Pack<T, Ts...>;
|
|
};
|
|
|
|
template<typename P, typename T>
|
|
using PackPrepend = typename PackPrependImpl<P, T>::type;
|
|
|
|
/**
|
|
* @brief removes all occurrences a given type in a pack
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a type
|
|
*
|
|
* @return a new pack (P'0, ..., P'm) with P'i != T
|
|
*/
|
|
template<typename, typename, typename = Pack<>> struct PackRemoveImpl;
|
|
|
|
template<typename H, typename... Ts, typename E, typename... Outs>
|
|
struct PackRemoveImpl<Pack<H, Ts...>, E, Pack<Outs...>> {
|
|
using pack = If<std::is_same<H, E>{}, Pack<Outs...>, Pack<Outs..., H>>;
|
|
using type = typename PackRemoveImpl<Pack<Ts...>, E, pack>::type;
|
|
};
|
|
|
|
template<typename E, typename Out>
|
|
struct PackRemoveImpl<Pack<>, E, Out> {
|
|
using type = Out;
|
|
};
|
|
|
|
template<typename P, typename T>
|
|
using PackRemove = typename PackRemoveImpl<P, T>::type;
|
|
|
|
/**
|
|
* @brief tests a pack for any occurrence of a given type
|
|
*
|
|
* @param P a pack (P0, ... Pn)
|
|
* @param T a type
|
|
*
|
|
* @return true if any Pi == T
|
|
*/
|
|
template<typename, typename> struct PackContains;
|
|
|
|
template<typename H, typename... Ts, typename T>
|
|
struct PackContains<Pack<H, Ts...>, T> {
|
|
static constexpr bool value = std::is_same<H, T>::value || PackContains<Pack<Ts...>, T>::value;
|
|
};
|
|
|
|
template<typename T>
|
|
struct PackContains<Pack<>, T> {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template<typename P, typename T>
|
|
constexpr bool packContains = PackContains<P, T>::value;
|
|
|
|
/**
|
|
* @brief tests if a pack contains another pack
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param Q a pack (Q0, ..., Qn)
|
|
*
|
|
* @return true if all Qi are in P
|
|
*/
|
|
template<typename, typename> struct PackContainsAll;
|
|
|
|
template<typename P, typename H, typename... Ts>
|
|
struct PackContainsAll<P, Pack<H, Ts...>> {
|
|
static constexpr bool value = packContains<P, H> && PackContainsAll<P, Pack<Ts...>>::value;
|
|
};
|
|
|
|
template<typename P>
|
|
struct PackContainsAll<P, Pack<>> {
|
|
static constexpr bool value = true;
|
|
};
|
|
|
|
template<typename P, typename Q>
|
|
constexpr bool packContainsAll = PackContainsAll<P, Q>::value;
|
|
|
|
/**
|
|
* @brief tests if two packs intersect (non empty intersection)
|
|
*
|
|
* @param P0 a pack (P00, ..., P0n)
|
|
* @param P1 a pack (P10, ..., P1n)
|
|
*
|
|
* @return true if any P0i == P1j
|
|
*/
|
|
template<typename, typename> struct PackIntersects;
|
|
|
|
template<typename P, typename H, typename... Ts>
|
|
struct PackIntersects<P, Pack<H, Ts...>> {
|
|
static constexpr bool value = packContains<P, H> || PackIntersects<P, Pack<Ts...>>::value;
|
|
};
|
|
|
|
template<typename P>
|
|
struct PackIntersects<P, Pack<>> {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template<typename P0, typename P1>
|
|
constexpr bool packIntersects = PackIntersects<P0, P1>::value;
|
|
|
|
/**
|
|
* @brief inserts a new element in not already contained
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a new element
|
|
*
|
|
* @return a pack (P0, ..., Pn, T) if T != Pi, else P
|
|
*/
|
|
template<typename P, typename T>
|
|
struct PackInsertUniqImpl {
|
|
using type = If<packContains<P, T>, P, PackAppend<P, T>>;
|
|
};
|
|
|
|
template<typename P, typename T>
|
|
using PackInsetUniq = typename PackInsertUniqImpl<P, T>::type;
|
|
|
|
/**
|
|
* @brief computes a new pack containing any element only once
|
|
*
|
|
* @param P a pack (P0, ..., Pn)
|
|
*
|
|
* @return a pack (P'0, ..., P'm) with P'i != P'j for i != j
|
|
*/
|
|
template<typename, typename = Pack<>> struct PackUniqImpl;
|
|
|
|
template<typename IH, typename... ITs, typename... OTs>
|
|
struct PackUniqImpl<Pack<IH, ITs...>, Pack<OTs...>> {
|
|
using out = If<packContains<Pack<OTs...>, IH>, Pack<OTs...>, Pack<OTs..., IH>>;
|
|
using type = typename PackUniqImpl<Pack<ITs...>, out>::type;
|
|
};
|
|
|
|
template<typename... OTs>
|
|
struct PackUniqImpl<Pack<>, Pack<OTs...>> {
|
|
using type = Pack<OTs...>;
|
|
};
|
|
|
|
template<typename P>
|
|
using PackUniq = typename PackUniqImpl<P>::type;
|
|
|
|
/**
|
|
* @brief merges packs
|
|
*
|
|
* @param Ps a list of packs (P00, ..., P0n0)...(Px0, ..., Pxnx)
|
|
*
|
|
* @return a new pack (P00, ..., P0n0, ..., Px0, ..., Pxnx)
|
|
*/
|
|
template<typename...> struct PackMergeImpl;
|
|
|
|
template<typename... Ts, typename... Us, typename... Trail>
|
|
struct PackMergeImpl<Pack<Ts...>, Pack<Us...>, Trail...> {
|
|
using type = typename PackMergeImpl<Pack<Ts..., Us...>, Trail...>::type;
|
|
};
|
|
|
|
template<typename... Ts>
|
|
struct PackMergeImpl<Pack<Ts...>> {
|
|
using type = Pack<Ts...>;
|
|
};
|
|
|
|
template<>
|
|
struct PackMergeImpl<> {
|
|
using type = Pack<>;
|
|
};
|
|
|
|
template<typename... Ps>
|
|
using PackMerge = typename PackMergeImpl<Ps...>::type;
|
|
|
|
/**
|
|
* @brief merges unique elements from packs
|
|
*
|
|
* @param Ps a list of packs (P00, ..., P0n0)...(Px0, ..., Pxnx)
|
|
*
|
|
* @return the union of all packs Ps
|
|
*/
|
|
template<typename... Packs> struct PackUnionImpl {
|
|
using type = PackUniq<PackMerge<Packs...>>;
|
|
};
|
|
|
|
template<typename... Ps>
|
|
using PackUnion = typename PackUnionImpl<Ps...>::type;
|
|
|
|
namespace impl {
|
|
|
|
/**
|
|
* @brief computes a pack containing elements before a given one
|
|
*
|
|
* @param Comparator a comparator
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a type
|
|
*
|
|
* @return a new pack with elements before T
|
|
*/
|
|
namespace detail {
|
|
|
|
template<template<typename, typename> class, typename, typename, typename> struct PackSortBeforeImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename... Bs, typename T, typename... Ts, typename U>
|
|
struct PackSortBeforeImpl<Comparator, Pack<Bs...>, Pack<T, Ts...>, U> {
|
|
using trail = typename PackSortBeforeImpl<Comparator, Pack<Bs..., T>, Pack<Ts...>, U>::type;
|
|
using type = If<Comparator<T, U>::value, trail, Pack<Bs...>>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename... Bs, typename U>
|
|
struct PackSortBeforeImpl<Comparator, Pack<Bs...>, Pack<>, U> {
|
|
using type = Pack<Bs...>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P, typename T>
|
|
using PackSortBefore = typename PackSortBeforeImpl<Comparator, Pack<>, P, T>::type;
|
|
|
|
}
|
|
|
|
template<template<typename, typename> class, typename, typename> struct PackSortBeforeImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename... Ts, typename U>
|
|
struct PackSortBeforeImpl<Comparator, Pack<Ts...>, U> {
|
|
using type = detail::PackSortBefore<Comparator, Pack<Ts...>, U>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P, typename T>
|
|
using PackSortBefore = typename PackSortBeforeImpl<Comparator, P, T>::type;
|
|
|
|
/**
|
|
* @brief computes a pack containing elements after a given one
|
|
*
|
|
* @param Comparator a comparator
|
|
* @param P a pack (P0, ..., Pn)
|
|
* @param T a type
|
|
*
|
|
* @return a new pack with elements after T
|
|
*/
|
|
namespace detail {
|
|
|
|
template<template<typename, typename> class, typename, typename, typename> struct PackSortAfterImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename... Bs, typename T, typename... Ts, typename U>
|
|
struct PackSortAfterImpl<Comparator, Pack<Bs...>, Pack<T, Ts...>, U> {
|
|
using trail = typename PackSortAfterImpl<Comparator, Pack<Bs..., T>, Pack<Ts...>, U>::type;
|
|
using type = If<Comparator<T, U>::value, trail, Pack<T, Ts...>>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename... Bs, typename U>
|
|
struct PackSortAfterImpl<Comparator, Pack<Bs...>, Pack<>, U> {
|
|
using type = Pack<>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P, typename T>
|
|
using PackSortAfter = typename PackSortAfterImpl<Comparator, Pack<>, P, T>::type;
|
|
|
|
}
|
|
|
|
template<template<typename, typename> class, typename, typename> struct PackSortAfterImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename... Ts, typename U>
|
|
struct PackSortAfterImpl<Comparator, Pack<Ts...>, U> {
|
|
using type = detail::PackSortAfter<Comparator, Pack<Ts...>, U>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P, typename T>
|
|
using PackSortAfter = typename PackSortAfterImpl<Comparator, P, T>::type;
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief insert an element into a sorted pack
|
|
*
|
|
* @param Comparator a comparator
|
|
* @param P a sorted pack
|
|
* @param T a type
|
|
*
|
|
* @return a new sorted pack containing T
|
|
*/
|
|
template<template<typename, typename> class, typename, typename> struct PackSortInsertImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename... Ts, typename T>
|
|
struct PackSortInsertImpl<Comparator, Pack<Ts...>, T> {
|
|
using before = impl::PackSortBefore<Comparator, Pack<Ts...>, T>;
|
|
using after = impl::PackSortAfter<Comparator, Pack<Ts...>, T>;
|
|
|
|
using type = PackMerge<before, Pack<T>, after>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P, typename T>
|
|
using PackSortInsert = typename PackSortInsertImpl<Comparator, P, T>::type;
|
|
|
|
/**
|
|
* @brief sorts a pack
|
|
*
|
|
* @param Comparator a comparator
|
|
* @param P a pack
|
|
*
|
|
* @return a sorted pack
|
|
*/
|
|
template<template<typename, typename> class, typename> struct PackSortImpl;
|
|
|
|
template<template<typename, typename> class Comparator, typename T, typename... Ts>
|
|
struct PackSortImpl<Comparator, Pack<T, Ts...>> {
|
|
using trail = typename PackSortImpl<Comparator, Pack<Ts...>>::type;
|
|
using type = PackSortInsert<Comparator, trail, T>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator>
|
|
struct PackSortImpl<Comparator, Pack<>> {
|
|
using type = Pack<>;
|
|
};
|
|
|
|
template<template<typename, typename> class Comparator, typename P>
|
|
using PackSort = typename PackSortImpl<Comparator, P>::type;
|
|
|
|
/**
|
|
* @brief applies a metafunction to each type in a pack
|
|
*
|
|
* @param P a pack
|
|
* @param F a metafunction
|
|
*
|
|
* @return a transformed pack
|
|
*/
|
|
template<typename, template<typename> class> struct PackForEachImpl;
|
|
|
|
template<typename T, typename... Ts, template<typename> class F>
|
|
struct PackForEachImpl<Pack<T, Ts...>, F> {
|
|
using type = PackPrepend<typename PackForEachImpl<Pack<Ts...>, F>::type, F<T>>;
|
|
};
|
|
|
|
template<template<typename> class F>
|
|
struct PackForEachImpl<Pack<>, F> {
|
|
using type = Pack<>;
|
|
};
|
|
|
|
template<typename P, template<typename> class F>
|
|
using PackForEach = typename PackForEachImpl<P, F>::type;
|
|
|
|
/**
|
|
* @brief checks a property for each element and returns true if all are true
|
|
*
|
|
* @param P a pack
|
|
* @param F a metafunction Pi -> bool
|
|
*
|
|
* @return true if all F<Pi>::value are true
|
|
*/
|
|
template<typename, template<typename> class> struct PackAll;
|
|
|
|
template<typename T, typename... Ts, template<typename> class F>
|
|
struct PackAll<Pack<T, Ts...>, F> {
|
|
static constexpr bool value = F<T>::value && PackAll<Pack<Ts...>, F>::value;
|
|
};
|
|
|
|
template<template<typename> class F>
|
|
struct PackAll<Pack<>, F> {
|
|
static constexpr bool value = true;
|
|
};
|
|
|
|
template<typename P, template<typename> class F>
|
|
constexpr bool packAll = PackAll<P, F>::value;
|
|
|
|
/**
|
|
* @brief checks a property for each element and returns true if any is true
|
|
*
|
|
* @param P a pack
|
|
* @param F a metafunction Pi -> bool
|
|
*
|
|
* @return true if any F<Pi>::value is true
|
|
*/
|
|
template<typename, template<typename> class> struct PackAny;
|
|
|
|
template<typename T, typename... Ts, template<typename> class F>
|
|
struct PackAny<Pack<T, Ts...>, F> {
|
|
static constexpr bool value = F<T>::value || PackAll<Pack<Ts...>, F>::value;
|
|
};
|
|
|
|
template<template<typename> class F>
|
|
struct PackAny<Pack<>, F> {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template<typename P, template<typename> class F>
|
|
constexpr bool packAny = PackAny<P, F>::value;
|
|
|
|
}
|
|
|
|
#endif
|