diff options
-rw-r--r-- | src/include/usr/targeting/attributeenums.H | 1 | ||||
-rw-r--r-- | src/include/usr/targeting/iterators/rangefilter.H | 323 | ||||
-rw-r--r-- | src/include/usr/targeting/iterators/targetiterator.H | 257 | ||||
-rw-r--r-- | src/include/usr/targeting/predicates/predicatebase.H | 111 | ||||
-rw-r--r-- | src/include/usr/targeting/predicates/predicatectm.H | 118 | ||||
-rw-r--r-- | src/include/usr/targeting/predicates/predicatepostfixexpr.H | 204 | ||||
-rw-r--r-- | src/include/usr/targeting/targetservice.H | 95 | ||||
-rw-r--r-- | src/usr/targeting/iterators/rangefilter.C | 89 | ||||
-rw-r--r-- | src/usr/targeting/iterators/targetiterator.C | 88 | ||||
-rw-r--r-- | src/usr/targeting/makefile | 21 | ||||
-rw-r--r-- | src/usr/targeting/predicates/predicatebase.C | 54 | ||||
-rw-r--r-- | src/usr/targeting/predicates/predicatectm.C | 63 | ||||
-rw-r--r-- | src/usr/targeting/predicates/predicatepostfixexpr.C | 198 | ||||
-rw-r--r-- | src/usr/targeting/targetservice.C | 108 | ||||
-rw-r--r-- | src/usr/targeting/test/targetingtest.H | 533 | ||||
-rw-r--r-- | src/usr/targeting/trace.H | 2 |
16 files changed, 2224 insertions, 41 deletions
diff --git a/src/include/usr/targeting/attributeenums.H b/src/include/usr/targeting/attributeenums.H index c4cd5c28a..6d7eed93d 100644 --- a/src/include/usr/targeting/attributeenums.H +++ b/src/include/usr/targeting/attributeenums.H @@ -34,6 +34,7 @@ namespace TARGETING */ enum ATTRIBUTE_ID { + ATTR_NA = 0x00, ATTR_CLASS = 0x01, ATTR_TYPE = 0x02, ATTR_MODEL = 0x03, diff --git a/src/include/usr/targeting/iterators/rangefilter.H b/src/include/usr/targeting/iterators/rangefilter.H new file mode 100644 index 000000000..b582cb0b6 --- /dev/null +++ b/src/include/usr/targeting/iterators/rangefilter.H @@ -0,0 +1,323 @@ + +#ifndef TARG_RANGEFILTER_H +#define TARG_RANGEFILTER_H + +/** + * @file rangefilter.H + * + * @brief Interface describing an object which takes an iterator range and + * allows caller to iterate through the elements which match a supplied + * predicate (filter) + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/target.H> +#include <targeting/predicates/predicatebase.H> +#include <targeting/iterators/targetiterator.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FUNC + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" + +#define TARG_CLASS "RangeFilter<IteratorType>::" + +/** + * @brief Templated class which which takes an iterator range of arbitrary type + * and allows caller to iterate through the elements which match a supplied + * predicate (filter) + */ +template<typename IteratorType> +class RangeFilter +{ + public: + + /** + * @var Forward the type of iterated elements to help build the + * class generically + */ + typedef typename IteratorType::value_type value_type; + + /** + * @var fake_bool is a pointer to a member function of RangeFilter + * which takes no arguments and returns void. + * Used to implement ability to check if range iterator is valid + */ + typedef void (RangeFilter::*fake_bool)() const; + + /** + * @brief Create a range object and locate first item in the range that + * matches the predicate (or the first if no predicate) + * + * @param[in] i_begin Iterator pointing to first item in range + * @param[in] i_end Iterator pointing to last item in range + * @param[in] i_pPredicate Predicate evaluated against each pointed to + * item + * + * @note Begin iterator must point to element prior to end iterator, + * otherwise result is undefined + */ + RangeFilter( + const IteratorType& i_begin, + const IteratorType& i_end, + const PredicateBase* i_pPredicate = NULL); + + /** + * @brief Destroy a range object (nothing to do) + */ + ~RangeFilter() + { + } + + /** + * @brief Dummy function used to implement ability to check if range + * iterator is valid + */ + operator fake_bool() const + { + return (iv_current != iv_end) + ? &RangeFilter::notComparable : NULL; + } + + /** + * @brief Pre-increment operator which advances the range's iterator + * to point to the next valid element + * + * @return Reference to this range filter + */ + RangeFilter& operator++(); + + /** + * @brief Dereference the range filter, returning the element pointed + * + * @return The element pointed to by the range filter + */ + value_type operator*() const + { + return *iv_current; + } + + /** + * @brief Dereference the range filter, returning the element pointed + * for use by the dereference and call member operator + * + * @return The element pointed to by the range filter + */ + value_type operator->() const + { + return *iv_current; + } + + /** + * @brief Reset the range's internal iterator to point to the first + * item in the range that matches the predicate (or the first if no + * predicate) + */ + void reset(); + + /** + * @brief Set the range's predicate filter + * + * @param[in] i_pPredicate Predicate to evaluate against elements + * pointed to by the range + */ + void setPredicate( + const PredicateBase* i_pPredicate); + + /** + * @brief Assignment operator; assign one range filter to another + * + * @param[in] i_rhs Range filter to assign + */ + RangeFilter& operator=( + const RangeFilter& i_rhs); + + /** + * @brief Copy constructor; create range filter using another range + * filter as a prototype for it + * + * @param[in] i_rhs Range filter to assign on create + */ + RangeFilter( + const RangeFilter& i_rhs); + + private: + + /** + * @brief Update internal cursor to point to the next element of the + * underlying range + * + * @note If the internal cursor is at the end of the range, then do + * nothing + */ + void advance(); + + /** + * @brief Update internal cursor to point to the next element of the + * underlying range only if not past the end of the range and the + * predicate doesn't match the current item + * + * @note If the internal cursor is at the end of the range, then do + * nothing + */ + void advanceIfNoMatch(); + + /** + * @brief Dummy function used to implement ability to check if range + * iterator is valid + */ + void notComparable() const + { + } + + IteratorType iv_current; ///< Iterator pointing to the + ///< current element + IteratorType iv_begin; ///< Iterator pointing to first + ///< element in range + IteratorType iv_end; ///< Iterator to past the end + ///< element in range + const PredicateBase* iv_pPredicate; ///< Range filter +}; + +typedef RangeFilter<TargetIterator> TargetRangeFilter; +typedef RangeFilter<ConstTargetIterator> ConstTargetRangeFilter; + +//****************************************************************************** +// RangeFilter::RangeFilter +//****************************************************************************** + +template<typename IteratorType> +RangeFilter<IteratorType>::RangeFilter( + const IteratorType& i_begin, + const IteratorType& i_end, + const PredicateBase* const i_pPredicate) +: iv_current(i_begin), + iv_begin(i_begin), + iv_end(i_end), + iv_pPredicate(i_pPredicate) +{ + advanceIfNoMatch(); +} + +//****************************************************************************** +// RangeFilter::operator= +//****************************************************************************** + +template<typename IteratorType> +RangeFilter<IteratorType>& RangeFilter<IteratorType>::operator=( + const RangeFilter& i_rhs) +{ + iv_current = i_rhs.iv_current; + iv_begin = i_rhs.iv_begin; + iv_end = i_rhs.iv_end; + iv_pPredicate = i_rhs.iv_pPredicate; +} + +//****************************************************************************** +// RangeFilter::RangeFilter (copy constructor) +//****************************************************************************** + +template<typename IteratorType> +RangeFilter<IteratorType>::RangeFilter( + const RangeFilter& i_rhs) +: iv_current(i_rhs.iv_current), + iv_begin(i_rhs.iv_begin), + iv_end(i_rhs.iv_end), + iv_pPredicate(i_rhs.iv_pPredicate) +{ +} + +//****************************************************************************** +// RangeFilter::setPredicate +//****************************************************************************** + +template<typename IteratorType> +void RangeFilter<IteratorType>::setPredicate( + const PredicateBase* const i_pPredicate) +{ + iv_pPredicate = i_pPredicate; + advanceIfNoMatch(); +} + +//****************************************************************************** +// RangeFilter::reset +//****************************************************************************** + +template<typename IteratorType> +void RangeFilter<IteratorType>::reset() +{ + iv_current = iv_begin; + advanceIfNoMatch(); +} + +//****************************************************************************** +// RangeFilter::operator++ +//****************************************************************************** + +template<typename IteratorType> +RangeFilter<IteratorType>& RangeFilter<IteratorType>::operator++() +{ + advance(); + return *this; +} + +/** + * @brief Disable meaningless "bool" comparisons that can occur when + * evaluating a range as a bool by forcing a compilation failure. + * Function interfaces not documented since they are not used. + */ +template <typename T> +bool operator!=(const TargetRangeFilter& i_lhs, const T& i_rhs) +{ + i_lhs.notComparable(); + return false; +} + +template <typename T> +bool operator==(const TargetRangeFilter& i_lhs, const T& i_rhs) +{ + i_lhs.notComparable(); + return false; +} + +template <typename T> +bool operator!=(const ConstTargetRangeFilter& i_lhs, const T& i_rhs) +{ + i_lhs.notComparable(); + return false; +} + +template <typename T> +bool operator==(const ConstTargetRangeFilter& i_lhs, const T& i_rhs) +{ + i_lhs.notComparable(); + return false; +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + +#endif + diff --git a/src/include/usr/targeting/iterators/targetiterator.H b/src/include/usr/targeting/iterators/targetiterator.H new file mode 100644 index 000000000..6f250cbb5 --- /dev/null +++ b/src/include/usr/targeting/iterators/targetiterator.H @@ -0,0 +1,257 @@ + +#ifndef TARG_TARGETITERATOR_H +#define TARG_TARGETITERATOR_H + +/** + * @file targetiterator.H + * + * @brief Interface describing iterator/const iterator used to iterate through + * target service targets + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD +#include <stddef.h> + +// Other Host Boot Components +#include <builtins.h> + +// Targeting Component + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FUNC + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" + +#define TARG_CLASS "_TargetIterator<T>::" + +class Target; + +/** + * @brief Class which iterates through targets managed by the target service. + * Provides "Target*" and "const Target*" versions via templates + */ +template<typename T> +class _TargetIterator +{ + public: + + /** + * @brief Maps type of iterated element to common alias (Target* or + * const Target*) + */ + typedef T iterator; + typedef T value_type; + + /** + * @brief Create an iterator to a (const/non-const) target handle. + * Defaults to end() + */ + ALWAYS_INLINE + _TargetIterator() + : iv_pCurrent(NULL) + { + } + + /** + * @brief Create an iterator to a (const/non-const) target handle + * + * @param[in] i_pTarget Target handle (pointer or const pointer + * depending on flavor) the iterator should reference + */ + ALWAYS_INLINE + explicit _TargetIterator(T i_pTarget) + : iv_pCurrent(i_pTarget) + { + } + + /** + * @brief Destroy an iterator to a (const/non-const) target handle + * + * @note Iterator does not own any resources to destroy + */ + ALWAYS_INLINE + ~_TargetIterator() + { + } + + /** + * @brief Dereference the iterator (return what it points to) + * + * @return Target handle in form of Target* or const Target* + * + * @note Returns NULL if it points to end(), should not be + * dereferenced in this case. + */ + ALWAYS_INLINE + T operator* () const + { + // Only return copy of the target pointer (instead of a reference) + // because a reference will go out of scope when the iterator + // advances + return iv_pCurrent; + } + + /** + * @brief Dereference the iterator (return what it points to) + * and (outside this function) call a function/member of + * the referenced target + * + * @return Target handle in form of Target* or const Target* + * + * @note Returns NULL if it points to end(), causing an + * assert when automatically dereferenced. + */ + ALWAYS_INLINE + T operator->() const + { + // Only return copy of the target pointer (instead of a reference) + // because a reference will go out of scope when the iterator + // advances + return iv_pCurrent; + } + + /** + * @brief Pre-increment the iterator + * + * @return The reference to the same iterator after advancing it + */ + ALWAYS_INLINE + _TargetIterator& operator++(); + + /** + * @brief Post-increment the iterator + * + * @param[in] UNNAMED Dummy parameter used to distinguish + * this interface from pre-increment + * + * @return Copy of the original iterator before it advanced + */ + ALWAYS_INLINE + _TargetIterator operator++(int); + + /** + * @brief Determine if two iterators of same type are logically equal + * + * @param[in] i_rhs The other iterator to compare + * + * @return bool indicating whether the iterators point to the same + * entity + * + * @retval true Iterators point to same entity + * @retval false Iterators do not point to same entity + */ + ALWAYS_INLINE + bool operator==(const _TargetIterator& i_rhs) const + { + return (iv_pCurrent == i_rhs.iv_pCurrent); + } + + /** + * @brief Determine if two iterators of same type are logically not + * equal + * + * @param[in] i_rhs The other iterator to compare + * + * @return bool indicating whether the iterators point to a different + * logical entity + * + * @retval true Iterators point to different entity + * @retval false Iterators point to same entity + */ + ALWAYS_INLINE + bool operator!=(const _TargetIterator& i_rhs) const + { + return (iv_pCurrent != i_rhs.iv_pCurrent); + } + + /** + * @brief Assignment operator; assign iterator to another (such that + * they logically point to same entity) + * + * @param[in] i_rhs The iterator to assign + * + * @return Reference to the iterator, now updated to point to the same + * entity as the input iterator points to + */ + ALWAYS_INLINE + _TargetIterator& operator=(const _TargetIterator& i_rhs) + { + iv_pCurrent = i_rhs.iv_pCurrent; + return *this; + } + + /** + * @brief Copy constructor; assign iterator to a new iterator (such + * that they logically point to same entity) + * + * @param[in] i_rhs The iterator to assign + */ + ALWAYS_INLINE + _TargetIterator(const _TargetIterator& i_rhs) + : iv_pCurrent(i_rhs.iv_pCurrent) + { + } + + private: + + /** + * @brief Advance the iterator to point to the next item maintained by + * the target service (or end() if end of list) + */ + void advance(); + + T iv_pCurrent; // Pointer to current target +}; + +/** + * @brief Type aliases to simplify user code + */ +typedef _TargetIterator<Target*> TargetIterator; +typedef _TargetIterator<const Target*> ConstTargetIterator; + +//****************************************************************************** +// _TargetIterator::operator++ (postincrement) +//****************************************************************************** + +template<typename T> +_TargetIterator<T> _TargetIterator<T>::operator++(int) +{ + _TargetIterator l_originalIterator(*this); + advance(); + return l_originalIterator; +} + +//****************************************************************************** +// _TargetIterator::operator++ (preincrement) +//****************************************************************************** + +template<typename T> +_TargetIterator<T>& _TargetIterator<T>::operator++() +{ + advance(); + return *this; +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + +#endif // TARG_TARGETITERATOR_H + diff --git a/src/include/usr/targeting/predicates/predicatebase.H b/src/include/usr/targeting/predicates/predicatebase.H new file mode 100644 index 000000000..e555092b9 --- /dev/null +++ b/src/include/usr/targeting/predicates/predicatebase.H @@ -0,0 +1,111 @@ + +#ifndef TARG_PREDICATEBASE_H +#define TARG_PREDICATEBASE_H + +/** + * @file predicatebase.H + * + * @brief Interface for an abstract targeting predicate which filters a set of + * targets based on the programmed criteria. Concrete predicates must + * provide the interface specified here. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component + +//****************************************************************************** +// Macros +//****************************************************************************** + +/** + * @brief Disable copy constructor / assignment operators + */ +#undef TARG_DISABLE_COPY_AND_ASSIGNMENT_OPERATORS +#define TARG_DISABLE_COPY_AND_ASSIGNMENT_OPERATORS(Type) \ + Type(const Type& i_other); \ + Type& operator=(const Type& i_other) + +/** + * @brief Ensure trace macros are undefined + */ +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicateBase::" + +class Target; + +/** + * @brief Abstract predicate class which specifies an interface for all + * concrete predicates. A predicate acts as a filter on a set of targets. + */ +class PredicateBase +{ + public: + + /** + * @brief Destroys the predicate base class (nothing to do) + */ + virtual ~PredicateBase(); + + /** + * @brief Predicate function call interface + * + * @par Detailed Description: + * This abstract interface must be declared/implemented by all + * derived predicates. A concrete version of this function accepts + * a target, applies the associated predicate logic, and returns + * whether the target met the predicate criteria or not. Caller + * must always supply a valid Target*, or routine will assert. + * + * @param[in] i_pTarget Pointer to target to apply predicate to + * + * @return Boolean indicating whether target matches criteria specified + * by the concrete predicate + * + * @retval true Target matches the predicate criteria + * @retval false Target does not match the predicate criteria + */ + virtual bool operator()( + const Target* i_pTarget) const = 0; + + protected: + + /** + * @brief Create the predicate base class (nothing to do) + * + * @note Constructor protected to allow access from the derived class + */ + PredicateBase() + { + #define TARG_FN "PredicateBase()" + #undef TARG_FN + } + + private: + + TARG_DISABLE_COPY_AND_ASSIGNMENT_OPERATORS(PredicateBase); +}; + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + +#endif // TARG_PREDICATEBASE_H diff --git a/src/include/usr/targeting/predicates/predicatectm.H b/src/include/usr/targeting/predicates/predicatectm.H new file mode 100644 index 000000000..760f0d02d --- /dev/null +++ b/src/include/usr/targeting/predicates/predicatectm.H @@ -0,0 +1,118 @@ + +#ifndef TARG_PREDICATECTM_H +#define TARG_PREDICATECTM_H + +/** + * @file predicatectm.H + * + * @brief Interface for a predicate which fiters a target based on its class, + * type, and model. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/target.H> +#include <targeting/attributeenums.H> +#include <targeting/predicates/predicatebase.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicateCTM::" + +class Target; + +/** + * @brief Predicate class which filters a target based on its class, type, + * and model + */ +class PredicateCTM : public PredicateBase +{ + public: + + /** + * @brief Create a target class, type, model predicate + * + * @param[in] i_class Class of matching target, default NA (any) + * @param[in] i_type Type of matching target, default NA (any) + * @param[in] i_model Model of matching target, default NA (any) + */ + PredicateCTM( + CLASS i_class = CLASS_NA, + TYPE i_type = TYPE_NA, + MODEL i_model = MODEL_NA); + + /** + * @brief Destroy a class, type, model predicate + */ + virtual ~PredicateCTM() + { + #define TARG_FUNC "~PredicateCTM()" + #undef TARG_FUNC + } + + /** + * @brief Returns whether target matches the specified class, type, + * model + * + * @par Detailed Description: + * Returns whether target matches the specified class, type, model. + * Note that all three fields are always compared, so wildcards + * (CLASS_NA, TYPE_NA, MODEL_NA) must be used for any fields that + * do not matter. See PredicateBase class for parameter/return + * description. + */ + virtual bool operator()( + const Target* i_pTarget) const; + + private: + + CLASS iv_class; ///< Class to compare with that of target + TYPE iv_type; ///< Type to compare with that of target + MODEL iv_model; ///< Model to compare with that of target + + TARG_DISABLE_COPY_AND_ASSIGNMENT_OPERATORS(PredicateCTM); +}; + +//****************************************************************************** +// PredicateCTM::PredicateCTM +//****************************************************************************** + +inline PredicateCTM::PredicateCTM( + const CLASS i_class, + const TYPE i_type, + const MODEL i_model) +: iv_class(i_class), + iv_type(i_type), + iv_model(i_model) +{ + #define TARG_FUNC "PredicateCTM(...)" + #undef TARG_FUNC +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + +#endif // TARG_PREDICATECTM_H diff --git a/src/include/usr/targeting/predicates/predicatepostfixexpr.H b/src/include/usr/targeting/predicates/predicatepostfixexpr.H new file mode 100644 index 000000000..12388fc46 --- /dev/null +++ b/src/include/usr/targeting/predicates/predicatepostfixexpr.H @@ -0,0 +1,204 @@ + +#ifndef TARG_PREDICATEPOSTFIXEXPR_H +#define TARG_PREDICATEPOSTFIXEXPR_H + +/** + * @file predicatepostfixexpr.H + * + * @brief Interface for predicate which allows callers to chain multiple other + * predicates together in complex logical expressions, and then evaluate + * them against a target + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD +#include <vector> + +// Other Host Boot Components + +// Targeting Component +#include <targeting/predicates/predicatebase.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicatePostfixExpr::" + +class Target; + +/** + * @brief Predicate which can compute aribtrarily complex logical expressions + * of other predicates using postfix notation + */ +class PredicatePostfixExpr : public PredicateBase +{ + public: + + /** + * @brief Create empty postfix predicate expression which will always + * evaluate true if not otherwise modified. Any updates to the + * expression completely replace the initial "always true" + * behavior. + */ + PredicatePostfixExpr(); + + /** + * @brief Destroy a postfix predicate expression + * + * @note: Nothing extra to do here since object does not own the + * predicates + */ + virtual ~PredicatePostfixExpr(); + + /** + * @brief Updates the postfix predicate expression by pushing the given + * predicate onto the expression stack + * + * @param[in] i_pPredicate Pointer to existing concrete predicate. + * Passing a NULL predicate is not allowed (results in assert) + * + * @verbatim + * Example: + * + * Stack before calling push(&P2): P1 + * Stack after calling push(&P2): P1 P2 + * @endverbatim + * + * @return Reference to the same predicate expression, for chaining + */ + PredicatePostfixExpr& push( + const PredicateBase* i_pPredicate); + + /** + * @brief Updates the postfix predicate expression by pushing the + * logical "AND" operation onto the expression stack. + * + * @verbatim + * Example: + * + * Stack before calling And(): P1 P2 + * Stack after calling And(): P1 P2 AND + * Stack after evaluation: (P1 && P2) + * @endverbatim + * + * @return Reference to the same predicate expression, for chaining + */ + PredicatePostfixExpr& And(); + + /** + * @brief Updates the postfix predicate expression by pushing the + * logical "NOT" operation onto the expression stack. + * + * @verbatim + * Example: + * + * Stack before calling Not(): P1 + * Stack after calling Not(): P1 NOT + * Stack after evaluation: (!P1) + * @endverbatim + * + * @return Reference to the same predicate expression, for chaining + */ + PredicatePostfixExpr& Not(); + + /** + * @brief Updates the postfix predicate expression by pushing the + * logical "OR" operation onto the expression stack. + * + * @verbatim + * Example: + * + * Stack before calling Or(): P1 P2 + * Stack after calling Or(): P1 P2 OR + * Stack after evaluation: (P1 || P2) + * @endverbatim + * + * @return Reference to the same predicate expression for chaining + */ + PredicatePostfixExpr& Or(); + + /** + * @brief Returns whether the given target matches the criteria + * specified by the postfix predicate expression + * + * @par Detailed Description: + * Returns whether the given target matches the criteria + * specified by the postfix predicate expression. The routine + * sequentially evaluates a predicate against the supplied target + * or applies a logical operation to one or more prior predicate + * evaluations using a postfix algorithm. Routine will assert + * if postfix expression is not formatted properly, final result + * stack does not have exactly one result, target is NULL, or + * invalid logical operator was requested. See PredicateBase class + * for parameter/return description. + * + * @verbatim + * Example: + * + * PredicatePostfixExpr l_expr; + * l_expr.push(&P1).push(&P2).Or().push(&P3).And().Not(); + * + * Equivalent infix expression: !((P1 || P2) && P3) + * Assume predicate results of: P1 = 0, P2 = 1, P3 = 0 + * Expression stack prior to evaluation: P1 P2 OR P3 AND NOT + * Evaluation step 1: 1 P3 AND NOT (evaluated P1 P2 OR) + * Evaluation step 2: 0 NOT (evaluated 1 P3 AND) + * Evaluation step 3: 1 (evaluated 0 NOT; final result) + * @endverbatim + */ + virtual bool operator()( + const Target* i_pTarget) const; + + private: + + /** + * @brief Enumeration describing the type of logical operator to + * apply to one or more previous predicate evaluations + */ + enum LogicalOperator + { + EVAL, ///< Special logical operator - evaluate a predicate + AND, ///< Logically AND the result of the preceding two evaluations + OR, ///< Logically OR the result of the preceding two evaluations + NOT, ///< Logically negate the result of the preceding evaluation + }; + + /** + * @brief Structure describing one unit of the postfix predicate + * expression under evaluation + */ + struct Operation + { + LogicalOperator logicalOp; ///< Logical operator to + ///< apply to result stack + const PredicateBase* const pPredicate; ///< Predicate to evaluate, + ///< if logicalOp == EVAL + }; + + std::vector<Operation> iv_ops; ///< Expression operations to perform + + TARG_DISABLE_COPY_AND_ASSIGNMENT_OPERATORS(PredicatePostfixExpr); +}; + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + +#endif // TARG_PREDICATEPOSTFIXEXPR_H diff --git a/src/include/usr/targeting/targetservice.H b/src/include/usr/targeting/targetservice.H index 2797890c5..77e4b23f4 100644 --- a/src/include/usr/targeting/targetservice.H +++ b/src/include/usr/targeting/targetservice.H @@ -28,6 +28,8 @@ #include <targeting/attributeenums.H> #include <targeting/target.H> #include <targeting/entitypath.H> +#include <targeting/iterators/targetiterator.H> +#include <targeting/predicates/predicatebase.H> //****************************************************************************** // Interface Definitions @@ -140,6 +142,52 @@ class TargetService void init(); /** + * @brief Map iterator types to common aliases + */ + typedef TargetIterator iterator; + typedef ConstTargetIterator const_iterator; + + /** + * @brief Return iterator which points to first target service target + * (or end() if none) + * + * @return Iterator pointing to first target service target + */ + iterator begin(); + + /** + * @brief Return iterator to const which points to first target service + * target (or end() if none) + * + * @return Iterator to const pointing to first target service target + */ + const_iterator begin() const; + + /** + * @brief Return iterator which points to the "past the end of the + * list" target maintained by the target service + * + * @return Iterator pointing to the "past the end of the list" target + * maintained by the target service + */ + iterator end(); + + /** + * @brief Return iterator to const which points to the "past the end of + * the list" target maintained by the target service + * + * @return Iterator to const pointing to the "past the end of the list" + * target maintained by the target service + */ + const_iterator end() const; + + /** + * @brief Allow iterator access to the target service's target store + */ + friend class _TargetIterator<Target*>; + friend class _TargetIterator<const Target*>; + + /** * @brief Returns the top level physical target * * Returns the top level (usually system) target. Caller must check @@ -272,25 +320,31 @@ class TargetService * for said source target, the routine will return all targets * contained within the processor chip. * + * @param[out] o_list List of target handles that match the specified + * criteria * @param[in] i_pTarget Target from which to search for other targets * @param[in] i_type Type of association linking the specified target * to candidate result targets * @param[in] i_recursionLevel Whether to return candidate targets * immediately associated to the specified target or recursively * associated to it. - * @param[out] o_list List of target handles that match the specified - * criteria + * @param[in] i_pPredicate Pointer to a predicate to be evaluated + * against each candidate target (as determined by the source + * target, type, and recursion level parameters). If the predicate + * returns true, the target will be added to the result list. A + * value of NULL acts as a predicate that always returns true. * * @pre N/A * * @post Caller's list cleared; list of target handles matching the * specified criteria returned */ - void getAssociated( - const Target* i_pTarget, - ASSOCIATION_TYPE i_type, - RECURSION_LEVEL i_recursionLevel, - TargetHandleList& o_list) const; + void getAssociated( + TargetHandleList& o_list, + const Target* const i_pTarget, + const ASSOCIATION_TYPE i_type = CHILD, + const RECURSION_LEVEL i_recursionLevel = IMMEDIATE, + const PredicateBase* i_pPredicate = NULL) const; /** * @brief Dump the target service for debug only @@ -387,6 +441,10 @@ class TargetService * @param[in] i_recursionLevel Whether to provide immediate or * recursive results * @param[in] i_entityPath Entity path to start search from + * @param[in] i_pPredicate Pointer to a predicate to be evaluated + * against each candidate target. If the predicate returns true, + * the target will be added to the result list. A value of NULL + * acts as a predicate that always returns true. * @param[out] o_list List of returned target handles * * @pre Target service must be initialized @@ -396,10 +454,11 @@ class TargetService * path returned */ void _getInwards( - ATTRIBUTE_ID i_attr, - RECURSION_LEVEL i_recursionLevel, - EntityPath i_entityPath, - TargetHandleList& o_list) const; + ATTRIBUTE_ID i_attr, + RECURSION_LEVEL i_recursionLevel, + EntityPath i_entityPath, + const PredicateBase* i_pPredicate, + TargetHandleList& o_list) const; /** * @brief Returns handles to the targets associated to the @@ -418,6 +477,10 @@ class TargetService * @param[in] i_recursionLevel Whether to provide immediate or * recursive results * @param[in] i_entityPath Entity path to look from + * @param[in] i_pPredicate Pointer to a predicate to be evaluated + * against each candidate target. If the predicate returns true, + * the target will be added to the result list. A value of NULL + * acts as a predicate that always returns true. * @param[out] o_list List of returned target handles * * @pre Target service must be initialized @@ -427,13 +490,13 @@ class TargetService * entity path returned. */ void _getOutwards( - ATTRIBUTE_ID i_attr, - RECURSION_LEVEL i_recursionLevel, - EntityPath i_entityPath, - TargetHandleList& o_list ) const; + ATTRIBUTE_ID i_attr, + RECURSION_LEVEL i_recursionLevel, + EntityPath i_entityPath, + const PredicateBase* i_pPredicate, + TargetHandleList& o_list ) const; // Instance variables - bool iv_initialized; ///< Is service initialized or not Target (*iv_targets)[]; ///< Pointer to array of target objects uint32_t iv_maxTargets; ///< Maximum # target objects in the array diff --git a/src/usr/targeting/iterators/rangefilter.C b/src/usr/targeting/iterators/rangefilter.C new file mode 100644 index 000000000..64ceb1f78 --- /dev/null +++ b/src/usr/targeting/iterators/rangefilter.C @@ -0,0 +1,89 @@ + +/** + * @file rangefilter.C + * + * @brief Implementation of an object which takes an iterator range and + * allows caller to iterate through the elements which match a supplied + * predicate (filter) + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/iterators/rangefilter.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FUNC + +//****************************************************************************** +// Implementation +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" + +#define TARG_CLASS "RangeFilter<IteratorType>::" + +//****************************************************************************** +// RangeFilter<IteratorType>::advance +//****************************************************************************** + +template<typename IteratorType> +void RangeFilter<IteratorType>::advance() +{ + if(iv_current != iv_end) + { + while( (++iv_current) != iv_end ) + { + if( (!iv_pPredicate) + || ((*iv_pPredicate)(*iv_current))) + { + break; + } + } + } +} + +//****************************************************************************** +// RangeFilter<IteratorType>::advanceIfNoMatch +//****************************************************************************** + +template<typename IteratorType> +void RangeFilter<IteratorType>::advanceIfNoMatch() +{ + if( (iv_current != iv_end) + && ( (iv_pPredicate) + && (!((*iv_pPredicate)(*iv_current))))) + { + advance(); + } +} + +//****************************************************************************** +// Explicit template class member function instantiations +//****************************************************************************** + +template void RangeFilter<TargetIterator>::advance(); +template void RangeFilter<ConstTargetIterator>::advance(); + +template void RangeFilter<TargetIterator>::advanceIfNoMatch(); +template void RangeFilter<ConstTargetIterator>::advanceIfNoMatch(); + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + diff --git a/src/usr/targeting/iterators/targetiterator.C b/src/usr/targeting/iterators/targetiterator.C new file mode 100644 index 000000000..f3549a633 --- /dev/null +++ b/src/usr/targeting/iterators/targetiterator.C @@ -0,0 +1,88 @@ + +/** + * @file targetiterator.C + * + * @brief Implementation of iterator/const iterator used to iterate through + * target service targets + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/iterators/targetiterator.H> +#include <targeting/targetservice.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FUNC + +//****************************************************************************** +// Implementation +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" + +#define TARG_CLASS "_TargetIterator<T>::" + +//****************************************************************************** +// TargetIterator::advance +//****************************************************************************** + +template<typename T> +void _TargetIterator<T>::advance() +{ + TargetService& l_targetService = targetService(); + + // If cursor points to end()/NULL, do nothing. Otherwise, check to see if + // it should advance (possibly to NULL) + if(iv_pCurrent != NULL) + { + // Advance to end() if no targets available. Otherwise, check to see if + // it should advance (possibly to NULL) + if (l_targetService.iv_maxTargets > 0) + { + // If at or past last element, advance to end() else advance + if(iv_pCurrent >= + &(*l_targetService.iv_targets)[l_targetService.iv_maxTargets-1]) + { + iv_pCurrent = NULL; + } + else + { + iv_pCurrent++; + } + } + else + { + iv_pCurrent = NULL; + } + } +} + +//****************************************************************************** +// Explicit template class member function instantiations +//****************************************************************************** + +template void _TargetIterator<Target*>::advance(); +template void _TargetIterator<const Target*>::advance(); + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + + + diff --git a/src/usr/targeting/makefile b/src/usr/targeting/makefile index 09b9d3be3..70edd18ac 100644 --- a/src/usr/targeting/makefile +++ b/src/usr/targeting/makefile @@ -1,7 +1,26 @@ ROOTPATH = ../../.. MODULE = targeting -OBJS = target.o targetservice.o entitypath.o fakepnordata.o +VPATH = \ + predicates: \ + iterators: + +PREDICATES_OBJS = \ + predicatebase.o \ + predicatepostfixexpr.o \ + predicatectm.o + +ITERATORS_OBJS = \ + targetiterator.o \ + rangefilter.o + +TARGET_OBJS = \ + target.o \ + targetservice.o \ + entitypath.o \ + fakepnordata.o + +OBJS = ${TARGET_OBJS} ${PREDICATES_OBJS} ${ITERATORS_OBJS} SUBDIRS = test.d diff --git a/src/usr/targeting/predicates/predicatebase.C b/src/usr/targeting/predicates/predicatebase.C new file mode 100644 index 000000000..61e17b984 --- /dev/null +++ b/src/usr/targeting/predicates/predicatebase.C @@ -0,0 +1,54 @@ + +/** + * @file predicatebase.C + * + * @brief Implementation for an abstract targeting predicate which filters a + * set of targets based on the programmed criteria. Only required to + * implement the virtual destrutor which leads to duplicate weak symbols + * if it were instead inlined. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/predicates/predicatebase.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicateBase::" + +//****************************************************************************** +// PredicateBase::~PredicateBase +//****************************************************************************** + +PredicateBase::~PredicateBase() +{ + #define TARG_FN "~PredicateBase()" + #undef TARG_FN +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + diff --git a/src/usr/targeting/predicates/predicatectm.C b/src/usr/targeting/predicates/predicatectm.C new file mode 100644 index 000000000..8185020f5 --- /dev/null +++ b/src/usr/targeting/predicates/predicatectm.C @@ -0,0 +1,63 @@ + +/** + * @file predicatectm.C + * + * @brief Implementation for a predicate which fiters a target based on its + * class, type, and model. + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components + +// Targeting Component +#include <targeting/target.H> +#include <targeting/attributeenums.H> +#include <targeting/predicates/predicatectm.H> + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicateCTM::" + +//****************************************************************************** +// PredicateCTM::operator() +//****************************************************************************** + +bool PredicateCTM::operator()( + const Target* const i_pTarget) const +{ + #define TARG_FUNC "operator()(...)" + + return ( ( (iv_class == CLASS_NA) + || (i_pTarget->getAttr<ATTR_CLASS>() == iv_class)) + && ( (iv_type == TYPE_NA) + || (i_pTarget->getAttr<ATTR_TYPE>() == iv_type)) + && ( (iv_model == MODEL_NA) + || (i_pTarget->getAttr<ATTR_MODEL>() == iv_model))); + + #undef TARG_FUNC +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + diff --git a/src/usr/targeting/predicates/predicatepostfixexpr.C b/src/usr/targeting/predicates/predicatepostfixexpr.C new file mode 100644 index 000000000..7f5e89260 --- /dev/null +++ b/src/usr/targeting/predicates/predicatepostfixexpr.C @@ -0,0 +1,198 @@ + +/** + * @file predicatepostfixexpr.C + * + * @brief Implementation for predicate which allows callers to chain multiple + * other predicates together in complex logical expressions, and then + * evaluate them against a target + */ + +//****************************************************************************** +// Includes +//****************************************************************************** + +// STD + +// Other Host Boot Components +#include <assert.h> + +// Targeting Component +#include <targeting/predicates/predicatepostfixexpr.H> +#include "../trace.H" + +//****************************************************************************** +// Macros +//****************************************************************************** + +#undef TARG_NAMESPACE +#undef TARG_CLASS +#undef TARG_FN + +//****************************************************************************** +// Interface +//****************************************************************************** + +namespace TARGETING +{ + +#define TARG_NAMESPACE "TARGETING::" +#define TARG_CLASS "PredicatePostfixExpr::" + +//****************************************************************************** +// PredicatePostfixExpr::PredicatePostfixExpr +//****************************************************************************** + +PredicatePostfixExpr::PredicatePostfixExpr() +{ +} + +//****************************************************************************** +// PredicatePostfixExpr::~PredicatePostfixExpr +//****************************************************************************** + +PredicatePostfixExpr::~PredicatePostfixExpr() +{ +} + +//****************************************************************************** +// PredicatePostfixExpr::push +//****************************************************************************** + +PredicatePostfixExpr& PredicatePostfixExpr::push( + const PredicateBase* const i_pPredicate) +{ + #define TARG_FN "push(...)" + + assert(i_pPredicate != NULL, + TARG_LOC "Caller supplied a NULL predicate"); + Operation l_op = {EVAL,i_pPredicate}; + iv_ops.push_back(l_op); + return *this; + + #undef TARG_FN +} + +//****************************************************************************** +// PredicatePostfixExpr::And +//****************************************************************************** + +PredicatePostfixExpr& PredicatePostfixExpr::And() +{ + #define TARG_FN "And()" + + Operation l_op = {AND,NULL}; + iv_ops.push_back(l_op); + return *this; + + #undef TARG_FN +} + +//****************************************************************************** +// PredicatePostfixExpr::Not +//****************************************************************************** + +PredicatePostfixExpr& PredicatePostfixExpr::Not() +{ + #define TARG_FN "Not()" + + Operation l_op = {NOT,NULL}; + iv_ops.push_back(l_op); + return *this; + + #undef TARG_FN +} + +//****************************************************************************** +// PredicatePostfixExpr::Or +//****************************************************************************** + +PredicatePostfixExpr& PredicatePostfixExpr::Or() +{ + #define TARG_FN "Or()" + + Operation l_op = {OR,NULL}; + iv_ops.push_back(l_op); + return *this; + + #undef TARG_FN +} + +//****************************************************************************** +// PredicatePostfixExpr::operator() +//****************************************************************************** + +bool PredicatePostfixExpr::operator()( + const Target* const i_pTarget) const +{ + #define TARG_FN "operator()(...)" + + assert(i_pTarget != NULL, + TARG_LOC "Caller supplied a NULL target"); + + std::vector<bool> l_stack; + bool l_result = false; + + for(uint32_t i=0; i<iv_ops.size(); ++i) + { + switch(iv_ops[i].logicalOp) + { + case EVAL: + l_stack.push_back((*iv_ops[i].pPredicate)(i_pTarget)); + break; + case AND: + assert(l_stack.size() >= 2, + TARG_LOC "Stack for AND must be >=2 but is %d", + l_stack.size()); + l_result = l_stack.back(); + l_stack.pop_back(); + l_stack.back() &= l_result; + break; + case OR: + assert(l_stack.size() >= 2, + TARG_LOC "Stack for OR must be >= 2 but is %d", + l_stack.size()); + l_result = l_stack.back(); + l_stack.pop_back(); + l_stack.back() |= l_result; + break; + case NOT: + assert(l_stack.size() >= 1, + TARG_LOC "Stack for NOT must be >= 1 but is %d", + l_stack.size()); + l_stack.back() = !l_stack.back(); + break; + default: + assert(0, + TARG_LOC "Attempted to evaluate unsupported " + "logical operation %d", + iv_ops[i].logicalOp); + break; + } + } + + // If no predicates and we haven't asserted (no misformatting), element + // should be returned + if(l_stack.size() == 0) + { + l_result = true; + } + else + { + assert(l_stack.size() == 1, + TARG_LOC "Postfix expression created incorrectly. Stack " + "size should be 1 but is %d", + l_stack.size()); + + l_result = l_stack.front(); + } + + return l_result; + + #undef TARG_FN +} + +#undef TARG_CLASS +#undef TARG_NAMESPACE + +} // End namespace TARGETING + diff --git a/src/usr/targeting/targetservice.C b/src/usr/targeting/targetservice.C index 4418358ef..3b3b4098b 100644 --- a/src/usr/targeting/targetservice.C +++ b/src/usr/targeting/targetservice.C @@ -23,6 +23,7 @@ #include <targeting/targetservice.H> #include "trace.H" #include "fakepnordata.H" +#include <targeting/predicates/predicatebase.H> //****************************************************************************** // targetService @@ -162,6 +163,72 @@ void TargetService::init() } //****************************************************************************** +// TargetService::begin (non-const version) +//****************************************************************************** + +TargetService::iterator TargetService::begin() +{ + #define TARG_FN "begin()" + + assert(iv_initialized); + + Target* l_pFirstTarget = (iv_maxTargets == 0) ? NULL : &(*iv_targets)[0]; + + return iterator(l_pFirstTarget); + + #undef TARG_FN +} + +//****************************************************************************** +// TargetService::begin (const version) +//****************************************************************************** + +//TargetService::const_iterator +_TargetIterator<const Target*> TargetService::begin() const +{ + #define TARG_FN "begin() const" + + assert(iv_initialized); + + const Target* l_pFirstTarget = + (iv_maxTargets == 0) ? NULL : &(*iv_targets)[0]; + + return const_iterator(l_pFirstTarget); + + #undef TARG_FN +} + +//****************************************************************************** +// TargetService::end (non-const version) +//****************************************************************************** + +TargetService::iterator TargetService::end() +{ + #define TARG_FN "end()" + + assert(iv_initialized); + + return iterator(NULL); + + #undef TARG_FN +} + +//****************************************************************************** +// TargetService::end (const version) +//****************************************************************************** + +TargetService::const_iterator TargetService::end() const +{ + #define TARG_FN "end() const" + + assert(iv_initialized); + + return const_iterator(NULL); + + #undef TARG_FN +} + +//****************************************************************************** // TargetService::getTopLevelTarget //****************************************************************************** @@ -305,10 +372,11 @@ bool TargetService::tryGetPath( //****************************************************************************** void TargetService::getAssociated( - const Target* const i_pTarget, - const ASSOCIATION_TYPE i_type, - const RECURSION_LEVEL i_recursionLevel, - TargetHandleList& o_list) const + TargetHandleList& o_list, + const Target* const i_pTarget, + const ASSOCIATION_TYPE i_type, + const RECURSION_LEVEL i_recursionLevel, + const PredicateBase* const i_pPredicate) const { #define TARG_FN "getAssociated(...)" @@ -340,13 +408,13 @@ void TargetService::getAssociated( if (iv_associationMappings[i].associationDir == INWARDS) { (void) _getInwards(iv_associationMappings[i].attr, - i_recursionLevel, l_entityPath, o_list); + i_recursionLevel, l_entityPath, i_pPredicate, o_list); } else if (iv_associationMappings[i].associationDir == OUTWARDS) { (void) _getOutwards(iv_associationMappings[i].attr, - i_recursionLevel, l_entityPath, o_list); + i_recursionLevel, l_entityPath, i_pPredicate, o_list); } else { @@ -509,10 +577,11 @@ uint32_t TargetService::_maxTargets() //****************************************************************************** void TargetService::_getInwards( - const ATTRIBUTE_ID i_attr, - const RECURSION_LEVEL i_recursionLevel, - EntityPath i_entityPath, - TargetHandleList& o_list) const + const ATTRIBUTE_ID i_attr, + const RECURSION_LEVEL i_recursionLevel, + EntityPath i_entityPath, + const PredicateBase* const i_pPredicate, + TargetHandleList& o_list) const { #define TARG_FN "_getInwards(...)" @@ -524,7 +593,10 @@ void TargetService::_getInwards( EntityPath l_candidatePath; bool l_candidateFound = tryGetPath(i_attr, &(*iv_targets)[i], l_candidatePath); - if (l_candidateFound && (l_candidatePath == i_entityPath)) + if ( l_candidateFound + && (l_candidatePath == i_entityPath) + && ( (i_pPredicate == NULL) + || (*i_pPredicate)( &(*iv_targets)[i]) ) ) { o_list.push_back(&(*iv_targets)[i]); break; @@ -545,10 +617,11 @@ void TargetService::_getInwards( //****************************************************************************** void TargetService::_getOutwards( - const ATTRIBUTE_ID i_attr, - const RECURSION_LEVEL i_recursionLevel, - EntityPath i_entityPath, - TargetHandleList& o_list) const + const ATTRIBUTE_ID i_attr, + const RECURSION_LEVEL i_recursionLevel, + EntityPath i_entityPath, + const PredicateBase* const i_pPredicate, + TargetHandleList& o_list) const { #define TARG_FN "_getOutwards()...)" @@ -573,7 +646,9 @@ void TargetService::_getOutwards( || ( (i_recursionLevel == ALL) && (l_candidatePath.size() > i_entityPath.size()))) { - if (i_entityPath.equals(l_candidatePath,i_entityPath.size())) + if ( i_entityPath.equals(l_candidatePath,i_entityPath.size()) + && ( (i_pPredicate == NULL) + || (*i_pPredicate)( &(*iv_targets)[i]) ) ) { o_list.push_back(&(*iv_targets)[i]); } @@ -591,3 +666,4 @@ void TargetService::_getOutwards( #undef TARG_NAMESPACE } // End namespace TARGETING + diff --git a/src/usr/targeting/test/targetingtest.H b/src/usr/targeting/test/targetingtest.H index bd8ffdb0e..309bf3606 100644 --- a/src/usr/targeting/test/targetingtest.H +++ b/src/usr/targeting/test/targetingtest.H @@ -23,6 +23,9 @@ #include <targeting/entitypath.H> #include <targeting/target.H> #include <targeting/targetservice.H> +#include <targeting/iterators/rangefilter.H> +#include <targeting/predicates/predicatectm.H> +#include <targeting/predicates/predicatepostfixexpr.H> class TargetingTestSuite: public CxxTest::TestSuite { @@ -128,9 +131,11 @@ class TargetingTestSuite: public CxxTest::TestSuite // TargetHandleList& o_list) const; TargetHandleList l_list; - (void) l_targetService.getAssociated(l_pTopLevel, + (void) l_targetService.getAssociated( + l_list, + l_pTopLevel, TARGETING::TargetService::CHILD, - TARGETING::TargetService::IMMEDIATE, l_list); + TARGETING::TargetService::IMMEDIATE); if (!l_list.size()) { TS_FAIL("Should have found some child elements" ); @@ -140,9 +145,11 @@ class TargetingTestSuite: public CxxTest::TestSuite // target TargetHandleList l_parentList; - (void) l_targetService.getAssociated(l_list[0], + (void) l_targetService.getAssociated( + l_parentList, + l_list[0], TARGETING::TargetService::PARENT, - TARGETING::TargetService::IMMEDIATE, l_parentList); + TARGETING::TargetService::IMMEDIATE); if (l_parentList.size() != 1) { @@ -155,18 +162,22 @@ class TargetingTestSuite: public CxxTest::TestSuite "handle" ); } - (void) l_targetService.getAssociated(l_pTopLevel, + (void) l_targetService.getAssociated( + l_list, + l_pTopLevel, TARGETING::TargetService::CHILD_BY_AFFINITY, - TARGETING::TargetService::IMMEDIATE, l_list); + TARGETING::TargetService::IMMEDIATE); if (!l_list.size()) { TS_FAIL("Should have found some child elements" ); } - (void) l_targetService.getAssociated(l_pTopLevel, + (void) l_targetService.getAssociated( + l_list, + l_pTopLevel, TARGETING::TargetService::CHILD_BY_AFFINITY, - TARGETING::TargetService::ALL, l_list); + TARGETING::TargetService::ALL); if (!l_list.size()) { @@ -452,6 +463,512 @@ class TargetingTestSuite: public CxxTest::TestSuite TS_TRACE(EXIT_MRK "testTargetClass" ); } + + void testPredicateCtm() + { + TS_TRACE(ENTER_MRK "testPredicateCtm" ); + + using namespace TARGETING; + TargetService& l_targetService = targetService(); + + // Get top level (system) target + Target* l_pTopLevel = NULL; + (void) l_targetService.getTopLevelTarget(l_pTopLevel); + if (l_pTopLevel == NULL) + { + TS_FAIL("Top level handle was NULL when initialization " + "complete"); + } + + PredicateCTM l_allWild; + if( ! l_allWild(l_pTopLevel) ) + { + TS_FAIL("CTM all wildcards filter should have matched system " + "target"); + } + + PredicateCTM l_typeModelWild(CLASS_SYS); + if( ! l_typeModelWild(l_pTopLevel) ) + { + TS_FAIL("CTM class sys, remaining wildcards filter should have " + "matched system "); + } + + PredicateCTM l_modelWild(CLASS_SYS,TYPE_SYS); + if( ! l_modelWild(l_pTopLevel) ) + { + TS_FAIL("CTM class sys, type sys, remaining wildcards filter " + "should have matched system "); + } + + PredicateCTM l_noWild(CLASS_SYS,TYPE_SYS,MODEL_POWER8); + if( ! l_noWild(l_pTopLevel) ) + { + TS_FAIL("CTM class sys, type sys, model power8 should have " + "matched system "); + } + + PredicateCTM l_classWild(CLASS_NA,TYPE_SYS,MODEL_POWER8); + if( ! l_classWild(l_pTopLevel) ) + { + TS_FAIL("CTM class wild, type sys, model power8 should have " + "matched system "); + } + + PredicateCTM l_typeWild(CLASS_SYS,TYPE_NA,MODEL_POWER8); + if( ! l_typeWild(l_pTopLevel) ) + { + TS_FAIL("CTM class sys, wild, model power8 should have " + "matched system "); + } + + PredicateCTM l_classModelWild(CLASS_NA,TYPE_SYS,MODEL_NA); + if( ! l_classModelWild(l_pTopLevel) ) + { + TS_FAIL("CTM wild, type sys, wild should have " + "matched system "); + } + + PredicateCTM l_classTypeWild(CLASS_NA,TYPE_NA,MODEL_NA); + if( ! l_classTypeWild(l_pTopLevel) ) + { + TS_FAIL("CTM wild, wild, model should have " + "matched system "); + } + + PredicateCTM l_chipClass(CLASS_CHIP,TYPE_NA,MODEL_NA); + if( l_chipClass(l_pTopLevel) ) + { + TS_FAIL("CTM of class chip, wild, wild should not have matched " + "matched system "); + } + + #if 0 // Prove copy CTOR/assignment operator is disabled + PredicateCTM l_ctmLhs; + PredicateCTM l_ctmRhs; + + l_ctmLhs = l_ctmRhs; + + PredicateCTM l_ctmCtor(l_ctmRhs); + #endif + + PredicateBase* l_pBase = new PredicateCTM(CLASS_SYS); + delete l_pBase; + l_pBase = NULL; + + TS_TRACE(EXIT_MRK "testPredicateCtm" ); + + } + + void testPredicatePostfixExpr() + { + TS_TRACE(ENTER_MRK "testPredicatePostfixExpr" ); + + using namespace TARGETING; + TargetService& l_targetService = targetService(); + + // Get top level (system) target + Target* l_pTopLevel = NULL; + (void) l_targetService.getTopLevelTarget(l_pTopLevel); + if (l_pTopLevel == NULL) + { + TS_FAIL("Top level handle was NULL when initialization " + "complete"); + } + + PredicatePostfixExpr l_alwaysTrueExpr; + if(!l_alwaysTrueExpr(l_pTopLevel) ) + { + TS_FAIL("Always true filter should have matched system"); + } + + #if 0 + // Triggers NULL assertion check on push + l_alwaysTrueExpr.push(NULL); + #endif + + #if 0 + // Triggers not enough stack elements assertion when evaluating Not + l_alwaysTrueExpr.Not(); + if(l_alwaysTrueExpr(l_pTopLevel) ) + { + TS_FAIL("Negated always true filter should not have matched " + "system"); + } + #endif + + #if 0 + // Triggers illegal target assertion + l_alwaysTrueExpr(NULL); + #endif + + #if 0 + // Triggers formatting assertion + l_alwaysTrueExpr.And(); + l_alwaysTrueExpr(l_pTopLevel); + #endif + + #if 0 + // Triggers formatting assertion + l_alwaysTrueExpr.Or(); + l_alwaysTrueExpr(l_pTopLevel); + #endif + + PredicateCTM l_sysClass(CLASS_SYS); + + #if 0 + // Triggers formatting assertion + l_alwaysTrueExpr.push(&l_sysClass); + l_alwaysTrueExpr.And(); + l_alwaysTrueExpr(l_pTopLevel); + #endif + + #if 0 + // Triggers formatting assertion + l_alwaysTrueExpr.push(&l_sysClass); + l_alwaysTrueExpr.Or(); + l_alwaysTrueExpr(l_pTopLevel); + #endif + + #if 0 + // Triggers illegal formatting exception + // != 1 results on stack + l_alwaysTrueExpr.push(&l_sysClass); + l_alwaysTrueExpr.push(&l_sysClass); + l_alwaysTrueExpr.Not(); + l_alwaysTrueExpr(l_pTopLevel); + #endif + + PredicateCTM l_sysType(CLASS_NA,TYPE_SYS); + PredicateCTM l_power8Model(CLASS_NA,TYPE_NA,MODEL_POWER8); + PredicatePostfixExpr l_expr; + l_expr.push(&l_sysClass).push(&l_sysType).And(); + l_expr.push(&l_power8Model).And(); + + if(!l_expr(l_pTopLevel) ) + { + TS_FAIL("CTM of class sys && type sys && model power8 should " + "have matched system"); + } + + l_expr.Not(); + + if(l_expr(l_pTopLevel) ) + { + TS_FAIL("CTM of class sys && type sys && model power8 should " + "npt have matched system after negation"); + } + + l_expr.push(&l_sysClass); + l_expr.Or(); + + if(!l_expr(l_pTopLevel) ) + { + TS_FAIL("CTM of class sys && type sys && model power8 should " + "have matched system after negation then || sys class"); + } + + PredicatePostfixExpr* l_pExpr = new PredicatePostfixExpr; + l_pExpr->push(&l_sysClass).push(&l_sysType).And(); + l_pExpr->push(&l_power8Model).And(); + delete (static_cast<PredicateBase*>(l_pExpr)); + + #if 0 + PredicatePostfixExpr l_lhs; + PredicatePostfixExpr l_rhs; + + l_lhs = l_rhs; + + PredicatePostfixExpr l_cpCtor(l_rhs); + #endif + + + TS_TRACE(EXIT_MRK "testPredicatePostfixExpr" ); + } + + void testTargetIterator() + { + TS_TRACE(ENTER_MRK "testTargetIterator"); + + using namespace TARGETING; + TargetService& l_targetService = targetService(); + + + TargetIterator l_pIt; + if( l_pIt != l_targetService.end() ) + { + TS_FAIL("Default TargetIterator should point to past the end " + "of container"); + } + + ++l_pIt; + if( l_pIt != l_targetService.end() ) + { + TS_FAIL("Default TargetIterator preincremented should point to " + "past the end of container"); + } + + TargetIterator* l_pItNew = new TargetIterator; + delete l_pItNew; + l_pItNew = NULL; + + if(*l_pIt != NULL) + { + TS_FAIL("Default TargetIterator dereference should return NULL"); + } + + // Get top level (system) target to verify at least 1 target + Target* l_pTopLevel = NULL; + (void) l_targetService.getTopLevelTarget(l_pTopLevel); + if (l_pTopLevel == NULL) + { + TS_FAIL("Top level handle was NULL when initialization " + "complete"); + } + + l_pIt = l_targetService.begin(); + if((*l_pIt) == NULL) + { + TS_FAIL("TargetService begin() should return !NULL"); + } + + CLASS l_class = CLASS_NA; + if( !l_pIt->tryGetAttr<ATTR_CLASS>(l_class) ) + { + TS_FAIL("Failed to get expected class attribute"); + } + + TargetIterator l_rhs = l_targetService.begin(); + if( ! (l_pIt == l_rhs) ) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + l_rhs = l_targetService.begin(); + if( l_pIt != l_rhs ) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + TargetIterator l_rhs2 = l_targetService.begin(); + ++l_rhs2; + ++l_pIt; + if( l_pIt != l_rhs2 ) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + l_rhs2++; + l_pIt++; + if( l_pIt != l_rhs2 ) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + TargetIterator l_pItClone(l_rhs2); + if( l_pIt != l_pItClone) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + if(l_pIt != l_pItClone++) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + if( (++l_pIt) != l_pItClone) + { + TS_FAIL("Iterators should be equal, but aren't"); + } + + const TargetService& l_constTargetService = targetService(); + + ConstTargetIterator l_pConstIt; + if( l_pConstIt != l_constTargetService.end() ) + { + TS_FAIL("Default ConstTargetIterator should point to past the " + "end of container"); + } + + l_pConstIt = l_constTargetService.begin(); + if( (*l_pConstIt) == NULL) + { + TS_FAIL("Iterator does not point to valid Target as expected"); + } + + TS_TRACE(EXIT_MRK "testTargetIterator" ); + } + + void testRangeFilter(void) + { + TS_TRACE(ENTER_MRK "testRangeFilters" ); + + using namespace TARGETING; + + TargetRangeFilter* l_pRangeFilter = new TargetRangeFilter( + targetService().begin(), + targetService().end(), + NULL); + delete l_pRangeFilter; + l_pRangeFilter = NULL; + + + TargetRangeFilter l_f1( + targetService().begin(), + targetService().end(), + NULL); + + Target* l_pBegin = (*l_f1); + ++l_f1; + Target* l_pNext = (*l_f1); + if( (l_pBegin == NULL) + || (l_pNext == NULL) + || (l_pBegin == l_pNext) + ) + { + TS_FAIL("Target* pointed to by Begin/next NULL -or- begin ==" + "next"); + } + + l_f1.reset(); + if( *l_f1 != l_pBegin ) + { + TS_FAIL("Target* after reset should be equal to original"); + } + + l_f1.reset(); + TargetRangeFilter l_f2 = l_f1; + PredicateCTM l_ctm(CLASS_SYS,TYPE_CORE); // Nonsense CTM + l_f1.setPredicate(&l_ctm); + if( *l_f1 == l_pBegin ) + { + TS_FAIL("Target* after reset and change of predicate should be" + "different than the original"); + } + + PredicateCTM l_ctm1(CLASS_CHIP,TYPE_PROC); + + TargetRangeFilter l_f3( + targetService().begin(), + targetService().end(), + &l_ctm1); + for(;l_f3;++l_f3) + { + if(l_f3->getAttr<ATTR_TYPE>() != TYPE_PROC) + { + TS_FAIL("Should only have returned type proc"); + break; + } + } + + TargetIterator l_pIt = targetService().begin(); + ++l_pIt; + ++l_pIt; + + if(l_pIt == targetService().end()) + { + TS_FAIL("Not enough elements for test"); + } + + TargetRangeFilter l_partial( + targetService().begin(), + l_pIt, + NULL); + int i=0; + + for(; l_partial; ++l_partial) + { + i++; + } + + if(i != 2) + { + TS_FAIL("Should have gotten 2 elements %d",i); + } + + TS_TRACE(EXIT_MRK "testRangeFilter" ); + } + + void testComplexFilter(void) + { + TS_TRACE(ENTER_MRK "testComplexFilter" ); + + using namespace TARGETING; + + TargetService& l_targetService = targetService(); + + TargetRangeFilter f(l_targetService.begin(), + l_targetService.end(), + NULL); + int l_count = 0; + for(; f; ++f, l_count++) + { + } + + TS_TRACE(INF_MRK "Found %d total targets", l_count); + + PredicateCTM l_procs(CLASS_CHIP); + PredicateCTM l_enclosures(CLASS_ENC); + PredicatePostfixExpr l_query; + l_query.push(&l_procs).push(&l_enclosures).Or(); + + f.setPredicate(&l_query); + f.reset(); + + l_count = 0; + for(; f; ++f, ++l_count) + { + EntityPath l_path = f->getAttr<ATTR_PHYS_PATH>(); + l_path.dump(); + } + + TS_TRACE(INF_MRK "Found %d targets that are chips or enclosures ", + l_count); + + l_query.Not(); + f.reset(); + + l_count = 0; + for(; f; ++f, ++l_count) + { + } + + TS_TRACE(INF_MRK "Found %d targets that are not chips or " + "enclosures",l_count); + + Target* l_pMasterProcChipTargetHandle = NULL; + (void) l_targetService.masterProcChipTargetHandle( + l_pMasterProcChipTargetHandle); + if(l_pMasterProcChipTargetHandle == NULL) + { + TS_FAIL("Master processor chip target not found"); + } + + PredicateCTM l_ex(CLASS_UNIT,TYPE_EX); + PredicateCTM l_mba(CLASS_UNIT,TYPE_MBA); + PredicatePostfixExpr l_procquery; + l_procquery.push(&l_ex).push(&l_mba).Or(); + + TargetHandleList l_list; + (void) targetService().getAssociated( + l_list, + l_pMasterProcChipTargetHandle, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_procquery); + + l_count = 0; + for(uint32_t i=0; i<l_list.size(); ++i, ++l_count) + { + EntityPath l_path = l_list[i]->getAttr<ATTR_PHYS_PATH>(); + l_path.dump(); + } + + TS_TRACE(INF_MRK "Found %d targets that are ex/mba units off " + "master processor",l_count); + + TS_TRACE(EXIT_MRK "testComplexFilter" ); + } }; #endif // End __TESTTARGETING_H diff --git a/src/usr/targeting/trace.H b/src/usr/targeting/trace.H index d16ef8ece..e7ffe0365 100644 --- a/src/usr/targeting/trace.H +++ b/src/usr/targeting/trace.H @@ -22,6 +22,8 @@ namespace TARGETING extern trace_desc_t* g_trac_targeting; } +#define TARG_LOC TARG_NAMESPACE TARG_CLASS TARG_FN ": " + #define TARG_TAG "[TARG]" #define TARG_ENTER(args...) \ TRACFCOMP(TARGETING::g_trac_targeting,TARG_TAG " " ENTER_MRK " " TARG_NAMESPACE \ |