changes from Daryle Walker

[SVN r10264]
This commit is contained in:
Dave Abrahams 2001-06-04 11:57:37 +00:00
parent dd3cfe1837
commit b7c8e0c17f
4 changed files with 1921 additions and 877 deletions

View File

@ -1,20 +1,20 @@
// Boost operators.hpp header file ----------------------------------------// // Boost operators.hpp header file ----------------------------------------//
// (C) Copyright David Abrahams 1999. Permission to copy, use, // (C) Copyright David Abrahams, Jeremy Siek, and Daryle Walker 1999-2001.
// modify, sell and distribute this software is granted provided this // Permission to copy, use, modify, sell and distribute this software is
// copyright notice appears in all copies. This software is provided // granted provided this copyright notice appears in all copies. This
// "as is" without express or implied warranty, and with no claim as // software is provided "as is" without express or implied warranty, and
// to its suitability for any purpose. // with no claim as to its suitability for any purpose.
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation. // See http://www.boost.org for most recent version including documentation.
// Revision History // Revision History
// 29 May 01 Added operator classes for << and >>. Added input and output
// iterator helper classes. Added classes to connect equality and
// relational operators. Added classes for groups of related
// operators. Reimplemented example operator and iterator helper
// classes in terms of the new groups. (Daryle Walker, with help
// from Alexy Gurtovoy)
// 11 Feb 01 Fixed bugs in the iterator helpers which prevented explicitly // 11 Feb 01 Fixed bugs in the iterator helpers which prevented explicitly
// supplied arguments from actually being used (Dave Abrahams) // supplied arguments from actually being used (Dave Abrahams)
// 04 Jul 00 Fixed NO_OPERATORS_IN_NAMESPACE bugs, major cleanup and // 04 Jul 00 Fixed NO_OPERATORS_IN_NAMESPACE bugs, major cleanup and
@ -282,12 +282,190 @@ struct indexable : B
} }
}; };
// More operator classes (contributed by Daryle Walker) --------------------//
template <class T, class U, class B = ::boost::detail::empty_base>
struct left_shiftable2 : B
{
friend T operator<<(T x, const U& y) { return x <<= y; }
};
template <class T, class B = ::boost::detail::empty_base>
struct left_shiftable1 : B
{
friend T operator<<(T x, const T& y) { return x <<= y; }
};
template <class T, class U, class B = ::boost::detail::empty_base>
struct right_shiftable2 : B
{
friend T operator>>(T x, const U& y) { return x >>= y; }
};
template <class T, class B = ::boost::detail::empty_base>
struct right_shiftable1 : B
{
friend T operator>>(T x, const T& y) { return x >>= y; }
};
template <class T, class U, class B = ::boost::detail::empty_base>
struct equivalent2 : B
{
friend bool operator==(const T& x, const U& y)
{
return !(x < y) && !(x > y);
}
};
template <class T, class B = ::boost::detail::empty_base>
struct equivalent1 : B
{
friend bool operator==(const T&x, const T&y)
{
return !(x < y) && !(y < x);
}
};
template <class T, class U, class B = ::boost::detail::empty_base>
struct partially_ordered2 : B
{
friend bool operator<=(const T& x, const U& y)
{ return (x < y) || (x == y); }
friend bool operator>=(const T& x, const U& y)
{ return (x > y) || (x == y); }
friend bool operator>(const U& x, const T& y)
{ return y < x; }
friend bool operator<(const U& x, const T& y)
{ return y > x; }
friend bool operator<=(const U& x, const T& y)
{ return (y > x) || (y == x); }
friend bool operator>=(const U& x, const T& y)
{ return (y < x) || (y == x); }
};
template <class T, class B = ::boost::detail::empty_base>
struct partially_ordered1 : B
{
friend bool operator>(const T& x, const T& y)
{ return y < x; }
friend bool operator<=(const T& x, const T& y)
{ return (x < y) || (x == y); }
friend bool operator>=(const T& x, const T& y)
{ return (y < x) || (x == y); }
};
// Combined operator classes (contributed by Daryle Walker) ----------------//
template <class T, class U, class B = ::boost::detail::empty_base>
struct totally_ordered2
: less_than_comparable2<T, U
, equality_comparable2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct totally_ordered1
: less_than_comparable1<T
, equality_comparable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct additive2
: addable2<T, U
, subtractable2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct additive1
: addable1<T
, subtractable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct multiplicative2
: multipliable2<T, U
, dividable2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct multiplicative1
: multipliable1<T
, dividable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct integer_multiplicative2
: multiplicative2<T, U
, modable2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct integer_multiplicative1
: multiplicative1<T
, modable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct arithmetic2
: additive2<T, U
, multiplicative2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct arithmetic1
: additive1<T
, multiplicative1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct integer_arithmetic2
: additive2<T, U
, integer_multiplicative2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct integer_arithmetic1
: additive1<T
, integer_multiplicative1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct bitwise2
: xorable2<T, U
, andable2<T, U
, orable2<T, U, B
> > > {};
template <class T, class B = ::boost::detail::empty_base>
struct bitwise1
: xorable1<T
, andable1<T
, orable1<T, B
> > > {};
template <class T, class B = ::boost::detail::empty_base>
struct unit_steppable
: incrementable<T
, decrementable<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct shiftable2
: left_shiftable2<T, U
, right_shiftable2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct shiftable1
: left_shiftable1<T
, right_shiftable1<T, B
> > {};
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
} // namespace boost } // namespace boost
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE #endif // BOOST_NO_OPERATORS_IN_NAMESPACE
// BOOST_IMPORT_TEMPLATE1/BOOST_IMPORT_TEMPLATE2 - // BOOST_IMPORT_TEMPLATE1 .. BOOST_IMPORT_TEMPLATE3 -
// //
// When BOOST_NO_OPERATORS_IN_NAMESPACE is defined we need a way to import an // When BOOST_NO_OPERATORS_IN_NAMESPACE is defined we need a way to import an
// operator template into the boost namespace. BOOST_IMPORT_TEMPLATE1 is used // operator template into the boost namespace. BOOST_IMPORT_TEMPLATE1 is used
@ -295,12 +473,31 @@ struct indexable : B
// two-argument forms. Note that these macros expect to be invoked from within // two-argument forms. Note that these macros expect to be invoked from within
// boost. // boost.
#if defined(BOOST_NO_OPERATORS_IN_NAMESPACE) #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
# if defined(BOOST_NO_USING_TEMPLATE) // The template is already in boost so we have nothing to do.
# define BOOST_IMPORT_TEMPLATE3(template_name)
# define BOOST_IMPORT_TEMPLATE2(template_name)
# define BOOST_IMPORT_TEMPLATE1(template_name)
#else // BOOST_NO_OPERATORS_IN_NAMESPACE
# ifndef BOOST_NO_USING_TEMPLATE
// Bring the names in with a using-declaration
// to avoid stressing the compiler.
# define BOOST_IMPORT_TEMPLATE3(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name;
# else
// Otherwise, because a Borland C++ 5.5 bug prevents a using declaration
// from working, we are forced to use inheritance for that compiler.
# define BOOST_IMPORT_TEMPLATE3(template_name) \
template <class T, class U, class V, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, U, V, B> {};
// Because a Borland C++ 5.5 bug prevents a using declaration from working,
// we are forced to use inheritance for that compiler.
# define BOOST_IMPORT_TEMPLATE2(template_name) \ # define BOOST_IMPORT_TEMPLATE2(template_name) \
template <class T, class U, class B = ::boost::detail::empty_base> \ template <class T, class U, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, U, B> {}; struct template_name : ::template_name<T, U, B> {};
@ -309,21 +506,8 @@ struct indexable : B
template <class T, class B = ::boost::detail::empty_base> \ template <class T, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, B> {}; struct template_name : ::template_name<T, B> {};
# else
// Otherwise, bring the names in with a using-declaration to avoid
// stressing the compiler
# define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name;
# endif // BOOST_NO_USING_TEMPLATE # endif // BOOST_NO_USING_TEMPLATE
#else // !BOOST_NO_OPERATORS_IN_NAMESPACE
// The template is already in boost so we have nothing to do.
# define BOOST_IMPORT_TEMPLATE2(template_name)
# define BOOST_IMPORT_TEMPLATE1(template_name)
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE #endif // BOOST_NO_OPERATORS_IN_NAMESPACE
// //
@ -332,7 +516,7 @@ struct indexable : B
// the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as // the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as
// neccessary. // neccessary.
// //
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// is_chained_base<> - a traits class used to distinguish whether an operator // is_chained_base<> - a traits class used to distinguish whether an operator
// template argument is being used for base class chaining, or is specifying a // template argument is being used for base class chaining, or is specifying a
@ -355,6 +539,15 @@ template<class T> struct is_chained_base {
} // namespace boost } // namespace boost
// Import a 3-type-argument operator template into boost (if neccessary) and
// provide a specialization of 'is_chained_base<>' for it.
# define BOOST_OPERATOR_TEMPLATE3(template_name3) \
BOOST_IMPORT_TEMPLATE3(template_name3) \
template<class T, class U, class V, class B> \
struct is_chained_base< ::boost::template_name3<T, U, V, B> > { \
typedef ::boost::detail::true_t value; \
};
// Import a 2-type-argument operator template into boost (if neccessary) and // Import a 2-type-argument operator template into boost (if neccessary) and
// provide a specialization of 'is_chained_base<>' for it. // provide a specialization of 'is_chained_base<>' for it.
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \ # define BOOST_OPERATOR_TEMPLATE2(template_name2) \
@ -414,6 +607,8 @@ BOOST_OPERATOR_TEMPLATE1(template_name##1)
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
# define BOOST_OPERATOR_TEMPLATE3(template_name3) \
BOOST_IMPORT_TEMPLATE3(template_name3)
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \ # define BOOST_OPERATOR_TEMPLATE2(template_name2) \
BOOST_IMPORT_TEMPLATE2(template_name2) BOOST_IMPORT_TEMPLATE2(template_name2)
# define BOOST_OPERATOR_TEMPLATE1(template_name1) \ # define BOOST_OPERATOR_TEMPLATE1(template_name1) \
@ -442,47 +637,41 @@ BOOST_OPERATOR_TEMPLATE(orable)
BOOST_OPERATOR_TEMPLATE1(incrementable) BOOST_OPERATOR_TEMPLATE1(incrementable)
BOOST_OPERATOR_TEMPLATE1(decrementable) BOOST_OPERATOR_TEMPLATE1(decrementable)
BOOST_OPERATOR_TEMPLATE2(dereferenceable) BOOST_OPERATOR_TEMPLATE2(dereferenceable)
BOOST_OPERATOR_TEMPLATE3(indexable)
// indexable doesn't follow the patterns above (it has 4 template arguments), so BOOST_OPERATOR_TEMPLATE(left_shiftable)
// we just write out the compiler hacks explicitly. BOOST_OPERATOR_TEMPLATE(right_shiftable)
#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE BOOST_OPERATOR_TEMPLATE(equivalent)
# ifdef BOOST_NO_USING_TEMPLATE BOOST_OPERATOR_TEMPLATE(partially_ordered)
template <class T, class I, class R, class B = ::boost::detail::empty_base>
struct indexable : ::indexable<T,I,R,B> {};
# else
using ::indexable;
# endif
#endif
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION BOOST_OPERATOR_TEMPLATE(totally_ordered)
template <class T, class I, class R, class B> BOOST_OPERATOR_TEMPLATE(additive)
struct is_chained_base< ::boost::indexable<T, I, R, B> > { BOOST_OPERATOR_TEMPLATE(multiplicative)
typedef ::boost::detail::true_t operator_template_type; BOOST_OPERATOR_TEMPLATE(integer_multiplicative)
}; BOOST_OPERATOR_TEMPLATE(arithmetic)
#endif BOOST_OPERATOR_TEMPLATE(integer_arithmetic)
BOOST_OPERATOR_TEMPLATE(bitwise)
BOOST_OPERATOR_TEMPLATE1(unit_steppable)
BOOST_OPERATOR_TEMPLATE(shiftable)
#undef BOOST_OPERATOR_TEMPLATE #undef BOOST_OPERATOR_TEMPLATE
#undef BOOST_OPERATOR_TEMPLATE3
#undef BOOST_OPERATOR_TEMPLATE2 #undef BOOST_OPERATOR_TEMPLATE2
#undef BOOST_OPERATOR_TEMPLATE1 #undef BOOST_OPERATOR_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE1 #undef BOOST_IMPORT_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE2 #undef BOOST_IMPORT_TEMPLATE2
#undef BOOST_IMPORT_TEMPLATE3
// The following 'operators' classes can only be used portably if the derived class // The following 'operators' classes can only be used portably if the derived class
// declares ALL of the required member operators. // declares ALL of the required member operators.
template <class T, class U> template <class T, class U>
struct operators2 struct operators2
: less_than_comparable2<T,U : totally_ordered2<T,U
, equality_comparable2<T,U , integer_arithmetic2<T,U
, addable2<T,U , bitwise2<T,U
, subtractable2<T,U > > > {};
, multipliable2<T,U
, dividable2<T,U
, modable2<T,U
, orable2<T,U
, andable2<T,U
, xorable2<T,U
> > > > > > > > > > {};
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T, class U = T> template <class T, class U = T>
@ -492,31 +681,47 @@ template <class T> struct operators<T, T>
#else #else
template <class T> struct operators template <class T> struct operators
#endif #endif
: less_than_comparable<T : totally_ordered<T
, equality_comparable<T , integer_arithmetic<T
, addable<T , bitwise<T
, subtractable<T , unit_steppable<T
, multipliable<T > > > > {};
, dividable<T
, modable<T
, orable<T
, andable<T
, xorable<T
, incrementable<T
, decrementable<T
> > > > > > > > > > > > {};
// Iterator helper classes (contributed by Jeremy Siek) -------------------// // Iterator helper classes (contributed by Jeremy Siek) -------------------//
// (Input and output iterator helpers contributed by Daryle Walker) -------//
// (Changed to use combined operator classes by Daryle Walker) ------------//
template <class T,
class V,
class D = std::ptrdiff_t,
class P = V const *,
class R = V const &>
struct input_iterator_helper
: equality_comparable1<T
, incrementable<T
, dereferenceable<T, P
, boost::iterator<std::input_iterator_tag, V, D, P, R
> > > > {};
template <class T,
class V = void,
class D = void,
class P = void,
class R = void>
struct output_iterator_helper
: incrementable<T
, boost::iterator<std::output_iterator_tag, V, D, P, R
> > {};
template <class T, template <class T,
class V, class V,
class D = std::ptrdiff_t, class D = std::ptrdiff_t,
class P = V*, class P = V*,
class R = V&> class R = V&>
struct forward_iterator_helper struct forward_iterator_helper
: equality_comparable<T : equality_comparable1<T
, incrementable<T , incrementable<T
, dereferenceable<T,P , dereferenceable<T, P
, boost::iterator<std::forward_iterator_tag,V,D,P,R , boost::iterator<std::forward_iterator_tag, V, D, P, R
> > > > {}; > > > > {};
template <class T, template <class T,
@ -525,12 +730,11 @@ template <class T,
class P = V*, class P = V*,
class R = V&> class R = V&>
struct bidirectional_iterator_helper struct bidirectional_iterator_helper
: equality_comparable<T : equality_comparable1<T
, incrementable<T , unit_steppable<T
, decrementable<T , dereferenceable<T, P
, dereferenceable<T,P , boost::iterator<std::bidirectional_iterator_tag, V, D, P, R
, boost::iterator<std::bidirectional_iterator_tag,V,D,P,R > > > > {};
> > > > > {};
template <class T, template <class T,
class V, class V,
@ -538,22 +742,17 @@ template <class T,
class P = V*, class P = V*,
class R = V&> class R = V&>
struct random_access_iterator_helper struct random_access_iterator_helper
: equality_comparable<T : totally_ordered1<T
, less_than_comparable<T , unit_steppable<T
, incrementable<T , dereferenceable<T, P
, decrementable<T , additive2<T, D
, dereferenceable<T,P , indexable<T, D, R
, addable2<T,D , boost::iterator<std::random_access_iterator_tag, V, D, P, R
, subtractable2<T,D > > > > > >
, indexable<T,D,R
, boost::iterator<std::random_access_iterator_tag,V,D,P,R
> > > > > > > > >
{ {
#ifndef __BORLANDC__
friend D requires_difference_operator(const T& x, const T& y) { friend D requires_difference_operator(const T& x, const T& y) {
return x - y; return x - y;
} }
#endif
}; // random_access_iterator_helper }; // random_access_iterator_helper
} // namespace boost } // namespace boost

View File

@ -9,16 +9,25 @@
// See http://www.boost.org for most recent version including documentation. // See http://www.boost.org for most recent version including documentation.
// Revision History // Revision History
// 29 May 01 Factored implementation, added comparison tests, use Test Tools
// library (Daryle Walker)
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek) // 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
#include <string> #define BOOST_INCLUDE_MAIN
#include <iostream> #include <boost/test/test_tools.hpp> // for main
using namespace std;
#include <boost/operators.hpp> #include <boost/config.hpp> // for BOOST_STATIC_CONSTANT
using namespace boost; #include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/operators.hpp> // for boost::random_access_iterator_helper
#include <cstddef> // for std::ptrdiff_t, std::size_t
#include <cstring> // for std::strcmp
#include <iostream> // for std::cout (std::endl, ends, and flush indirectly)
#include <string> // for std::string
#include <strstream> // for std::ostrstream
// Iterator test class
template <class T, class R, class P> template <class T, class R, class P>
struct test_iter struct test_iter
: public boost::random_access_iterator_helper< : public boost::random_access_iterator_helper<
@ -29,7 +38,7 @@ struct test_iter
typedef std::ptrdiff_t Distance; typedef std::ptrdiff_t Distance;
public: public:
test_iter(T* i) : _i(i) { } explicit test_iter(T* i =0) : _i(i) { }
test_iter(const self& x) : _i(x._i) { } test_iter(const self& x) : _i(x._i) { }
self& operator=(const self& x) { _i = x._i; return *this; } self& operator=(const self& x) { _i = x._i; return *this; }
Reference operator*() const { return *_i; } Reference operator*() const { return *_i; }
@ -43,127 +52,280 @@ public:
return x._i - y._i; return x._i - y._i;
} }
protected: protected:
T* _i; P _i;
}; };
// Iterator operator testing classes
int class test_opr_base
main()
{ {
string array[] = { "apple", "orange", "pear", "peach", "grape", "plum" }; protected:
{ // Test data and types
test_iter<string,string&,string*> i = array, BOOST_STATIC_CONSTANT( std::size_t, fruit_length = 6u );
ie = array + sizeof(array)/sizeof(string); BOOST_STATIC_CONSTANT( std::size_t, scratch_length = 40u );
// Tests for all of the operators added by random_access_iterator_helper typedef std::string fruit_array_type[ fruit_length ];
typedef char scratch_array_type[ scratch_length ];
// test i++ static fruit_array_type fruit;
while (i != ie) static scratch_array_type scratch;
cout << *i++ << " ";
cout << endl;
i = array;
// test i-- }; // test_opr_base
while (ie != i) {
ie--;
cout << *ie << " ";
}
cout << endl;
ie = array + sizeof(array)/sizeof(string);
// test i->m template <typename T, typename R = T&, typename P = T*>
while (i != ie) { class test_opr
cout << i->size() << " "; : public test_opr_base
++i; {
} typedef test_opr<T, R, P> self_type;
cout << endl;
i = array;
// test i + n public:
while (i < ie) { // Types
cout << *i << " "; typedef T value_type;
i = i + 2; typedef R reference;
} typedef P pointer;
cout << endl;
i = array;
// test n + i typedef test_iter<T, R, P> iter_type;
while (i < ie) {
cout << *i << " ";
i = ptrdiff_t(2) + i;
}
cout << endl;
i = array;
// test i - n // Test controller
while (ie > i) { static void master_test( char const name[] );
ie = ie - 2;
cout << *ie << " ";
}
cout << endl;
ie = array + sizeof(array)/sizeof(string);
// test i[n] private:
for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j) // Test data
cout << i[j] << " "; static iter_type const fruit_begin, fruit_end;
cout << endl;
}
{
test_iter<string, const string&, const string*> i = array,
ie = array + sizeof(array)/sizeof(string);
// Tests for all of the operators added by random_access_iterator_helper // Test parts
static void post_increment_test();
static void post_decrement_test();
static void indirect_referral_test();
static void offset_addition_test();
static void reverse_offset_addition_test();
static void offset_subtraction_test();
static void comparison_test();
static void indexing_test();
// test i++ }; // test_opr
while (i != ie)
cout << *i++ << " ";
cout << endl;
i = array;
// test i--
while (ie != i) {
ie--;
cout << *ie << " ";
}
cout << endl;
ie = array + sizeof(array)/sizeof(string);
// test i->m // Class-static data definitions
while (i != ie) { typename test_opr_base::fruit_array_type
cout << i->size() << " "; test_opr_base::fruit = { "apple", "orange", "pear", "peach", "grape", "plum" };
++i;
}
cout << endl;
i = array;
// test i + n typename test_opr_base::scratch_array_type
while (i < ie) { test_opr_base::scratch = "";
cout << *i << " ";
i = i + 2;
}
cout << endl;
i = array;
// test n + i template <typename T, typename R, typename P>
while (i < ie) { typename test_opr<T, R, P>::iter_type const
cout << *i << " "; test_opr<T, R, P>::fruit_begin( fruit );
i = ptrdiff_t(2) + i;
}
cout << endl;
i = array;
// test i - n template <typename T, typename R, typename P>
while (ie > i) { typename test_opr<T, R, P>::iter_type const
ie = ie - 2; test_opr<T, R, P>::fruit_end( fruit + fruit_length );
cout << *ie << " ";
}
cout << endl;
ie = array + sizeof(array)/sizeof(string);
// test i[n]
for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j) // Main testing function
cout << i[j] << " "; int
cout << endl; test_main( int , char * [] )
} {
return 0; using std::string;
typedef test_opr<string, string &, string *> test1_type;
typedef test_opr<string, string const &, string const *> test2_type;
test1_type::master_test( "non-const string" );
test2_type::master_test( "const string" );
return boost::exit_success;
}
// Tests for all of the operators added by random_access_iterator_helper
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::master_test
(
char const name[]
)
{
std::cout << "Doing test run for " << name << '.' << std::endl;
post_increment_test();
post_decrement_test();
indirect_referral_test();
offset_addition_test();
reverse_offset_addition_test();
offset_subtraction_test();
comparison_test();
indexing_test();
}
// Test post-increment
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::post_increment_test
(
)
{
std::cout << "\tDoing post-increment test." << std::endl;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_begin ; i != fruit_end ; )
{
oss << *i++ << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "apple orange pear peach grape plum ")
== 0 );
}
// Test post-decrement
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::post_decrement_test
(
)
{
std::cout << "\tDoing post-decrement test." << std::endl;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_end ; i != fruit_begin ; )
{
i--;
oss << *i << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "plum grape peach pear orange apple ")
== 0 );
}
// Test indirect structure referral
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::indirect_referral_test
(
)
{
std::cout << "\tDoing indirect reference test." << std::endl;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_begin ; i != fruit_end ; ++i )
{
oss << i->size() << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "5 6 4 5 5 4 ") == 0 );
}
// Test offset addition
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::offset_addition_test
(
)
{
std::cout << "\tDoing offset addition test." << std::endl;
std::ptrdiff_t const two = 2;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_begin ; i != fruit_end ; i = i + two )
{
oss << *i << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "apple pear grape ") == 0 );
}
// Test offset addition, in reverse order
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::reverse_offset_addition_test
(
)
{
std::cout << "\tDoing reverse offset addition test." << std::endl;
std::ptrdiff_t const two = 2;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_begin ; i != fruit_end ; i = two + i )
{
oss << *i << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "apple pear grape ") == 0 );
}
// Test offset subtraction
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::offset_subtraction_test
(
)
{
std::cout << "\tDoing offset subtraction test." << std::endl;
std::ptrdiff_t const two = 2;
std::ostrstream oss( scratch, scratch_length );
for ( iter_type i = fruit_end ; fruit_begin < i ; )
{
i = i - two;
if ( (fruit_begin < i) || (fruit_begin == i) )
{
oss << *i << ' ';
}
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "grape pear apple ") == 0 );
}
// Test comparisons
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::comparison_test
(
)
{
using std::cout;
using std::ptrdiff_t;
cout << "\tDoing comparison tests.\n\t\tPass:";
for ( iter_type i = fruit_begin ; i != fruit_end ; ++i )
{
ptrdiff_t const i_offset = i - fruit_begin;
cout << ' ' << *i << std::flush;
for ( iter_type j = fruit_begin ; j != fruit_end ; ++j )
{
ptrdiff_t const j_offset = j - fruit_begin;
BOOST_TEST( (i != j) == (i_offset != j_offset) );
BOOST_TEST( (i > j) == (i_offset > j_offset) );
BOOST_TEST( (i <= j) == (i_offset <= j_offset) );
BOOST_TEST( (i >= j) == (i_offset >= j_offset) );
}
}
cout << std::endl;
}
// Test indexing
template <typename T, typename R, typename P>
void
test_opr<T, R, P>::indexing_test
(
)
{
std::cout << "\tDoing indexing test." << std::endl;
std::ostrstream oss( scratch, scratch_length );
for ( std::size_t k = 0u ; k < fruit_length ; ++k )
{
oss << fruit_begin[ k ] << ' ';
}
oss << std::ends;
BOOST_TEST( std::strcmp(oss.str(), "apple orange pear peach grape plum ")
== 0 );
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,18 +8,26 @@
// See http://www.boost.org for most recent version including documentation. // See http://www.boost.org for most recent version including documentation.
// Revision History // Revision History
// 20 May 01 Output progress messages. Added tests for new operator
// templates. Updated random number generator. Changed tests to
// use Boost Test Tools library. (Daryle Walker)
// 04 Jun 00 Added regression test for a bug I found (David Abrahams) // 04 Jun 00 Added regression test for a bug I found (David Abrahams)
// 17 Jun 00 Fix for broken compilers (Aleksey Gurtovoy) // 17 Jun 00 Fix for broken compilers (Aleksey Gurtovoy)
// ?? ??? 00 Major update to randomly test all one- and two- argument forms by // ?? ??? 00 Major update to randomly test all one- and two- argument forms by
// wrapping integral types and comparing the results of operations to // wrapping integral types and comparing the results of operations
// the results for the raw types (David Abrahams) // to the results for the raw types (David Abrahams)
// 12 Dec 99 Minor update, output confirmation message. // 12 Dec 99 Minor update, output confirmation message.
// 15 Nov 99 Initial version // 15 Nov 99 Initial version
#include <boost/operators.hpp> #define BOOST_INCLUDE_MAIN
#include <cassert>
#include <iostream> #include <boost/config.hpp> // for BOOST_MSVC
#include <boost/min_rand.hpp> #include <boost/cstdlib.hpp> // for boost::exit_success
#include <boost/operators.hpp> // for the tested items
#include <boost/random/linear_congruential.hpp> // for boost::minstd_rand
#include <boost/test/test_tools.hpp> // for main
#include <iostream> // for std::cout (std::endl indirectly)
namespace namespace
@ -28,14 +36,18 @@ namespace
int true_value(int x) { return x; } int true_value(int x) { return x; }
long true_value(long x) { return x; } long true_value(long x) { return x; }
signed char true_value(signed char x) { return x; } signed char true_value(signed char x) { return x; }
short true_value(short x) { return x; }
unsigned int true_value(unsigned int x) { return x; } unsigned int true_value(unsigned int x) { return x; }
unsigned long true_value(unsigned long x) { return x; } unsigned long true_value(unsigned long x) { return x; }
unsigned char true_value(unsigned char x) { return x; } unsigned char true_value(unsigned char x) { return x; }
unsigned short true_value(unsigned short x) { return x; }
// The use of operators<> here tended to obscure interactions with certain // The use of operators<> here tended to obscure
// compiler bugs // interactions with certain compiler bugs
template <class T> template <class T>
class Wrapped1 : boost::operators<Wrapped1<T> > class Wrapped1
: boost::operators<Wrapped1<T> >
, boost::shiftable<Wrapped1<T> >
{ {
public: public:
explicit Wrapped1( T v = T() ) : _value(v) {} explicit Wrapped1( T v = T() ) : _value(v) {}
@ -60,6 +72,10 @@ namespace
{ _value &= x._value; return *this; } { _value &= x._value; return *this; }
Wrapped1& operator^=(const Wrapped1& x) Wrapped1& operator^=(const Wrapped1& x)
{ _value ^= x._value; return *this; } { _value ^= x._value; return *this; }
Wrapped1& operator<<=(const Wrapped1& x)
{ _value <<= x._value; return *this; }
Wrapped1& operator>>=(const Wrapped1& x)
{ _value >>= x._value; return *this; }
Wrapped1& operator++() { ++_value; return *this; } Wrapped1& operator++() { ++_value; return *this; }
Wrapped1& operator--() { --_value; return *this; } Wrapped1& operator--() { --_value; return *this; }
@ -70,9 +86,11 @@ namespace
T true_value(Wrapped1<T> x) { return x.value(); } T true_value(Wrapped1<T> x) { return x.value(); }
template <class T, class U> template <class T, class U>
class Wrapped2 : class Wrapped2
boost::operators<Wrapped2<T, U> >, : boost::operators<Wrapped2<T, U> >
boost::operators2<Wrapped2<T, U>, U> , boost::operators2<Wrapped2<T, U>, U>
, boost::shiftable1<Wrapped2<T, U>
, boost::shiftable2<Wrapped2<T, U>, U > >
{ {
public: public:
explicit Wrapped2( T v = T() ) : _value(v) {} explicit Wrapped2( T v = T() ) : _value(v) {}
@ -97,6 +115,10 @@ namespace
{ _value &= x._value; return *this; } { _value &= x._value; return *this; }
Wrapped2& operator^=(const Wrapped2& x) Wrapped2& operator^=(const Wrapped2& x)
{ _value ^= x._value; return *this; } { _value ^= x._value; return *this; }
Wrapped2& operator<<=(const Wrapped2& x)
{ _value <<= x._value; return *this; }
Wrapped2& operator>>=(const Wrapped2& x)
{ _value >>= x._value; return *this; }
Wrapped2& operator++() { ++_value; return *this; } Wrapped2& operator++() { ++_value; return *this; }
Wrapped2& operator--() { --_value; return *this; } Wrapped2& operator--() { --_value; return *this; }
@ -111,6 +133,8 @@ namespace
Wrapped2& operator|=(U u) { _value |= u; return *this; } Wrapped2& operator|=(U u) { _value |= u; return *this; }
Wrapped2& operator&=(U u) { _value &= u; return *this; } Wrapped2& operator&=(U u) { _value &= u; return *this; }
Wrapped2& operator^=(U u) { _value ^= u; return *this; } Wrapped2& operator^=(U u) { _value ^= u; return *this; }
Wrapped2& operator<<=(U u) { _value <<= u; return *this; }
Wrapped2& operator>>=(U u) { _value >>= u; return *this; }
private: private:
T _value; T _value;
@ -118,203 +142,268 @@ namespace
template <class T, class U> template <class T, class U>
T true_value(Wrapped2<T,U> x) { return x.value(); } T true_value(Wrapped2<T,U> x) { return x.value(); }
template <class T>
class Wrapped3
: boost::equivalent<Wrapped3<T> >
, boost::partially_ordered<Wrapped3<T> >
, boost::equality_comparable<Wrapped3<T> >
{
public:
explicit Wrapped3( T v = T() ) : _value(v) {}
T value() const { return _value; }
bool operator<(const Wrapped3& x) const { return _value < x._value; }
private:
T _value;
};
template <class T>
T true_value(Wrapped3<T> x) { return x.value(); }
template <class T, class U>
class Wrapped4
: boost::equality_comparable1<Wrapped4<T, U>
, boost::equivalent1<Wrapped4<T, U>
, boost::partially_ordered1<Wrapped4<T, U> > > >
, boost::partially_ordered2<Wrapped4<T, U>, U
, boost::equivalent2<Wrapped4<T, U>, U
, boost::equality_comparable2<Wrapped4<T, U>, U> > >
{
public:
explicit Wrapped4( T v = T() ) : _value(v) {}
T value() const { return _value; }
bool operator<(const Wrapped4& x) const { return _value < x._value; }
bool operator<(U u) const { return _value < u; }
bool operator>(U u) const { return _value > u; }
private:
T _value;
};
template <class T, class U>
T true_value(Wrapped4<T,U> x) { return x.value(); }
// MyInt uses only the single template-argument form of all_operators<> // MyInt uses only the single template-argument form of all_operators<>
typedef Wrapped1<int> MyInt; typedef Wrapped1<int> MyInt;
typedef Wrapped2<long, long> MyLong; typedef Wrapped2<long, long> MyLong;
typedef Wrapped3<signed char> MyChar;
typedef Wrapped4<short, short> MyShort;
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2) void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert(true_value(y1) == true_value(y2)); BOOST_TEST( true_value(y1) == true_value(y2) );
assert(true_value(x1) == true_value(x2)); BOOST_TEST( true_value(x1) == true_value(x2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_less_than_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_less_than_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 < y1) == (x2 < y2)); BOOST_TEST( (x1 < y1) == (x2 < y2) );
assert((x1 <= y1) == (x2 <= y2)); BOOST_TEST( (x1 <= y1) == (x2 <= y2) );
assert((x1 >= y1) == (x2 >= y2)); BOOST_TEST( (x1 >= y1) == (x2 >= y2) );
assert((x1 > y1) == (x2 > y2)); BOOST_TEST( (x1 > y1) == (x2 > y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_less_than_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_less_than_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_less_than_comparable_aux(x1, y1, x2, y2); test_less_than_comparable_aux( x1, y1, x2, y2 );
test_less_than_comparable_aux(y1, x1, y2, x2); test_less_than_comparable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_equality_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_equality_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 == y1) == (x2 == y2)); BOOST_TEST( (x1 == y1) == (x2 == y2) );
assert((x1 != y1) == (x2 != y2)); BOOST_TEST( (x1 != y1) == (x2 != y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_equality_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_equality_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_equality_comparable_aux(x1, y1, x2, y2); test_equality_comparable_aux( x1, y1, x2, y2 );
test_equality_comparable_aux(y1, x1, y2, x2); test_equality_comparable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_multipliable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_multipliable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 * y1).value() == (x2 * y2)); BOOST_TEST( (x1 * y1).value() == (x2 * y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_multipliable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_multipliable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_multipliable_aux(x1, y1, x2, y2); test_multipliable_aux( x1, y1, x2, y2 );
test_multipliable_aux(y1, x1, y2, x2); test_multipliable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_addable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_addable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 + y1).value() == (x2 + y2)); BOOST_TEST( (x1 + y1).value() == (x2 + y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_addable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_addable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_addable_aux(x1, y1, x2, y2); test_addable_aux( x1, y1, x2, y2 );
test_addable_aux(y1, x1, y2, x2); test_addable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_subtractable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_subtractable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
assert((x1 - y1).value() == x2 - y2); BOOST_TEST( (x1 - y1).value() == (x2 - y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
if (y2 != 0) if ( y2 != 0 )
assert((x1 / y1).value() == x2 / y2); BOOST_TEST( (x1 / y1).value() == (x2 / y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
if (y2 != 0) if ( y2 != 0 )
assert((x1 / y1).value() == x2 / y2); BOOST_TEST( (x1 % y1).value() == (x2 % y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_xorable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_xorable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 ^ y1).value() == (x2 ^ y2)); BOOST_TEST( (x1 ^ y1).value() == (x2 ^ y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_xorable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_xorable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_xorable_aux(x1, y1, x2, y2); test_xorable_aux( x1, y1, x2, y2 );
test_xorable_aux(y1, x1, y2, x2); test_xorable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_andable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_andable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 & y1).value() == (x2 & y2)); BOOST_TEST( (x1 & y1).value() == (x2 & y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_andable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_andable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_andable_aux(x1, y1, x2, y2); test_andable_aux( x1, y1, x2, y2 );
test_andable_aux(y1, x1, y2, x2); test_andable_aux( y1, x1, y2, x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_orable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_orable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
assert((x1 | y1).value() == (x2 | y2)); BOOST_TEST( (x1 | y1).value() == (x2 | y2) );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_orable(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_orable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
sanity_check(x1, y1, x2, y2); sanity_check( x1, y1, x2, y2 );
test_orable_aux(x1, y1, x2, y2); test_orable_aux( x1, y1, x2, y2 );
test_orable_aux(y1, x1, y2, x2); test_orable_aux( y1, x1, y2, x2 );
}
template <class X1, class Y1, class X2, class Y2>
void test_left_shiftable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
sanity_check( x1, y1, x2, y2 );
BOOST_TEST( (x1 << y1).value() == (x2 << y2) );
}
template <class X1, class Y1, class X2, class Y2>
void test_right_shiftable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
sanity_check( x1, y1, x2, y2 );
BOOST_TEST( (x1 >> y1).value() == (x2 >> y2) );
} }
template <class X1, class X2> template <class X1, class X2>
void test_incrementable(X1 x1, X2 x2) void test_incrementable(X1 x1, X2 x2)
{ {
sanity_check(x1, x1, x2, x2); sanity_check( x1, x1, x2, x2 );
assert(x1++.value() == x2++); BOOST_TEST( (x1++).value() == x2++ );
assert(x1.value() == x2); BOOST_TEST( x1.value() == x2 );
} }
template <class X1, class X2> template <class X1, class X2>
void test_decrementable(X1 x1, X2 x2) void test_decrementable(X1 x1, X2 x2)
{ {
sanity_check(x1, x1, x2, x2); sanity_check( x1, x1, x2, x2 );
assert(x1--.value() == x2--); BOOST_TEST( (x1--).value() == x2-- );
assert(x1.value() == x2); BOOST_TEST( x1.value() == x2 );
} }
template <class X1, class Y1, class X2, class Y2> template <class X1, class Y1, class X2, class Y2>
void test_all(X1 x1, Y1 y1, X2 x2, Y2 y2) void test_all(X1 x1, Y1 y1, X2 x2, Y2 y2)
{ {
test_less_than_comparable(x1, y1, x2, y2); test_less_than_comparable( x1, y1, x2, y2 );
test_equality_comparable(x1, y1, x2, y2); test_equality_comparable( x1, y1, x2, y2 );
test_multipliable(x1, y1, x2, y2); test_multipliable( x1, y1, x2, y2 );
test_addable(x1, y1, x2, y2); test_addable( x1, y1, x2, y2 );
test_subtractable(x1, y1, x2, y2); test_subtractable( x1, y1, x2, y2 );
test_dividable(x1, y1, x2, y2); test_dividable( x1, y1, x2, y2 );
test_modable(x1, y1, x2, y2); test_modable( x1, y1, x2, y2 );
test_xorable(x1, y1, x2, y2); test_xorable( x1, y1, x2, y2 );
test_andable(x1, y1, x2, y2); test_andable( x1, y1, x2, y2 );
test_orable(x1, y1, x2, y2); test_orable( x1, y1, x2, y2 );
test_incrementable(x1, x2); test_left_shiftable( x1, y1, x2, y2 );
test_decrementable(x1, x2); test_right_shiftable( x1, y1, x2, y2 );
test_incrementable( x1, x2 );
test_decrementable( x1, x2 );
} }
template <class Big, class Small> template <class Big, class Small>
struct tester struct tester
{ {
void operator()(boost::min_rand& randomizer) const void operator()(boost::minstd_rand& randomizer) const
{ {
Big b1 = Big(randomizer()); Big b1 = Big( randomizer() );
Big b2 = Big(randomizer()); Big b2 = Big( randomizer() );
Small s = Small(randomizer()); Small s = Small( randomizer() );
test_all(Wrapped1<Big>(b1), Wrapped1<Big>(b2), b1, b2); test_all( Wrapped1<Big>(b1), Wrapped1<Big>(b2), b1, b2 );
test_all(Wrapped2<Big, Small>(b1), s, b1, s); test_all( Wrapped2<Big, Small>(b1), s, b1, s );
} }
}; };
// added as a regression test. We had a bug which this uncovered. // added as a regression test. We had a bug which this uncovered.
struct Point struct Point
: boost::addable<Point, : boost::addable<Point
boost::subtractable<Point> > , boost::subtractable<Point> >
{ {
Point( int h, int v ) : h(h), v(v) {} Point( int h, int v ) : h(h), v(v) {}
Point() :h(0), v(0) {} Point() :h(0), v(0) {}
const Point& operator+=( const Point& rhs ) { h += rhs.h; v += rhs.v; return *this; } const Point& operator+=( const Point& rhs )
const Point& operator-=( const Point& rhs ) { h -= rhs.h; v -= rhs.v; return *this; } { h += rhs.h; v += rhs.v; return *this; }
const Point& operator-=( const Point& rhs )
{ h -= rhs.h; v -= rhs.v; return *this; }
int h; int h;
int v; int v;
}; };
} // unnamed namespace } // unnamed namespace
@ -340,20 +429,25 @@ template Wrapped2<unsigned long, unsigned char>;
template Wrapped2<unsigned long, unsigned long>; template Wrapped2<unsigned long, unsigned long>;
#endif #endif
#ifdef NDEBUG #define PRIVATE_EXPR_TEST(e, t) BOOST_TEST( ((e), (t)) )
#error This program is pointless when NDEBUG disables assert()!
#endif
int main()
int
test_main( int , char * [] )
{ {
using std::cout;
using std::endl;
// Regression test. // Regression test.
Point x; Point x;
x = x + Point(3, 4); x = x + Point(3, 4);
x = x - Point(3, 4); x = x - Point(3, 4);
cout << "Created point, and operated on it." << endl;
for (int n = 0; n < 10000; ++n) for (int n = 0; n < 10000; ++n)
{ {
boost::min_rand r; boost::minstd_rand r;
tester<long, int>()(r); tester<long, int>()(r);
tester<long, signed char>()(r); tester<long, signed char>()(r);
tester<long, long>()(r); tester<long, long>()(r);
@ -367,115 +461,197 @@ int main()
tester<unsigned int, unsigned char>()(r); tester<unsigned int, unsigned char>()(r);
} }
cout << "Did random tester loop." << endl;
MyInt i1(1); MyInt i1(1);
MyInt i2(2); MyInt i2(2);
MyInt i; MyInt i;
assert( i1.value() == 1 ); BOOST_TEST( i1.value() == 1 );
assert( i2.value() == 2 ); BOOST_TEST( i2.value() == 2 );
assert( i.value() == 0 ); BOOST_TEST( i.value() == 0 );
i = i2; cout << "Created MyInt objects.\n";
assert( i.value() == 2 );
assert( i2 == i );
assert( i1 != i2 );
assert( i1 < i2 );
assert( i1 <= i2 );
assert( i <= i2 );
assert( i2 > i1 );
assert( i2 >= i1 );
assert( i2 >= i );
i = i1 + i2; assert( i.value() == 3 ); PRIVATE_EXPR_TEST( (i = i2), (i.value() == 2) );
i = i + i2; assert( i.value() == 5 );
i = i - i1; assert( i.value() == 4 ); BOOST_TEST( i2 == i );
i = i * i2; assert( i.value() == 8 ); BOOST_TEST( i1 != i2 );
i = i / i2; assert( i.value() == 4 ); BOOST_TEST( i1 < i2 );
i = i % (i - i1); assert( i.value() == 1 ); BOOST_TEST( i1 <= i2 );
i = i2 + i2; assert( i.value() == 4 ); BOOST_TEST( i <= i2 );
i = i1 | i2 | i; assert( i.value() == 7 ); BOOST_TEST( i2 > i1 );
i = i & i2; assert( i.value() == 2 ); BOOST_TEST( i2 >= i1 );
i = i + i1; assert( i.value() == 3 ); BOOST_TEST( i2 >= i );
i = i ^ i1; assert( i.value() == 2 );
i = (i+i1)*(i2|i1); assert( i.value() == 9 ); PRIVATE_EXPR_TEST( (i = i1 + i2), (i.value() == 3) );
PRIVATE_EXPR_TEST( (i = i + i2), (i.value() == 5) );
PRIVATE_EXPR_TEST( (i = i - i1), (i.value() == 4) );
PRIVATE_EXPR_TEST( (i = i * i2), (i.value() == 8) );
PRIVATE_EXPR_TEST( (i = i / i2), (i.value() == 4) );
PRIVATE_EXPR_TEST( (i = i % ( i - i1 )), (i.value() == 1) );
PRIVATE_EXPR_TEST( (i = i2 + i2), (i.value() == 4) );
PRIVATE_EXPR_TEST( (i = i1 | i2 | i), (i.value() == 7) );
PRIVATE_EXPR_TEST( (i = i & i2), (i.value() == 2) );
PRIVATE_EXPR_TEST( (i = i + i1), (i.value() == 3) );
PRIVATE_EXPR_TEST( (i = i ^ i1), (i.value() == 2) );
PRIVATE_EXPR_TEST( (i = ( i + i1 ) * ( i2 | i1 )), (i.value() == 9) );
PRIVATE_EXPR_TEST( (i = i1 << i2), (i.value() == 4) );
PRIVATE_EXPR_TEST( (i = i2 >> i1), (i.value() == 1) );
cout << "Performed tests on MyInt objects.\n";
MyLong j1(1); MyLong j1(1);
MyLong j2(2); MyLong j2(2);
MyLong j; MyLong j;
assert( j1.value() == 1 ); BOOST_TEST( j1.value() == 1 );
assert( j2.value() == 2 ); BOOST_TEST( j2.value() == 2 );
assert( j.value() == 0 ); BOOST_TEST( j.value() == 0 );
j = j2; cout << "Created MyLong objects.\n";
assert( j.value() == 2 );
assert( j2 == j );
assert( 2 == j );
assert( j2 == 2 );
assert( j == j2 );
assert( j1 != j2 );
assert( j1 != 2 );
assert( 1 != j2 );
assert( j1 < j2 );
assert( 1 < j2 );
assert( j1 < 2 );
assert( j1 <= j2 );
assert( 1 <= j2 );
assert( j1 <= j );
assert( j <= j2 );
assert( 2 <= j2 );
assert( j <= 2 );
assert( j2 > j1 );
assert( 2 > j1 );
assert( j2 > 1 );
assert( j2 >= j1 );
assert( 2 >= j1 );
assert( j2 >= 1 );
assert( j2 >= j );
assert( 2 >= j );
assert( j2 >= 2 );
assert( (j1 + 2) == 3 ); PRIVATE_EXPR_TEST( (j = j2), (j.value() == 2) );
assert( (1 + j2) == 3 );
j = j1 + j2; assert( j.value() == 3 );
assert( (j + 2) == 5 ); BOOST_TEST( j2 == j );
assert( (3 + j2) == 5 ); BOOST_TEST( 2 == j );
j = j + j2; assert( j.value() == 5 ); BOOST_TEST( j2 == 2 );
BOOST_TEST( j == j2 );
BOOST_TEST( j1 != j2 );
BOOST_TEST( j1 != 2 );
BOOST_TEST( 1 != j2 );
BOOST_TEST( j1 < j2 );
BOOST_TEST( 1 < j2 );
BOOST_TEST( j1 < 2 );
BOOST_TEST( j1 <= j2 );
BOOST_TEST( 1 <= j2 );
BOOST_TEST( j1 <= j );
BOOST_TEST( j <= j2 );
BOOST_TEST( 2 <= j2 );
BOOST_TEST( j <= 2 );
BOOST_TEST( j2 > j1 );
BOOST_TEST( 2 > j1 );
BOOST_TEST( j2 > 1 );
BOOST_TEST( j2 >= j1 );
BOOST_TEST( 2 >= j1 );
BOOST_TEST( j2 >= 1 );
BOOST_TEST( j2 >= j );
BOOST_TEST( 2 >= j );
BOOST_TEST( j2 >= 2 );
BOOST_TEST( (j1 + 2) == 3 );
BOOST_TEST( (1 + j2) == 3 );
PRIVATE_EXPR_TEST( (j = j1 + j2), (j.value() == 3) );
assert( (j - 1) == 4 ); BOOST_TEST( (j + 2) == 5 );
j = j - j1; assert( j.value() == 4 ); BOOST_TEST( (3 + j2) == 5 );
PRIVATE_EXPR_TEST( (j = j + j2), (j.value() == 5) );
assert( (j * 2) == 8 ); BOOST_TEST( (j - 1) == 4 );
assert( (4 * j2) == 8 ); PRIVATE_EXPR_TEST( (j = j - j1), (j.value() == 4) );
j = j * j2; assert( j.value() == 8 );
assert( (j / 2) == 4 ); BOOST_TEST( (j * 2) == 8 );
j = j / j2; assert( j.value() == 4 ); BOOST_TEST( (4 * j2) == 8 );
PRIVATE_EXPR_TEST( (j = j * j2), (j.value() == 8) );
assert( (j % 3) == 1 ); BOOST_TEST( (j / 2) == 4 );
j = j % (j - j1); assert( j.value() == 1 ); PRIVATE_EXPR_TEST( (j = j / j2), (j.value() == 4) );
j = j2 + j2; assert( j.value() == 4 ); BOOST_TEST( (j % 3) == 1 );
PRIVATE_EXPR_TEST( (j = j % ( j - j1 )), (j.value() == 1) );
assert( (1 | j2 | j) == 7 ); PRIVATE_EXPR_TEST( (j = j2 + j2), (j.value() == 4) );
assert( (j1 | 2 | j) == 7 );
assert( (j1 | j2 | 4) == 7 );
j = j1 | j2 | j; assert( j.value() == 7 );
assert( (7 & j2) == 2 ); BOOST_TEST( (1 | j2 | j) == 7 );
assert( (j & 2) == 2 ); BOOST_TEST( (j1 | 2 | j) == 7 );
j = j & j2; assert( j.value() == 2 ); BOOST_TEST( (j1 | j2 | 4) == 7 );
PRIVATE_EXPR_TEST( (j = j1 | j2 | j), (j.value() == 7) );
j = j | j1; assert( j.value() == 3 ); BOOST_TEST( (7 & j2) == 2 );
BOOST_TEST( (j & 2) == 2 );
PRIVATE_EXPR_TEST( (j = j & j2), (j.value() == 2) );
assert( (3 ^ j1) == 2 ); PRIVATE_EXPR_TEST( (j = j | j1), (j.value() == 3) );
assert( (j ^ 1) == 2 );
j = j ^ j1; assert( j.value() == 2 );
j = (j+j1)*(j2|j1); assert( j.value() == 9 ); BOOST_TEST( (3 ^ j1) == 2 );
BOOST_TEST( (j ^ 1) == 2 );
PRIVATE_EXPR_TEST( (j = j ^ j1), (j.value() == 2) );
std::cout << "0 errors detected\n"; PRIVATE_EXPR_TEST( (j = ( j + j1 ) * ( j2 | j1 )), (j.value() == 9) );
return 0;
BOOST_TEST( (j1 << 2) == 4 );
BOOST_TEST( (j2 << 1) == 4 );
PRIVATE_EXPR_TEST( (j = j1 << j2), (j.value() == 4) );
BOOST_TEST( (j >> 2) == 1 );
BOOST_TEST( (j2 >> 1) == 1 );
PRIVATE_EXPR_TEST( (j = j2 >> j1), (j.value() == 1) );
cout << "Performed tests on MyLong objects.\n";
MyChar k1(1);
MyChar k2(2);
MyChar k;
BOOST_TEST( k1.value() == 1 );
BOOST_TEST( k2.value() == 2 );
BOOST_TEST( k.value() == 0 );
cout << "Created MyChar objects.\n";
PRIVATE_EXPR_TEST( (k = k2), (k.value() == 2) );
BOOST_TEST( k2 == k );
BOOST_TEST( k1 != k2 );
BOOST_TEST( k1 < k2 );
BOOST_TEST( k1 <= k2 );
BOOST_TEST( k <= k2 );
BOOST_TEST( k2 > k1 );
BOOST_TEST( k2 >= k1 );
BOOST_TEST( k2 >= k );
cout << "Performed tests on MyChar objects.\n";
MyShort l1(1);
MyShort l2(2);
MyShort l;
BOOST_TEST( l1.value() == 1 );
BOOST_TEST( l2.value() == 2 );
BOOST_TEST( l.value() == 0 );
cout << "Created MyShort objects.\n";
PRIVATE_EXPR_TEST( (l = l2), (l.value() == 2) );
BOOST_TEST( l2 == l );
BOOST_TEST( 2 == l );
BOOST_TEST( l2 == 2 );
BOOST_TEST( l == l2 );
BOOST_TEST( l1 != l2 );
BOOST_TEST( l1 != 2 );
BOOST_TEST( 1 != l2 );
BOOST_TEST( l1 < l2 );
BOOST_TEST( 1 < l2 );
BOOST_TEST( l1 < 2 );
BOOST_TEST( l1 <= l2 );
BOOST_TEST( 1 <= l2 );
BOOST_TEST( l1 <= l );
BOOST_TEST( l <= l2 );
BOOST_TEST( 2 <= l2 );
BOOST_TEST( l <= 2 );
BOOST_TEST( l2 > l1 );
BOOST_TEST( 2 > l1 );
BOOST_TEST( l2 > 1 );
BOOST_TEST( l2 >= l1 );
BOOST_TEST( 2 >= l1 );
BOOST_TEST( l2 >= 1 );
BOOST_TEST( l2 >= l );
BOOST_TEST( 2 >= l );
BOOST_TEST( l2 >= 2 );
cout << "Performed tests on MyShort objects.\n";
return boost::exit_success;
} }