tmp-policy/policy_fundamentals.h

211 lines
9.7 KiB
C++

// 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 TFirstPolicy, typename ... TOtherPolicies>
struct MajorFilter_<PolicyContainer<>,
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.
// Also, the primitive template handles with the situation in which
// the policy container has no element.
template <typename TPolicyContainer>
struct MinorCheckOuter_
{
using type = std::true_type;
};
// Template specialization of MinorCheckOuter_.
template <typename TCurPolicy, typename ... TRestPolicies>
struct MinorCheckOuter_<PolicyContainer<TCurPolicy, TRestPolicies...>>
{
// The main logic of recursion.
using type = std::conditional_t<
// Does TCurPolicy and the rest policy objects have the same minor class?
MinorCheckInner_<TCurPolicy, PolicyContainer<TRestPolicies...>>::type::value,
// ... if no, proceed with next policy object in the policy container.
typename MinorCheckOuter_<PolicyContainer<TRestPolicies...>>::type,
// ... if yes, simply returns false and ends the recursion.
std::false_type
>;
};
// Auxiliary template value meta-function definition: MinorCheck.
// Check if the TPolicyContainer has more than one element
// with the same minor class.
// If yes, returns false.
// If no, returns true.
template <typename TPolicyContainer>
constexpr bool MinorCheck = MinorCheckOuter_<TPolicyContainer>::type::value;
// Template Declaration: template <typename> struct PolicySelectionResult.
// The template class which describes the policy selection result.
template <typename TPolicyContainer>
struct PolicySelectionResult;
// Template specialization of PolicySelectionResult.
// If the PolicyContainer only has one policy object in it,
// the PolicySelectionResult simply inherits from the policy object.
template <typename TPolicy>
struct PolicySelectionResult<PolicyContainer<TPolicy>> :
public TPolicy {};
// Template specialization of PolicySelectionResult.
// If the PolicyContainer has more than one policy object in it,
// the PolicySelectionResult inherits from the first policy object
// and the PolicySelectionResult of other policies.
// The result contains a definition that is dominant and unambiguous --
// each declaration comes from either Policy Group's initial definition
// or the policy object's overwritten definition.
template <typename TCurPolicy, typename ... TRestPolicies>
struct PolicySelectionResult<PolicyContainer<TCurPolicy, TRestPolicies...>> :
public TCurPolicy,
public PolicySelectionResult<PolicyContainer<TRestPolicies...>> {};
// Template Declaration: template <typename, typename> struct Selector_.
// The interface for users to get the policy selection result.
// TPolicyContainer - the policy container which contains the policy objects.
// TPolicyGroup - the original policy group.
template <typename TPolicyContainer, typename TPolicyGroup>
struct Selector_;
// Template specialization of Selector_.
// Restricts the TPolicyContainer can only be type PolicyContainer.
template <typename ... TPolicies, typename TPolicyGroup>
struct Selector_<PolicyContainer<TPolicies...>, TPolicyGroup>
{
// Use access specifier to prevent the users to use the internal types.
private:
// Use MajorFilter (MajorFilter_) to filter out the policy objects
// with unmatched MajorClass.
using FilteredPolicy = MajorFilter<PolicyContainer<TPolicies...>>;
// Check if the policy objects has conflict minor classes.
static_assert(MinorCheck<FilteredPolicy>, "Minor Class Set Conflict!");
public:
// Generate the policy selection result.
using type = std::conditional_t<
// Is the PolicyContainer empty?
IsArrayEmpty<FilteredPolicy>,
// ... if so, returns the policy group to represent the default definitions.
TPolicyGroup,
// ... if not, generate policy selection result to represent the user-selected definitions.
PolicySelectionResult<FilteredPolicy>
>;
};
// Auxiliary type definition - PolicySelect.
// To simplify the usage of Selector_.
template <typename TPolicyContainer, typename TPolicyGroup>
using PolicySelect = typename Selector_<TPolicyContainer, TPolicyGroup>::type;
}
// Expose the NSPolicySelect::PolicySelect to global scope.
using NSPolicySelect::PolicySelect;
#endif //TMP_POLICY_POLICY_FUNDAMENTALS_H