pfor/src/pfor/mp/pack.h

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