* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef ATVOSS_UTILITY_H
#define ATVOSS_UTILITY_H
namespace Atvoss::Util {
template <typename T>
struct AlwaysFalse : std::false_type {};
template <typename T>
inline constexpr bool AlwaysFalse_v = AlwaysFalse<T>::value;
template <template <typename...> class T, typename U>
struct IsSpecializationOf : std::false_type {};
template <template <typename...> class T, typename... Us>
struct IsSpecializationOf<T, T<Us...>> : std::true_type {};
template <template <typename...> class T, typename U>
inline constexpr bool IsSpecializationOf_v = IsSpecializationOf<T, U>::value;
template <typename T, typename = void>
struct HasClear : std::false_type {};
template <typename T>
struct HasClear<T, std::void_t<decltype(std::declval<T&>().Clear())>> : std::true_type {};
template <typename T>
inline constexpr bool HasClear_v = HasClear<T>::value;
template <
typename Tuple, typename Func, std::enable_if_t<IsSpecializationOf_v<std::tuple, std::decay_t<Tuple>>, int> = 0>
void ForEach(Tuple&& tuple, Func&& func)
{
std::apply(
[&func](auto&&... args) { (std::forward<Func>(func)(std::forward<decltype(args)>(args)), ...); },
std::forward<Tuple>(tuple));
}
namespace Detail {
template <typename T1, typename T2>
inline constexpr bool WouldCauseAmbiguity_v =
std::is_same_v<T1, T2> || std::is_base_of_v<T1, T2> || std::is_base_of_v<T2, T1>;
template <typename T>
inline constexpr bool CanCompress_v = std::is_empty_v<T> && !std::is_final_v<T>;
template <typename T1, typename T2>
inline constexpr bool CompressFirst_v = CanCompress_v<T1> && (!CanCompress_v<T2> || !WouldCauseAmbiguity_v<T1, T2>);
template <typename T1, typename T2>
inline constexpr bool CompressSecond_v = CanCompress_v<T2> && (!CanCompress_v<T1> || !WouldCauseAmbiguity_v<T1, T2>);
template <typename T, bool Compress>
struct CompressedDataStorage;
template <typename T>
struct CompressedDataStorage<T, false> {
template <typename U, typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>, CompressedDataStorage>>>
explicit constexpr CompressedDataStorage(U&& u) : data_(std::forward<U>(u))
{}
CompressedDataStorage() = default;
T& Data()
{
return data_;
}
const T& Data() const
{
return data_;
}
private:
T data_;
};
template <typename T>
struct CompressedDataStorage<T, true> : private T {
template <typename U, typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>, CompressedDataStorage>>>
explicit constexpr CompressedDataStorage(U&& u) : T(std::forward<U>(u))
{}
CompressedDataStorage() = default;
T& Data()
{
return static_cast<T&>(*this);
}
const T& Data() const
{
return static_cast<const T&>(*this);
}
};
template <typename T1, typename T2, bool CompressFirst, bool CompressSecond>
struct CompressedPairStorage;
template <typename T1, typename T2>
struct CompressedPairStorage<T1, T2, false, false> {
template <typename U1, typename U2>
explicit constexpr CompressedPairStorage(U1&& f, U2&& s) : first_(std::forward<U1>(f)), second_(std::forward<U2>(s))
{}
CompressedPairStorage() = default;
T1& First()
{
return first_;
}
const T1& First() const
{
return first_;
}
T2& Second()
{
return second_;
}
const T2& Second() const
{
return second_;
}
private:
T1 first_;
T2 second_;
};
template <typename T1, typename T2>
struct CompressedPairStorage<T1, T2, true, false> : private T1 {
template <typename U1, typename U2>
explicit constexpr CompressedPairStorage(U1&& f, U2&& s) : T1(std::forward<U1>(f)), second_(std::forward<U2>(s))
{}
CompressedPairStorage() = default;
T1& First()
{
return static_cast<T1&>(*this);
}
const T1& First() const
{
return static_cast<const T1&>(*this);
}
T2& Second()
{
return second_;
}
const T2& Second() const
{
return second_;
}
private:
T2 second_;
};
template <typename T1, typename T2>
struct CompressedPairStorage<T1, T2, false, true> : private T2 {
template <typename U1, typename U2>
explicit constexpr CompressedPairStorage(U1&& f, U2&& s) : T2(std::forward<U2>(s)), first_(std::forward<U1>(f))
{}
CompressedPairStorage() = default;
T1& First()
{
return first_;
}
const T1& First() const
{
return first_;
}
T2& Second()
{
return static_cast<T2&>(*this);
}
const T2& Second() const
{
return static_cast<const T2&>(*this);
}
private:
T1 first_;
};
template <typename T1, typename T2>
struct CompressedPairStorage<T1, T2, true, true> : private T1, private T2 {
template <typename U1, typename U2>
explicit constexpr CompressedPairStorage(U1&& f, U2&& s) : T1(std::forward<U1>(f)), T2(std::forward<U2>(s))
{}
CompressedPairStorage() = default;
T1& First()
{
return static_cast<T1&>(*this);
}
const T1& First() const
{
return static_cast<const T1&>(*this);
}
T2& Second()
{
return static_cast<T2&>(*this);
}
const T2& Second() const
{
return static_cast<const T2&>(*this);
}
};
template <typename T>
struct CompressedPairStorage<T, T, true, true> : private T {
template <typename U1, typename U2>
explicit constexpr CompressedPairStorage(U1&& f, U2&&) : T(std::forward<U1>(f))
{}
CompressedPairStorage() = default;
T& First()
{
return static_cast<T&>(*this);
}
const T& First() const
{
return static_cast<const T&>(*this);
}
T& Second()
{
return static_cast<T&>(*this);
}
const T& Second() const
{
return static_cast<const T&>(*this);
}
};
}
template <typename T>
class CompressedData : private Detail::CompressedDataStorage<T, std::is_empty_v<T> && !std::is_final_v<T>> {
using Storage = Detail::CompressedDataStorage<T, std::is_empty_v<T> && !std::is_final_v<T>>;
public:
using Type = T;
CompressedData() = default;
template <typename U, typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>, CompressedData>>>
explicit constexpr CompressedData(U&& u) : Storage(std::forward<U>(u))
{}
T& Data()
{
return Storage::Data();
}
const T& Data() const
{
return Storage::Data();
}
void swap(CompressedData& other) noexcept
{
using std::swap;
swap(Data(), other.Data());
}
};
template <typename T>
void swap(CompressedData<T>& lhs, CompressedData<T>& rhs) noexcept
{
lhs.swap(rhs);
}
template <typename T>
bool operator==(const CompressedData<T>& lhs, const CompressedData<T>& rhs)
{
return lhs.Data() == rhs.Data();
}
template <typename T>
bool operator!=(const CompressedData<T>& lhs, const CompressedData<T>& rhs)
{
return !(lhs == rhs);
}
template <typename T1, typename T2>
class CompressedPair
: private Detail::CompressedPairStorage<T1, T2, Detail::CompressFirst_v<T1, T2>, Detail::CompressSecond_v<T1, T2>> {
using Storage =
Detail::CompressedPairStorage<T1, T2, Detail::CompressFirst_v<T1, T2>, Detail::CompressSecond_v<T1, T2>>;
public:
using FirstType = T1;
using SecondType = T2;
CompressedPair() = default;
template <typename U1, typename U2>
explicit constexpr CompressedPair(U1&& f, U2&& s) : Storage(std::forward<U1>(f), std::forward<U2>(s))
{}
T1& First()
{
return Storage::First();
}
const T1& First() const
{
return Storage::First();
}
T2& Second()
{
return Storage::Second();
}
const T2& Second() const
{
return Storage::Second();
}
void swap(CompressedPair& other) noexcept
{
using std::swap;
swap(First(), other.First());
swap(Second(), other.Second());
}
};
template <typename T1, typename T2>
CompressedPair(T1&& f, T2&& s) -> CompressedPair<std::decay_t<T1>, std::decay_t<T2>>;
template <typename T1, typename T2>
void swap(CompressedPair<T1, T2>& lhs, CompressedPair<T1, T2>& rhs) noexcept
{
lhs.swap(rhs);
}
template <typename T1, typename T2>
bool operator==(const CompressedPair<T1, T2>& lhs, const CompressedPair<T1, T2>& rhs)
{
return lhs.First() == rhs.First() && lhs.Second() == rhs.Second();
}
template <typename T1, typename T2>
bool operator!=(const CompressedPair<T1, T2>& lhs, const CompressedPair<T1, T2>& rhs)
{
return !(lhs == rhs);
}
template <typename T>
struct TypeWrapper {
using Type = T;
};
template <typename T>
struct RetTypeWrapper {
using RetType = T;
};
template <typename T>
struct TensorTypeWrapper {
using TensorType = T;
};
template <typename... Ts>
struct TypeList {};
template <typename T>
struct IsTypeList : std::false_type {};
template <typename... Ts>
struct IsTypeList<TypeList<Ts...>> : std::true_type {};
template <typename T>
inline constexpr bool IsTypeList_v = IsTypeList<T>::value;
template <typename List>
struct First;
template <>
struct First<TypeList<>> {
using Type = void;
};
template <typename Head, typename... Tail>
struct First<TypeList<Head, Tail...>> {
using Type = Head;
};
template <typename List>
using First_t = typename First<List>::Type;
template <typename List>
struct Size;
template <typename... Ts>
struct Size<TypeList<Ts...>> {
static constexpr std::size_t value = sizeof...(Ts);
};
template <typename List>
inline constexpr std::size_t Size_v = Size<List>::value;
template <typename List, typename T>
struct Append;
template <typename... Ts, typename T>
struct Append<TypeList<Ts...>, T> {
using Type = TypeList<Ts..., T>;
};
template <typename List, typename T>
using Append_t = typename Append<List, T>::Type;
template <typename T, typename List>
struct Prepend;
template <typename T, typename... Ts>
struct Prepend<T, TypeList<Ts...>> {
using Type = TypeList<T, Ts...>;
};
template <typename T, typename List>
using Prepend_t = typename Prepend<T, List>::Type;
template <typename... Lists>
struct Concatenate;
template <>
struct Concatenate<> {
using Type = TypeList<>;
};
template <typename... Ts>
struct Concatenate<TypeList<Ts...>> {
using Type = TypeList<Ts...>;
};
template <typename... Ts, typename... Us>
struct Concatenate<TypeList<Ts...>, TypeList<Us...>> {
using Type = TypeList<Ts..., Us...>;
};
template <typename List1, typename List2, typename List3, typename... Lists>
struct Concatenate<List1, List2, List3, Lists...> {
using Type = typename Concatenate<typename Concatenate<List1, List2>::Type, List3, Lists...>::Type;
};
template <typename... Lists>
using Concatenate_t = typename Concatenate<Lists...>::Type;
template <template <typename> class Pred, typename List>
struct All;
template <template <typename> class Pred, typename Head, typename... Tail>
struct All<Pred, TypeList<Head, Tail...>>
: std::conditional_t<!Pred<Head>::value, std::false_type, All<Pred, TypeList<Tail...>>> {};
template <template <typename> class Pred>
struct All<Pred, TypeList<>> : std::true_type {};
template <template <typename> class Pred, typename List>
inline constexpr bool All_v = All<Pred, List>::value;
template <template <typename> class Pred, typename List>
struct Any;
template <template <typename> class Pred, typename Head, typename... Tail>
struct Any<Pred, TypeList<Head, Tail...>>
: std::conditional_t<Pred<Head>::value, std::true_type, Any<Pred, TypeList<Tail...>>> {};
template <template <typename> class Pred>
struct Any<Pred, TypeList<>> : std::false_type {};
template <template <typename> class Pred, typename List>
inline constexpr bool Any_v = Any<Pred, List>::value;
template <template <typename> class Pred, typename List>
struct Filter;
template <template <typename> class Pred, typename Head, typename... Tail>
struct Filter<Pred, TypeList<Head, Tail...>> {
using Type = typename std::conditional_t<
Pred<Head>::value, Prepend_t<Head, typename Filter<Pred, TypeList<Tail...>>::Type>,
typename Filter<Pred, TypeList<Tail...>>::Type>;
};
template <template <typename> class Pred>
struct Filter<Pred, TypeList<>> {
using Type = TypeList<>;
};
template <template <typename> class Pred, typename List>
using Filter_t = typename Filter<Pred, List>::Type;
template <template <typename> class Pred, typename List, typename = void>
struct Find;
template <template <typename> class Pred>
struct Find<Pred, TypeList<>> {
static constexpr std::size_t value = 0;
};
template <template <typename> class Pred, typename Head, typename... Tail>
struct Find<Pred, TypeList<Head, Tail...>, std::enable_if_t<Pred<Head>::value>> {
static constexpr std::size_t value = 0;
};
template <template <typename> class Pred, typename Head, typename... Tail>
struct Find<Pred, TypeList<Head, Tail...>, std::enable_if_t<!Pred<Head>::value>> {
static constexpr std::size_t value = Find<Pred, TypeList<Tail...>>::value + 1;
};
template <template <typename> class Pred, typename List>
inline constexpr std::size_t Find_v = Find<Pred, List>::value;
namespace Detail {
template <template <typename> class Pred, typename List, std::size_t Current, std::size_t Last>
struct FindLastImpl;
template <template <typename> class Pred, std::size_t Current, std::size_t Last>
struct FindLastImpl<Pred, TypeList<>, Current, Last> {
static constexpr std::size_t value = (Last == static_cast<std::size_t>(-1)) ? Current : Last;
};
template <template <typename> class Pred, typename Head, typename... Tail, std::size_t Current, std::size_t Last>
struct FindLastImpl<Pred, TypeList<Head, Tail...>, Current, Last> {
static constexpr std::size_t value = std::conditional_t<
Pred<Head>::value, FindLastImpl<Pred, TypeList<Tail...>, Current + 1, Current>,
FindLastImpl<Pred, TypeList<Tail...>, Current + 1, Last>>::value;
};
}
template <template <typename> class Pred, typename List>
struct FindLast : Detail::FindLastImpl<Pred, List, 0, static_cast<std::size_t>(-1)> {};
template <template <typename> class Pred, typename List>
inline constexpr std::size_t FindLast_v = FindLast<Pred, List>::value;
template <typename List, std::size_t N>
struct Get;
template <typename Head, typename... Tail, std::size_t N>
struct Get<TypeList<Head, Tail...>, N> {
using Type = typename Get<TypeList<Tail...>, N - 1>::Type;
};
template <typename Head, typename... Tail>
struct Get<TypeList<Head, Tail...>, 0> {
using Type = Head;
};
template <std::size_t N>
struct Get<TypeList<>, N> {
static_assert(N < 0, "[ERROR]: [Atvoss][Expression] Index out of bounds in Get");
};
template <typename List, std::size_t N>
using Get_t = typename Get<List, N>::Type;
template <typename List, std::size_t N>
struct GetFirstN;
template <typename Head, typename... Tail, std::size_t N>
struct GetFirstN<TypeList<Head, Tail...>, N> {
using Type = Concatenate_t<TypeList<Head>, typename GetFirstN<TypeList<Tail...>, N - 1>::Type>;
};
template <typename List>
struct GetFirstN<List, 0> {
using Type = TypeList<>;
};
template <typename List, std::size_t N>
using GetFirstN_t = typename GetFirstN<List, N>::Type;
template <typename List, std::size_t N, typename = void>
struct RemoveFirstN {
using Type = List;
};
template <typename Head, typename... Tail, std::size_t N>
struct RemoveFirstN<TypeList<Head, Tail...>, N, std::enable_if_t<(N > 0)>> {
using Type = typename RemoveFirstN<TypeList<Tail...>, N - 1>::Type;
};
template <typename List, std::size_t N>
using RemoveFirstN_t = typename RemoveFirstN<List, N>::Type;
template <typename List, std::size_t N>
struct GetLastN {
private:
constexpr static std::size_t total = Size_v<List>;
constexpr static std::size_t skip = (N < 0) ? total : ((N < total) ? total - N : 0);
public:
using Type = typename RemoveFirstN<List, skip>::Type;
};
template <typename List, std::size_t N>
using GetLastN_t = typename GetLastN<List, N>::Type;
template <typename List>
struct IsEmpty : std::false_type {};
template <>
struct IsEmpty<TypeList<>> : std::true_type {};
template <typename List>
inline constexpr bool IsEmpty_v = IsEmpty<List>::value;
template <typename List>
struct IsNotEmpty : std::true_type {};
template <>
struct IsNotEmpty<TypeList<>> : std::false_type {};
template <typename List>
inline constexpr bool IsNotEmpty_v = IsNotEmpty<List>::value;
template <typename List>
struct Rest;
template <typename Head, typename... Tail>
struct Rest<TypeList<Head, Tail...>> {
using Type = TypeList<Tail...>;
};
template <typename List>
using Rest_t = typename Rest<List>::Type;
template <typename List, std::size_t N>
struct Drop {
static_assert(IsNotEmpty_v<List>, "Cannot drop from empty list");
using Type = typename Drop<Rest_t<List>, N - 1>::Type;
};
template <typename List>
struct Drop<List, 0> {
using Type = List;
};
template <typename List, std::size_t N>
using Drop_t = typename Drop<List, N>::Type;
template <template <typename...> class Proc, typename List>
struct Apply;
template <template <typename...> class Proc, typename... Args>
struct Apply<Proc, TypeList<Args...>> {
using Type = typename Proc<Args...>::Type;
};
template <template <typename...> class Proc, typename List>
using Apply_t = typename Apply<Proc, List>::Type;
template <template <typename> class Proc, typename List>
struct Map;
template <template <typename> class Proc, typename... Ts>
struct Map<Proc, TypeList<Ts...>> {
using Type = TypeList<typename Proc<Ts>::Type...>;
};
template <template <typename> class Proc, typename List>
using Map_t = typename Map<Proc, List>::Type;
template <typename List>
struct Reverse;
template <>
struct Reverse<TypeList<>> {
using Type = TypeList<>;
};
template <typename Head, typename... Tail>
struct Reverse<TypeList<Head, Tail...>> {
using Type = Append_t<typename Reverse<TypeList<Tail...>>::Type, Head>;
};
template <typename List>
using Reverse_t = typename Reverse<List>::Type;
template <typename List, std::size_t N, typename NewItem>
struct Set;
template <typename Head, typename... Tail, std::size_t N, typename NewItem>
struct Set<TypeList<Head, Tail...>, N, NewItem> {
using Type = Prepend_t<Head, typename Set<TypeList<Tail...>, N - 1, NewItem>::Type>;
};
template <typename Head, typename... Tail, typename NewItem>
struct Set<TypeList<Head, Tail...>, 0, NewItem> {
using Type = TypeList<NewItem, Tail...>;
};
template <std::size_t N, typename NewItem>
struct Set<TypeList<>, N, NewItem> {
static_assert(N < 0, "Index out of bounds in Set");
};
template <typename List, std::size_t N, typename NewItem>
using Set_t = typename Set<List, N, NewItem>::Type;
template <typename T, typename = void>
struct IsTensor : std::false_type {};
template <typename T>
struct IsTensor<T, std::void_t<typename T::IsTensor>> : std::true_type {};
template <typename T>
inline constexpr bool IsTensor_v = IsTensor<T>::value;
template <typename List, std::size_t pos, typename NewItem, typename = void>
struct UpdateOrPrepend {
using Type = Prepend_t<NewItem, List>;
};
template <typename List, std::size_t pos, typename NewItem>
struct UpdateOrPrepend<List, pos, NewItem, std::enable_if_t<(pos < Size_v<List>)>> {
using Type = Set_t<List, pos, NewItem>;
};
template <typename List, std::size_t pos, typename NewItem>
using UpdateOrPrepend_t = typename UpdateOrPrepend<List, pos, NewItem>::Type;
template <typename List>
struct Unique;
template <>
struct Unique<TypeList<>> {
using Type = TypeList<>;
};
template <typename... Ts>
struct Unique<TypeList<Ts...>> {
private:
template <typename Accumulator, typename... Remaining>
struct TypeSet;
template <typename... Accumulated>
struct TypeSet<TypeList<Accumulated...>> {
using Type = TypeList<Accumulated...>;
};
template <typename... Accumulated, typename Head, typename... Tail>
struct TypeSet<TypeList<Accumulated...>, Head, Tail...> {
static constexpr bool contains = (std::is_same_v<Head, Accumulated> || ...);
using Type = typename std::conditional_t<
contains,
TypeSet<TypeList<Accumulated...>, Tail...>,
TypeSet<TypeList<Accumulated..., Head>, Tail...>>::Type;
};
public:
using Type = typename TypeSet<TypeList<>, Ts...>::Type;
};
template <typename List>
using Unique_t = typename Unique<List>::Type;
template <template <typename> class Pred, typename List>
struct FindUnique {
using ResultList = Filter_t<Pred, List>;
static_assert(Size_v<ResultList> != 0, "[ERROR]: [Atvoss][Expression] Cannot find the specified element");
static_assert(Size_v<ResultList> == 1, "[ERROR]: [Atvoss][Expression] A unique result is expected");
using Type = First_t<ResultList>;
};
template <template <typename> class Pred, typename List>
using FindUnique_t = typename FindUnique<Pred, List>::Type;
template <typename List, typename T>
struct Contains;
template <typename T>
struct Contains<TypeList<>, T> : std::false_type {};
template <typename... Tail, typename T>
struct Contains<TypeList<T, Tail...>, T> : std::true_type {};
template <typename Head, typename... Tail, typename T>
struct Contains<TypeList<Head, Tail...>, T> {
static constexpr bool value = Contains<TypeList<Tail...>, T>::value;
};
template <typename List, typename T>
inline constexpr bool Contains_v = Contains<List, T>::value;
template <typename List1, typename List2>
struct Intersection {
template <typename T>
struct IsInList2 : Contains<List2, T> {};
using Type = Filter_t<IsInList2, List1>;
};
template <typename List1, typename List2>
using Intersection_t = typename Intersection<List1, List2>::Type;
template <typename List1, typename List2>
struct Difference {
template <typename T>
struct IsNotInList2 {
static constexpr bool value = !Contains_v<List2, T>;
};
using Type = Filter_t<IsNotInList2, List1>;
};
template <typename List1, typename List2>
using Difference_t = typename Difference<List1, List2>::Type;
template <typename Func, typename Data>
constexpr auto ForEach(TypeList<>, Func&& , Data data)
{
return data;
}
template <typename Head, typename... Tail, typename Func, typename Data>
constexpr auto ForEach(TypeList<Head, Tail...>, Func&& func, Data data)
{
return ForEach(TypeList<Tail...>{}, std::forward<Func>(func), std::forward<Func>(func)(TypeWrapper<Head>{}, data));
}
template <typename... Items>
class IndexMap {
private:
using ItemList = TypeList<Items...>;
template <size_t Index, typename Value>
struct IndexValuePair {
static constexpr size_t index = Index;
using ValueType = Value;
};
template <size_t I, typename List>
struct FindByIndex;
template <size_t I>
struct FindByIndex<I, TypeList<>> {
using Type = void;
static constexpr bool found = false;
};
template <size_t I, typename Head, typename... Tail>
struct FindByIndex<I, TypeList<Head, Tail...>> {
private:
using TailResult = FindByIndex<I, TypeList<Tail...>>;
public:
static constexpr bool found = (Head::index == I) || TailResult::found;
using Type = std::conditional_t<(Head::index == I), typename Head::ValueType, typename TailResult::Type>;
};
template <size_t I, typename NewType, typename List>
struct SetByIndex;
template <size_t I, typename NewType>
struct SetByIndex<I, NewType, TypeList<>> {
using Type = TypeList<IndexValuePair<I, NewType>>;
};
template <size_t I, typename NewType, typename Head, typename... Tail>
struct SetByIndex<I, NewType, TypeList<Head, Tail...>> {
private:
using TailResult = typename SetByIndex<I, NewType, TypeList<Tail...>>::Type;
public:
using Type = std::conditional_t<
(Head::index == I), Prepend_t<IndexValuePair<I, NewType>, TailResult>, Prepend_t<Head, TailResult>>;
};
template <typename List>
struct ListToPack;
template <typename... Ts>
struct ListToPack<TypeList<Ts...>> {
template <template <typename...> class T>
using Apply = T<Ts...>;
};
public:
template <size_t I>
using At = typename FindByIndex<I, ItemList>::Type;
template <size_t I>
static constexpr bool Contains = FindByIndex<I, ItemList>::found;
template <size_t I, typename NewType>
using Set = typename ListToPack<typename SetByIndex<I, NewType, ItemList>::Type>::template Apply<IndexMap>;
static constexpr size_t size = sizeof...(Items);
};
template <template <typename, typename> class Less, typename List>
struct Sort;
template <template <typename, typename> class Less>
struct Sort<Less, TypeList<>> {
using Type = TypeList<>;
};
template <template <typename, typename> class Less, typename Head>
struct Sort<Less, TypeList<Head>> {
using Type = TypeList<Head>;
};
template <template <typename, typename> class Less, typename Head, typename... Tail>
struct Sort<Less, TypeList<Head, Tail...>> {
private:
using SortedTail = typename Sort<Less, TypeList<Tail...>>::Type;
template <typename Sorted, typename Item>
struct Insert;
template <typename Item>
struct Insert<TypeList<>, Item> {
using Type = TypeList<Item>;
};
template <typename SHead, typename... STail, typename Item>
struct Insert<TypeList<SHead, STail...>, Item> {
static constexpr bool insertHere = Less<Item, SHead>::value;
using Type = std::conditional_t<
insertHere, TypeList<Item, SHead, STail...>,
Concatenate_t<TypeList<SHead>, typename Insert<TypeList<STail...>, Item>::Type>>;
};
public:
using Type = typename Insert<SortedTail, Head>::Type;
};
template <template <typename, typename> class Less, typename List>
using Sort_t = typename Sort<Less, List>::Type;
}
#endif