Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:40

0001 //  (C) Copyright Gennadiy Rozental 2001.
0002 //  Distributed under the Boost Software License, Version 1.0.
0003 //  (See accompanying file LICENSE_1_0.txt or copy at
0004 //  http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 //  See http://www.boost.org/libs/test for the library home page.
0007 //
0008 //!@file
0009 //!@brief Collection comparison with enhanced reporting
0010 // ***************************************************************************
0011 
0012 #ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
0013 #define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
0014 
0015 // Boost.Test
0016 #include <boost/test/tools/assertion.hpp>
0017 
0018 #include <boost/test/utils/is_forward_iterable.hpp>
0019 #include <boost/test/utils/is_cstring.hpp>
0020 
0021 // Boost
0022 #include <boost/mpl/bool.hpp>
0023 #include <boost/mpl/if.hpp>
0024 #include <boost/utility/enable_if.hpp>
0025 #include <boost/type_traits/decay.hpp>
0026 
0027 #include <boost/test/detail/suppress_warnings.hpp>
0028 
0029 //____________________________________________________________________________//
0030 
0031 namespace boost {
0032 namespace test_tools {
0033 namespace assertion {
0034 
0035 // ************************************************************************** //
0036 // ************* selectors for specialized comparizon routines ************** //
0037 // ************************************************************************** //
0038 
0039 template<typename T>
0040 struct specialized_compare : public mpl::false_ {};
0041 
0042 template <typename T>
0043 struct is_c_array : public mpl::false_ {};
0044 
0045 template<typename T, std::size_t N>
0046 struct is_c_array<T [N]> : public mpl::true_ {};
0047 
0048 template<typename T, std::size_t N>
0049 struct is_c_array<T (&)[N]> : public mpl::true_ {};
0050 
0051 #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col)          \
0052 namespace boost { namespace test_tools { namespace assertion {  \
0053 template<>                                                      \
0054 struct specialized_compare<Col> : public mpl::true_ {};         \
0055 }}}                                                             \
0056 /**/
0057 
0058 // ************************************************************************** //
0059 // **************            lexicographic_compare             ************** //
0060 // ************************************************************************** //
0061 
0062 namespace op {
0063 
0064 template <typename OP, bool can_be_equal, bool prefer_shorter,
0065           typename Lhs, typename Rhs>
0066 inline
0067 typename boost::enable_if_c<
0068        unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
0069     && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
0070     assertion_result>::type
0071 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0072 {
0073     assertion_result ar( true );
0074 
0075     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0076     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0077 
0078     typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs);
0079     typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs);
0080     typename t_Lhs_iterator::const_iterator last1  = t_Lhs_iterator::end(lhs);
0081     typename t_Rhs_iterator::const_iterator last2  = t_Rhs_iterator::end(rhs);
0082     std::size_t                             pos    = 0;
0083 
0084     for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
0085         assertion_result const& element_ar = OP::eval(*first1, *first2);
0086         if( !can_be_equal && element_ar )
0087             return ar; // a < b
0088 
0089         assertion_result const& reverse_ar = OP::eval(*first2, *first1);
0090         if( element_ar && !reverse_ar )
0091             return ar; // a<=b and !(b<=a) => a < b => return true
0092 
0093         if( element_ar || !reverse_ar ) {
0094             continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
0095         }
0096 
0097         // !(a<=b) and b<=a => b < a => return false
0098         ar = false;
0099         ar.message() << "\nFailure at position " << pos << ":";
0100         ar.message() << "\n  - condition [" << tt_detail::print_helper(*first1) << OP::forward() << tt_detail::print_helper(*first2) << "] is false";
0101         if(!element_ar.has_empty_message())
0102             ar.message() << ": " << element_ar.message();
0103         ar.message() << "\n  - inverse condition [" << tt_detail::print_helper(*first2) << OP::forward() << tt_detail::print_helper(*first1) << "] is true";
0104         if(!reverse_ar.has_empty_message())
0105             ar.message() << ": " << reverse_ar.message();
0106         return ar;
0107     }
0108 
0109     if( first1 != last1 ) {
0110         if( prefer_shorter ) {
0111             ar = false;
0112             ar.message() << "\nFirst collection has extra trailing elements.";
0113         }
0114     }
0115     else if( first2 != last2 ) {
0116         if( !prefer_shorter ) {
0117             ar = false;
0118             ar.message() << "\nSecond collection has extra trailing elements.";
0119         }
0120     }
0121     else if( !can_be_equal ) {
0122         ar = false;
0123         ar.message() << "\nCollections appear to be equal.";
0124     }
0125 
0126     return ar;
0127 }
0128 
0129 template <typename OP, bool can_be_equal, bool prefer_shorter,
0130           typename Lhs, typename Rhs>
0131 inline
0132 typename boost::enable_if_c<
0133     (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
0134     assertion_result>::type
0135 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0136 {
0137     typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
0138     typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
0139 
0140     return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
0141         lhs_char_type(lhs),
0142         rhs_char_type(rhs));
0143 }
0144 
0145 //____________________________________________________________________________//
0146 
0147 // ************************************************************************** //
0148 // **************               equality_compare               ************** //
0149 // ************************************************************************** //
0150 
0151 template <typename OP, typename Lhs, typename Rhs>
0152 inline
0153 typename boost::enable_if_c<
0154        unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
0155     && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
0156     assertion_result>::type
0157 element_compare( Lhs const& lhs, Rhs const& rhs )
0158 {
0159     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0160     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0161 
0162     assertion_result ar( true );
0163 
0164     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
0165         ar = false;
0166         ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
0167         return ar;
0168     }
0169 
0170     typename t_Lhs_iterator::const_iterator left  = t_Lhs_iterator::begin(lhs);
0171     typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
0172     std::size_t                             pos   = 0;
0173 
0174     for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
0175         assertion_result const element_ar = OP::eval( *left, *right );
0176         if( element_ar )
0177             continue;
0178 
0179         ar = false;
0180         ar.message() << "\n  - mismatch at position " << pos << ": ["
0181                      << tt_detail::print_helper(*left)
0182                      << OP::forward()
0183                      << tt_detail::print_helper(*right)
0184                      << "] is false";
0185         if(!element_ar.has_empty_message())
0186             ar.message() << ": " << element_ar.message();
0187     }
0188 
0189     return ar;
0190 }
0191 
0192 // In case string comparison is branching here
0193 template <typename OP, typename Lhs, typename Rhs>
0194 inline
0195 typename boost::enable_if_c<
0196     (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
0197     assertion_result>::type
0198 element_compare( Lhs const& lhs, Rhs const& rhs )
0199 {
0200     typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
0201     typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
0202 
0203     return element_compare<OP>(lhs_char_type(lhs),
0204                                rhs_char_type(rhs));
0205 }
0206 
0207 //____________________________________________________________________________//
0208 
0209 // ************************************************************************** //
0210 // **************             non_equality_compare             ************** //
0211 // ************************************************************************** //
0212 
0213 template <typename OP, typename Lhs, typename Rhs>
0214 inline assertion_result
0215 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
0216 {
0217     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0218     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0219 
0220     assertion_result ar( true );
0221 
0222     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
0223         return ar;
0224 
0225     typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
0226     typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
0227     typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
0228 
0229     for( ; left != end; ++left, ++right ) {
0230         if( OP::eval( *left, *right ) )
0231             return ar;
0232     }
0233 
0234     ar = false;
0235     ar.message() << "\nCollections appear to be equal";
0236 
0237     return ar;
0238 }
0239 
0240 //____________________________________________________________________________//
0241 
0242 // ************************************************************************** //
0243 // **************                   cctraits                   ************** //
0244 // ************************************************************************** //
0245 // set of collection comparison traits per comparison OP
0246 
0247 template<typename OP>
0248 struct cctraits;
0249 
0250 template<typename Lhs, typename Rhs>
0251 struct cctraits<op::EQ<Lhs, Rhs> > {
0252     typedef specialized_compare<Lhs> is_specialized;
0253 };
0254 
0255 template<typename Lhs, typename Rhs>
0256 struct cctraits<op::NE<Lhs, Rhs> > {
0257     typedef specialized_compare<Lhs> is_specialized;
0258 };
0259 
0260 template<typename Lhs, typename Rhs>
0261 struct cctraits<op::LT<Lhs, Rhs> > {
0262     static const bool can_be_equal = false;
0263     static const bool prefer_short = true;
0264 
0265     typedef specialized_compare<Lhs> is_specialized;
0266 };
0267 
0268 template<typename Lhs, typename Rhs>
0269 struct cctraits<op::LE<Lhs, Rhs> > {
0270     static const bool can_be_equal = true;
0271     static const bool prefer_short = true;
0272 
0273     typedef specialized_compare<Lhs> is_specialized;
0274 };
0275 
0276 template<typename Lhs, typename Rhs>
0277 struct cctraits<op::GT<Lhs, Rhs> > {
0278     static const bool can_be_equal = false;
0279     static const bool prefer_short = false;
0280 
0281     typedef specialized_compare<Lhs> is_specialized;
0282 };
0283 
0284 template<typename Lhs, typename Rhs>
0285 struct cctraits<op::GE<Lhs, Rhs> > {
0286     static const bool can_be_equal = true;
0287     static const bool prefer_short = false;
0288 
0289     typedef specialized_compare<Lhs> is_specialized;
0290 };
0291 
0292 // ************************************************************************** //
0293 // **************              compare_collections             ************** //
0294 // ************************************************************************** //
0295 // Overloaded set of functions dispatching to specific implementation of comparison
0296 
0297 template <typename Lhs, typename Rhs, typename L, typename R>
0298 inline assertion_result
0299 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
0300 {
0301     return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
0302 }
0303 
0304 //____________________________________________________________________________//
0305 
0306 template <typename Lhs, typename Rhs, typename L, typename R>
0307 inline assertion_result
0308 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
0309 {
0310     return lhs == rhs;
0311 }
0312 
0313 //____________________________________________________________________________//
0314 
0315 template <typename Lhs, typename Rhs, typename L, typename R>
0316 inline assertion_result
0317 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
0318 {
0319     return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
0320 }
0321 
0322 //____________________________________________________________________________//
0323 
0324 template <typename Lhs, typename Rhs, typename L, typename R>
0325 inline assertion_result
0326 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
0327 {
0328     return lhs != rhs;
0329 }
0330 
0331 //____________________________________________________________________________//
0332 
0333 template <typename OP, typename Lhs, typename Rhs>
0334 inline assertion_result
0335 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0336 {
0337     return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
0338 }
0339 
0340 //____________________________________________________________________________//
0341 
0342 template <typename Lhs, typename Rhs, typename OP>
0343 inline assertion_result
0344 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
0345 {
0346     return lexicographic_compare<OP>( lhs, rhs );
0347 }
0348 
0349 //____________________________________________________________________________//
0350 
0351 template <typename Lhs, typename Rhs, typename L, typename R>
0352 inline assertion_result
0353 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
0354 {
0355     return lhs < rhs;
0356 }
0357 
0358 //____________________________________________________________________________//
0359 
0360 template <typename Lhs, typename Rhs, typename L, typename R>
0361 inline assertion_result
0362 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
0363 {
0364     return lhs <= rhs;
0365 }
0366 
0367 //____________________________________________________________________________//
0368 
0369 template <typename Lhs, typename Rhs, typename L, typename R>
0370 inline assertion_result
0371 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
0372 {
0373     return lhs > rhs;
0374 }
0375 
0376 //____________________________________________________________________________//
0377 
0378 template <typename Lhs, typename Rhs, typename L, typename R>
0379 inline assertion_result
0380 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
0381 {
0382     return lhs >= rhs;
0383 }
0384 
0385 //____________________________________________________________________________//
0386 
0387 // ************************************************************************** //
0388 // ********* specialization of comparison operators for collections ********* //
0389 // ************************************************************************** //
0390 
0391 #define DEFINE_COLLECTION_COMPARISON( oper, name, rev, name_inverse ) \
0392 template<typename Lhs,typename Rhs>                                 \
0393 struct name<Lhs,Rhs,typename boost::enable_if_c<                    \
0394     unit_test::is_forward_iterable<Lhs>::value                      \
0395     &&   !unit_test::is_cstring_comparable<Lhs>::value              \
0396     && unit_test::is_forward_iterable<Rhs>::value                   \
0397     &&   !unit_test::is_cstring_comparable<Rhs>::value>::type> {    \
0398 public:                                                             \
0399     typedef assertion_result result_type;                           \
0400     typedef name_inverse<Lhs, Rhs> inverse;                         \
0401     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
0402     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
0403                                                                     \
0404     typedef name<Lhs, Rhs> OP;                                      \
0405                                                                     \
0406     typedef typename                                                \
0407         mpl::if_c<                                                  \
0408           mpl::or_<                                                 \
0409               typename is_c_array<Lhs>::type,                       \
0410               typename is_c_array<Rhs>::type                        \
0411           >::value,                                                 \
0412           mpl::true_,                                               \
0413           typename                                                  \
0414               mpl::if_c<is_same<typename decay<Lhs>::type,          \
0415                                 typename decay<Rhs>::type>::value,  \
0416                         typename cctraits<OP>::is_specialized,      \
0417                         mpl::false_>::type                          \
0418           >::type is_specialized;                                   \
0419                                                                     \
0420     typedef name<typename t_Lhs_iterator_helper::value_type,        \
0421                  typename t_Rhs_iterator_helper::value_type         \
0422                  > elem_op;                                         \
0423                                                                     \
0424     static assertion_result                                         \
0425     eval( Lhs const& lhs, Rhs const& rhs)                           \
0426     {                                                               \
0427         return assertion::op::compare_collections( lhs, rhs,        \
0428             (boost::type<elem_op>*)0,                               \
0429             is_specialized() );                                     \
0430     }                                                               \
0431                                                                     \
0432     template<typename PrevExprType>                                 \
0433     static void                                                     \
0434     report( std::ostream&,                                          \
0435             PrevExprType const&,                                    \
0436             Rhs const& ) {}                                         \
0437                                                                     \
0438     static char const* forward()                                    \
0439     { return " " #oper " "; }                                       \
0440     static char const* revert()                                     \
0441     { return " " #rev " "; }                                        \
0442                                                                     \
0443 };                                                                  \
0444 /**/
0445 
0446 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
0447 #undef DEFINE_COLLECTION_COMPARISON
0448 
0449 //____________________________________________________________________________//
0450 
0451 } // namespace op
0452 } // namespace assertion
0453 } // namespace test_tools
0454 } // namespace boost
0455 
0456 #include <boost/test/detail/enable_warnings.hpp>
0457 
0458 #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER