211 lines
9.7 KiB
C++
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
|