tmp-policy/policy_fundamentals.h

139 lines
6.1 KiB
C
Raw Normal View History

2022-08-04 13:44:15 +08:00
// tmp_policy
// Created by lucas on 22-7-26.
// Re-implementation of a typical policy architecture in C++ Template Meta-Programming.
#ifndef TMP_POLICY_POLICY_FUNDAMENTALS_H
#define TMP_POLICY_POLICY_FUNDAMENTALS_H
#include <type_traits>
// The container of policy objects.
template <typename ...>
struct PolicyContainer;
// This part of logic should not be accessed by the outside code.
namespace NSPolicySelect {
// Auxiliary Meta-Function: template <typename> constexpr bool IsArrayEmpty
// To indicate whether a PolicyContainer is empty or not.
// True branch: If the template parameter isn't PolicyContainer,
// or is a PolicyContainer with no element,
// the meta-function returns true.
template <typename T>
constexpr bool IsArrayEmpty = true;
// False branch: If the template parameter is a PolicyContainer
// with more than one element,
// the meta-function returns false.
template <typename TCurrent, typename ... TTypes>
constexpr bool IsArrayEmpty<PolicyContainer<TCurrent, TTypes...>> = false;
// Meta-Function: template <typename, typename> struct MajorFilter_;
// Remove the policy object whose MajorClass doesn't match with the first policy object.
// Also, the primitive template handles with the situation in which the two PolicyContainer are both empty.
template <typename TPolicyContainerModified, typename TPolicyContainerOriginal>
struct MajorFilter_
{
using type = PolicyContainer<>;
};
// Template specialization of MajorFilter_.
template <typename TFirstPolicy, typename ... TModifiedPolicies,
typename TCurPolicy, typename ... TOtherPolicies>
struct MajorFilter_<PolicyContainer<TFirstPolicy, TModifiedPolicies...>,
PolicyContainer<TCurPolicy, TOtherPolicies...>>
{
// The main logic of the loop.
// Use std::conditional_t to perform branch structure.
using type = std::conditional_t<
// Condition: Does TCurPolicy contain the same major class as the policy group?
std::is_same<typename TFirstPolicy::MajorClass, typename TCurPolicy::MajorClass>::value,
// True branch: If it does, add TCurPolicy to the policy group.
typename MajorFilter_<PolicyContainer<TFirstPolicy, TModifiedPolicies..., TCurPolicy>,
PolicyContainer<TOtherPolicies...>>::type,
// False branch: If it doesn't, skip TCurPolicy.
typename MajorFilter_<PolicyContainer<TFirstPolicy, TModifiedPolicies...>,
PolicyContainer<TOtherPolicies...>>::type
>;
// ... and recursively proceed with next element.
};
// Template specialization of MajorFilter_.
template <typename TEmptyContainer, typename TFirstPolicy, typename ... TOtherPolicies>
struct MajorFilter_<TEmptyContainer,
PolicyContainer<TFirstPolicy, TOtherPolicies...>>
{
// The beginning of the recursion.
// Simply put the first policy into the modified policy container.
using type = typename MajorFilter_<PolicyContainer<TFirstPolicy>,
PolicyContainer<TOtherPolicies...>>::type;
};
// Template specialization of MajorFilter_.
template <typename ... TPolicies, typename TEmptyContainer>
struct MajorFilter_<PolicyContainer<TPolicies...>, TEmptyContainer>
{
// Boundary of recursion: The proceeding policy container has no elements inside.
// Therefore, simply return the proceeded policy container.
using type = PolicyContainer<TPolicies...>;
};
// Auxiliary type definition: simplify the usage of MajorFilter_.
template <typename TPolicyCont>
using MajorFilter = typename MajorFilter_<PolicyContainer<>, TPolicyCont>::type;
// Meta-Function: template <typename, typename> struct MinorCheckInner_.
// Check whether the rest policy objects' MinorClass match with the current policy object or not.
// It performs as the inner loop of the minor check algorithm.
// Also, the primitive template handles with the boundary of recursion.
// It simply returns std::true_type when there is no policy object in the PolicyContainer.
template <typename TPolicy, typename TPolicyCont>
struct MinorCheckInner_
{
using type = std::true_type;
};
// Template specialization of MinorCheckInner_.
template <typename TPolicy, typename TCurPolicy, typename ... TRestPolicies>
struct MinorCheckInner_<TPolicy, PolicyContainer<TCurPolicy, TRestPolicies...>>
{
using type = std::conditional_t<
// The meta-function checks if two policy objects have the same minor class...
std::is_same<typename TPolicy::MinorClass, typename TCurPolicy::MinorClass>::value,
// ... if yes, simply returns false to end the recursion.
std::false_type,
// ... if no, proceeds check with TPolicy
// and the next policy object in the policy container.
typename MinorCheckInner_<TPolicy, PolicyContainer<TRestPolicies...>>::type
>;
};
// Meta-Function: template <typename> struct MinorCheckOuter_.
// For each policy object in the policy container,
// use MinorCheckInner_ to identify if there are another policy object
// having identical minor class.
template <typename TPolicyContainer>
struct MinorCheckOuter_
{
using type = std::true_type;
};
template <typename TCurPolicy, typename ... TRestPolicies>
struct MinorCheckOuter_<PolicyContainer<TCurPolicy, TRestPolicies...>>
{
private:
using InnerResult_ = typename MinorCheckInner_<TCurPolicy, PolicyContainer<TRestPolicies...>>::type;
public:
using type = std::conditional_t<
InnerResult_::value,
typename MinorCheckOuter_<PolicyContainer<TRestPolicies...>>::type,
std::false_type
>;
};
template <typename TPolicyContainer>
constexpr bool MinorCheck = MinorCheckOuter_<TPolicyContainer>::type::value;
}
#endif //TMP_POLICY_POLICY_FUNDAMENTALS_H