Files
libsst/Lib/Include/CML/vector/vector_comparison.h
2026-04-03 00:22:39 -05:00

237 lines
9.0 KiB
C++

/* -*- C++ -*- ------------------------------------------------------------
Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
The Configurable Math Library (CML) is distributed under the terms of the
Boost Software License, v1.0 (see cml/LICENSE for details).
*-----------------------------------------------------------------------*/
/** @file
* @brief
*/
#ifndef vector_comparison_h
#define vector_comparison_h
#include <cml/core/cml_assert.h>
#include <cml/et/size_checking.h>
#include <cml/et/scalar_ops.h>
/* This is used below to create a more meaningful compile-time error when
* vector_comparison is not provided with vector or VectorExpr arguments:
*/
struct vector_comparison_expects_vector_args_error;
#define CML_VEC_VEC_ORDER(_order_, _op_, _OpT_) \
template<typename E1, class AT1, typename E2, class AT2> \
inline bool \
_op_ ( \
const vector<E1,AT1>& left, \
const vector<E2,AT2>& right) \
{ \
return detail::vector_##_order_ (left, right, _OpT_ <E1,E2>()); \
}
#define CML_VEC_VECXPR_ORDER(_order_, _op_, _OpT_) \
template<typename E, class AT, class XprT> \
inline bool \
_op_ ( \
const vector<E,AT>& left, \
VECXPR_ARG_TYPE right) \
{ \
return detail::vector_##_order_ (left, right, \
_OpT_ <E, typename XprT::value_type>()); \
}
#define CML_VECXPR_VEC_ORDER(_order_, _op_, _OpT_) \
template<class XprT, typename E, class AT> \
inline bool \
_op_ ( \
VECXPR_ARG_TYPE left, \
const vector<E,AT>& right) \
{ \
return detail::vector_##_order_ (left, right, \
_OpT_ <typename XprT::value_type, E>()); \
}
#define CML_VECXPR_VECXPR_ORDER(_order_, _op_, _OpT_) \
template<class XprT1, class XprT2> \
inline bool \
_op_ ( \
VECXPR_ARG_TYPE_N(1) left, \
VECXPR_ARG_TYPE_N(2) right) \
{ \
return detail::vector_##_order_ (left, right, \
_OpT_ < \
typename XprT1::value_type, \
typename XprT2::value_type>()); \
}
namespace cml {
namespace detail {
/** Vector strict weak ordering relationship.
*
* OpT must implement a strict weak order on the vector element type.
* operator< and operator> on integer and floating-point types are
* examples.
*/
template<typename LeftT, typename RightT, typename OpT>
inline bool
vector_weak_order(const LeftT& left, const RightT& right, OpT)
{
/* Shorthand: */
typedef et::ExprTraits<LeftT> left_traits;
typedef et::ExprTraits<RightT> right_traits;
/* vector_comparison() requires vector expressions: */
CML_STATIC_REQUIRE_M(
(et::VectorExpressions<LeftT,RightT>::is_true),
vector_comparison_expects_vector_args_error);
/* Note: parens are required here so that the preprocessor ignores the
* commas:
*/
typedef typename et::VectorPromote<
typename left_traits::result_type,
typename right_traits::result_type
>::type result_type;
typedef typename result_type::size_tag size_tag;
/* Verify expression size: */
ssize_t N = (ssize_t) et::CheckedSize(left,right,size_tag());
for(ssize_t i = 0; i < N; ++ i) {
if(OpT().apply(
left_traits().get(left,i),
right_traits().get(right,i)
))
{
/* If weak order (a < b) is satisfied, return true: */
return true;
} else if(OpT().apply(
right_traits().get(right,i),
left_traits().get(left,i)
))
{
/* If !(b < a), then return false: */
return false;
} else {
/* Have !(a < b) && !(b < a) <=> (a >= b && b >= a) <=> (a == b).
* so need to test next element:
*/
continue;
}
}
/* XXX Can this be unrolled in any reasonable way? */
/* If we get here, then left == right: */
return false;
}
/** Vector total order relationship.
*
* OpT must implement a total order on the vector element type. operator<=
* and operator>= on integer and floating-point types are examples.
*/
template<typename LeftT, typename RightT, typename OpT>
inline bool
vector_total_order(const LeftT& left, const RightT& right, OpT)
{
/* Shorthand: */
typedef et::ExprTraits<LeftT> left_traits;
typedef et::ExprTraits<RightT> right_traits;
/* vector_comparison() requires vector expressions: */
CML_STATIC_REQUIRE_M(
(et::VectorExpressions<LeftT,RightT>::is_true),
vector_comparison_expects_vector_args_error);
/* Note: parens are required here so that the preprocessor ignores the
* commas:
*/
typedef typename et::VectorPromote<
typename left_traits::result_type,
typename right_traits::result_type
>::type result_type;
typedef typename result_type::size_tag size_tag;
/* Verify expression size: */
ssize_t N = (ssize_t) et::CheckedSize(left,right,size_tag());
for(ssize_t i = 0; i < N; ++ i) {
/* Test total order: */
if(OpT().apply(
left_traits().get(left,i),
right_traits().get(right,i)
))
{
/* Automatically true if weak order (a <= b) && !(b <= a) <=>
* (a <= b) && (b > a) <=> (a < b) is satisfied:
*/
if(!OpT().apply(
right_traits().get(right,i),
left_traits().get(left,i)
))
return true;
/* Otherwise, have equality (a <= b) && (b <= a), so continue
* to next element:
*/
else
continue;
} else {
/* Total order isn't satisfied (a > b), so return false: */
return false;
}
}
/* XXX Can this be unrolled in any reasonable way? */
/* Total (==) or weak (<) order was satisfied, so return true: */
return true;
}
}
/* XXX There is a better way to handle these with operator traits... */
CML_VEC_VEC_ORDER( total_order, operator==, et::OpEqual)
CML_VECXPR_VEC_ORDER( total_order, operator==, et::OpEqual)
CML_VEC_VECXPR_ORDER( total_order, operator==, et::OpEqual)
CML_VECXPR_VECXPR_ORDER( total_order, operator==, et::OpEqual)
CML_VEC_VEC_ORDER( weak_order, operator!=, et::OpNotEqual)
CML_VECXPR_VEC_ORDER( weak_order, operator!=, et::OpNotEqual)
CML_VEC_VECXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
CML_VECXPR_VECXPR_ORDER( weak_order, operator!=, et::OpNotEqual)
CML_VEC_VEC_ORDER( weak_order, operator<, et::OpLess)
CML_VECXPR_VEC_ORDER( weak_order, operator<, et::OpLess)
CML_VEC_VECXPR_ORDER( weak_order, operator<, et::OpLess)
CML_VECXPR_VECXPR_ORDER( weak_order, operator<, et::OpLess)
CML_VEC_VEC_ORDER( weak_order, operator>, et::OpGreater)
CML_VECXPR_VEC_ORDER( weak_order, operator>, et::OpGreater)
CML_VEC_VECXPR_ORDER( weak_order, operator>, et::OpGreater)
CML_VECXPR_VECXPR_ORDER( weak_order, operator>, et::OpGreater)
CML_VEC_VEC_ORDER( total_order, operator<=, et::OpLessEqual)
CML_VECXPR_VEC_ORDER( total_order, operator<=, et::OpLessEqual)
CML_VEC_VECXPR_ORDER( total_order, operator<=, et::OpLessEqual)
CML_VECXPR_VECXPR_ORDER( total_order, operator<=, et::OpLessEqual)
CML_VEC_VEC_ORDER( total_order, operator>=, et::OpGreaterEqual)
CML_VECXPR_VEC_ORDER( total_order, operator>=, et::OpGreaterEqual)
CML_VEC_VECXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
CML_VECXPR_VECXPR_ORDER( total_order, operator>=, et::OpGreaterEqual)
} // namespace cml
#endif
// -------------------------------------------------------------------------
// vim:ft=cpp