#ifndef MEDIAPIPE_FRAMEWORK_API2_TYPE_LIST_H_
#define MEDIAPIPE_FRAMEWORK_API2_TYPE_LIST_H_
#include <string>
#include <type_traits>
#include <utility>
namespace mediapipe {
namespace api2 {
namespace types {
// A list of types. This allows us to store a template parameter pack.
template <typename... Args>
struct List {};
// Concatenate two lists.
template <typename... As, typename... Bs>
auto concat(List<As...>, List<Bs...>) -> List<As..., Bs...> {
return {};
}
// Filter a list using a predicate.
template <template <typename> class Pred, typename... Args>
auto filter(List<Args...>) -> List<Args...> {
return {};
}
template <template <typename> class Pred, typename Head, typename... Tail>
auto filter(List<Head, Tail...>)
-> decltype(concat(typename std::conditional<Pred<Head>::value, List<Head>,
List<>>::type{},
filter<Pred>(List<Tail...>{}))) {
return {};
}
template <typename Pred>
auto filter(Pred, List<>) -> List<> {
return {};
}
template <typename Pred, typename Head, typename... Tail>
auto filter(Pred pred, List<Head, Tail...>)
-> decltype(concat(
typename std::conditional<pred(Head{}), List<Head>, List<>>::type{},
filter(pred, List<Tail...>{}))) {
return {};
}
// Invoke a template using a list's types as parameters.
template <template <typename...> class T, typename... Args>
auto apply(List<Args...>) -> T<Args...> {
return {};
}
// Wraps a single type. The wrapper can always be instantiated as a value,
// even if T cannot.
template <typename T>
struct Wrap {
using type = T;
};
// Find first match for a predicate.
template <template <typename> class Pred, typename... Args>
auto find(List<Args...>) -> Wrap<void> {
return {};
}
template <template <typename> class Pred, typename Head, typename... Tail>
auto find(List<Head, Tail...>) ->
typename std::conditional<Pred<Head>::value, Wrap<Head>,
decltype(find<Pred>(List<Tail...>{}))>::type {
return {};
}
template <class Pred, typename... Args>
auto find(Pred, List<Args...>) -> Wrap<void> {
return {};
}
template <class Pred, typename Head, typename... Tail>
auto find(Pred pred, List<Head, Tail...>) ->
typename std::conditional<pred(Head{}), Wrap<Head>,
decltype(find(pred, List<Tail...>{}))>::type {
return {};
}
// Apply a function to each item in a list.
template <template <typename> class Fun, typename... Items>
auto map(List<Items...>) -> List<typename Fun<Items>::type...> {
return {};
}
// Get the list's head.
template <typename... Args>
constexpr auto head(List<Args...>) -> Wrap<void> {
return {};
}
template <typename H, typename... T>
constexpr auto head(List<H, T...>) -> Wrap<H> {
return {};
}
// Get the list's length.
template <typename... Args>
constexpr std::size_t length(List<Args...>) {
return 0;
}
template <typename H, typename... T>
constexpr std::size_t length(List<H, T...>) {
return length(List<T...>{}) + 1;
}
// Add indices.
template <std::size_t I, typename T>
struct IndexedType {
static constexpr std::size_t kIndex = I;
using type = T;
};
template <typename... Args, std::size_t... Is>
auto enumerate_impl(List<Args...>, std::index_sequence<Is...>)
-> List<IndexedType<Is, Args>...> {
return {};
}
template <typename... Args>
auto enumerate(List<Args...> a)
-> decltype(enumerate_impl(a, std::index_sequence_for<Args...>{})) {
return {};
}
} // namespace types
} // namespace api2
} // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_API2_TYPE_LIST_H_