Skip to content

Commit

Permalink
Remove TraitHolder Specializations
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew-Whitlock committed Dec 10, 2024
1 parent 43c12a0 commit ba76568
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 94 deletions.
5 changes: 4 additions & 1 deletion src/checkpoint/serializers/serializer_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace checkpoint {
template<typename SerT, typename UserTraits = UserTraitHolder<>>
struct SerializerRef
{
using TraitHolder = typename UserTraits::BaseTraits;
using TraitHolder = UserTraits;

//Passing initialization to the serializer implementation
explicit SerializerRef(SerT* m_impl, const UserTraits& = {}) :
Expand Down Expand Up @@ -153,5 +153,8 @@ constexpr bool has_user_traits_v = has_user_traits<S, Traits...>::value;
template<typename S, typename... Traits>
constexpr bool has_any_user_traits_v = has_any_user_traits<S, Traits...>::value;

template<typename S>
using CopyUserTraits = serializerUserTraits::CopyTraits<typename S::TraitHolder>;

}
#endif /*INCLUDED_SRC_CHECKPOINT_SERIALIZERS_SERIALIZER_REF_H*/
209 changes: 116 additions & 93 deletions src/checkpoint/traits/user_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,131 +46,154 @@

namespace checkpoint {
namespace serializerUserTraits {

template<typename... Traits>
struct TraitHolder;

template<typename U, typename V>
struct is_base_or_derived
: std::disjunction<std::is_base_of<U,V>, std::is_base_of<V,U>> {};

template<typename U, typename V>
struct is_same_template
: std::false_type {};
template<template <typename...> typename Templ, typename... U, typename... V>
struct is_same_template<Templ<U...>, Templ<V...>>
: std::true_type {};

//Check if two traits are the same type when decayed
template<typename U, typename V>
struct traits_match
: std::disjunction<
#ifdef CHECKPOINT_INHERITED_USER_TRAITS
is_base_or_derived<std::decay_t<U>,std::decay_t<V>>,
#endif
#ifdef CHECKPOINT_TEMPLATED_USER_TRAITS
is_same_template<std::decay_t<U>,std::decay_t<V>>,
#endif
std::is_same<std::decay_t<U>,std::decay_t<V>>
> {};
struct traits_match : public std::is_same<std::decay_t<U>,std::decay_t<V>>{};
template<typename U, typename V>
inline constexpr bool traits_match_v = traits_match<U,V>::value;

struct NoTrait;

//Merge the traits of two TraitHolders
template<typename HolderA, typename HolderB>
struct MergeTraitsImpl;
template<typename HolderA, typename HolderB>
using MergeTraits = typename MergeTraitsImpl<HolderA, HolderB>::type;

template<typename... TraitsA, typename... TraitsB>
struct MergeTraitsImpl<TraitHolder<TraitsA...>, TraitHolder<TraitsB...>>{
using type = TraitHolder<TraitsA..., TraitsB...>;
};


//The type of the first trait in a TraitHolder
template<typename Holder>
struct FirstTraitImpl;
template<typename Holder>
using FirstTrait = typename FirstTraitImpl<Holder>::type;

template<typename Trait, typename... Traits>
struct FirstTraitImpl<TraitHolder<Trait, Traits...>>{
using type = Trait;
};


//Remove the first trait from a TraitHolder.
template<typename Holder>
struct PopTraitImpl;
template<typename Holder>
using PopTrait = typename PopTraitImpl<Holder>::type;

template<typename Trait, typename... Traits>
struct PopTraitImpl<TraitHolder<Trait, Traits...>>{
using type = TraitHolder<Traits...>;
};


template<typename Traits, typename T, typename... U>
struct WithoutHelper {
using type = typename WithoutHelper<typename Traits::template WithoutTrait<T>, U...>::type;
//Remove types T from a TraitHolder. Only (up to) one trait is removed per T
template<typename Holder, typename... T>
struct WithoutTraitsImpl;
template<typename Holder, typename... T>
using WithoutTraits = typename WithoutTraitsImpl<Holder, T...>::type;

template<typename Holder>
struct WithoutTraitsImpl<Holder> {
using type = Holder;
};
template<typename T, typename... U>
struct WithoutTraitsImpl<TraitHolder<>, T, U...> {
using type = TraitHolder<>;
};
template<typename Traits, typename T>
struct WithoutHelper<Traits, T> {
using type = typename Traits::template WithoutTrait<T>;
template<typename Holder, typename T, typename... U>
struct WithoutTraitsImpl<Holder, T, U...> {
using CheckTrait = FirstTrait<Holder>;
using Remaining = PopTrait<Holder>;
using WithoutT = std::conditional_t<
traits_match_v<T, CheckTrait>,
Remaining,
MergeTraits<TraitHolder<CheckTrait>, WithoutTraits<Remaining, T>>
>;
using type = WithoutTraits<WithoutT, U...>;
};


template<typename Trait = NoTrait, typename... Traits>
//Holds traits that should be unwrapped when passed into a TraitHolder
template<typename Holder>
struct NestedTraitHolder {
using Traits = Holder;
};
template<typename Holder>
using CopyTraits = NestedTraitHolder<Holder>;


//TraitHolder with any NestedTraitHolders unwrapped to their held traits
template<typename Holder>
struct UnwrapTraitsImpl;
template<typename Holder>
using UnwrapTraits = typename UnwrapTraitsImpl<Holder>::type;

template<>
struct UnwrapTraitsImpl<TraitHolder<>>{
using type = TraitHolder<>;
};
template<typename Trait, typename... Traits>
struct UnwrapTraitsImpl<TraitHolder<Trait, Traits...>>{
using type = MergeTraits<
TraitHolder<Trait>,
UnwrapTraits<TraitHolder<Traits...>>
>;
};
template<typename WrappedTraits, typename... Traits>
struct UnwrapTraitsImpl<
TraitHolder<NestedTraitHolder<WrappedTraits>, Traits...>
> {
using type = MergeTraits<WrappedTraits,
UnwrapTraits<TraitHolder<Traits...>>
>;
};


template<typename... Traits>
struct TraitHolder {
protected:
template<typename, typename...>
template<typename...>
friend struct TraitHolder;

template<typename T>
using has_trait = std::disjunction<traits_match<T, Trait>, traits_match<T, Traits>...>;
using has_trait = std::disjunction<traits_match<T, Traits>...>;

public:

//Remove one at a time, so we can allow multiple trait copies to be removed independently.
template<typename T>
using WithoutTrait = std::conditional_t<
traits_match_v<T, Trait>,
TraitHolder<Traits...>,
typename TraitHolder<Traits...>::template WithoutTrait<T>::template WithPre<Trait>
>;
template<typename... T>
using With = TraitHolder<Trait, Traits..., T...>;
using With = TraitHolder<Traits..., T...>;
//To respect ordering. Could be handy in the future -- disambiguating multiple hooks?
template<typename... T>
using WithPre = TraitHolder<T..., Trait, Traits...>;

//Flush out any nested traits (TraitHolder<..., TraitHolder<...>, ...>)
//Remove any NoTraits, unless that's the only trait.
using BaseTraits = typename TraitHolder<Traits...>::BaseTraits::template WithPre<Trait>;
using WithPre = TraitHolder<T..., Traits...>;

//Has all types T
template<typename... T>
using has = std::conjunction<has_trait<T>...>;
//Has any types within T
template<typename... T>
using has_any = std::disjunction<has_trait<T>...>;

template<typename T, typename... U>
using Without = typename WithoutHelper<BaseTraits, T, U...>::type;
};

//Empty specialization w/ shortcuts.
template<>
struct TraitHolder<NoTrait> {
using BaseTraits = TraitHolder<NoTrait>;

template<typename... T>
using has = std::false_type;
template<typename... T>
using has_any = std::false_type;

template<typename... T>
static constexpr bool has_v = false;
template<typename... T>
static constexpr bool has_any_v = false;

template<typename... T>
using With = TraitHolder<T...>;

//Type with each trait T removed once, if present.
//E.G. TraitHolder<TraitOne, TraitOne, TraitTwo, TraitThree>
// ::Without<TraitOne, TraitTwo>
// == TraitHolder<TraitOne, TraitThree>;
template<typename... T>
using WithPre = TraitHolder<T...>;

template<typename... T>
using Without = TraitHolder<NoTrait>;

template<typename T>
using WithoutTrait = TraitHolder<NoTrait>;

protected:
template<typename T>
using has_trait = std::false_type;

template<typename, typename...>
friend struct TraitHolder;
template<typename, typename, typename...>
friend struct WithoutHelper;
using Without = WithoutTraits<TraitHolder<Traits...>, T...>;
};

//Specialization to remove nested traits.
template<typename... Traits, typename... NestedTraits>
struct TraitHolder<TraitHolder<NestedTraits...>, Traits...>
: public TraitHolder<NestedTraits..., Traits...> {};
//Ignore nested NoTrait
template<typename... Traits>
struct TraitHolder<TraitHolder<NoTrait>, Traits...>
: public TraitHolder<Traits...> {};

} //namespace serializerUserTraits


template<typename... Traits>
using UserTraitHolder = typename serializerUserTraits::template TraitHolder<Traits...>::BaseTraits;
using UserTraitHolder = serializerUserTraits::UnwrapTraits<
serializerUserTraits::TraitHolder<Traits...>
>;
} //namespace checkpoint

#endif /*INCLUDED_SRC_CHECKPOINT_TRAITS_USER_TRAITS_H*/

0 comments on commit ba76568

Please sign in to comment.