From b7c8e0c17f8351e152b69ac4f16be703a42a5d4f Mon Sep 17 00:00:00 2001
From: Dave Abrahams
Date: Mon, 4 Jun 2001 11:57:37 +0000
Subject: [PATCH] changes from Daryle Walker
[SVN r10264]
---
include/boost/operators.hpp | 381 ++++++---
iterators_test.cpp | 382 ++++++---
operators.htm | 1513 +++++++++++++++++++++++------------
operators_test.cpp | 522 ++++++++----
4 files changed, 1921 insertions(+), 877 deletions(-)
diff --git a/include/boost/operators.hpp b/include/boost/operators.hpp
index e6a2cb0..14d4c31 100644
--- a/include/boost/operators.hpp
+++ b/include/boost/operators.hpp
@@ -1,20 +1,20 @@
// Boost operators.hpp header file ----------------------------------------//
-// (C) Copyright David Abrahams 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.
-
-// (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.
+// (C) Copyright David Abrahams, Jeremy Siek, and Daryle Walker 1999-2001.
+// 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.
// 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
// supplied arguments from actually being used (Dave Abrahams)
// 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
+struct left_shiftable2 : B
+{
+ friend T operator<<(T x, const U& y) { return x <<= y; }
+};
+
+template
+struct left_shiftable1 : B
+{
+ friend T operator<<(T x, const T& y) { return x <<= y; }
+};
+
+template
+struct right_shiftable2 : B
+{
+ friend T operator>>(T x, const U& y) { return x >>= y; }
+};
+
+template
+struct right_shiftable1 : B
+{
+ friend T operator>>(T x, const T& y) { return x >>= y; }
+};
+
+template
+struct equivalent2 : B
+{
+ friend bool operator==(const T& x, const U& y)
+ {
+ return !(x < y) && !(x > y);
+ }
+};
+
+template
+struct equivalent1 : B
+{
+ friend bool operator==(const T&x, const T&y)
+ {
+ return !(x < y) && !(y < x);
+ }
+};
+
+template
+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
+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
+struct totally_ordered2
+ : less_than_comparable2 > {};
+
+template
+struct totally_ordered1
+ : less_than_comparable1 > {};
+
+template
+struct additive2
+ : addable2 > {};
+
+template
+struct additive1
+ : addable1 > {};
+
+template
+struct multiplicative2
+ : multipliable2 > {};
+
+template
+struct multiplicative1
+ : multipliable1 > {};
+
+template
+struct integer_multiplicative2
+ : multiplicative2 > {};
+
+template
+struct integer_multiplicative1
+ : multiplicative1 > {};
+
+template
+struct arithmetic2
+ : additive2 > {};
+
+template
+struct arithmetic1
+ : additive1 > {};
+
+template
+struct integer_arithmetic2
+ : additive2 > {};
+
+template
+struct integer_arithmetic1
+ : additive1 > {};
+
+template
+struct bitwise2
+ : xorable2 > > {};
+
+template
+struct bitwise1
+ : xorable1 > > {};
+
+template
+struct unit_steppable
+ : incrementable > {};
+
+template
+struct shiftable2
+ : left_shiftable2 > {};
+
+template
+struct shiftable1
+ : left_shiftable1 > {};
+
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
} // namespace boost
#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
// 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
// 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 \
+ struct template_name : ::template_name {};
- // 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) \
template \
struct template_name : ::template_name {};
@@ -309,21 +506,8 @@ struct indexable : B
template \
struct template_name : ::template_name {};
-# 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
-#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
//
@@ -332,7 +516,7 @@ struct indexable : B
// the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as
// 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
// template argument is being used for base class chaining, or is specifying a
@@ -355,6 +539,15 @@ template struct is_chained_base {
} // 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 \
+ struct is_chained_base< ::boost::template_name3 > { \
+ typedef ::boost::detail::true_t value; \
+ };
+
// Import a 2-type-argument operator template into boost (if neccessary) and
// provide a specialization of 'is_chained_base<>' for it.
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \
@@ -414,6 +607,8 @@ BOOST_OPERATOR_TEMPLATE1(template_name##1)
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+# define BOOST_OPERATOR_TEMPLATE3(template_name3) \
+ BOOST_IMPORT_TEMPLATE3(template_name3)
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \
BOOST_IMPORT_TEMPLATE2(template_name2)
# define BOOST_OPERATOR_TEMPLATE1(template_name1) \
@@ -442,47 +637,41 @@ BOOST_OPERATOR_TEMPLATE(orable)
BOOST_OPERATOR_TEMPLATE1(incrementable)
BOOST_OPERATOR_TEMPLATE1(decrementable)
+
BOOST_OPERATOR_TEMPLATE2(dereferenceable)
+BOOST_OPERATOR_TEMPLATE3(indexable)
-// indexable doesn't follow the patterns above (it has 4 template arguments), so
-// we just write out the compiler hacks explicitly.
-#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE
-# ifdef BOOST_NO_USING_TEMPLATE
- template
- struct indexable : ::indexable {};
-# else
- using ::indexable;
-# endif
-#endif
+BOOST_OPERATOR_TEMPLATE(left_shiftable)
+BOOST_OPERATOR_TEMPLATE(right_shiftable)
+BOOST_OPERATOR_TEMPLATE(equivalent)
+BOOST_OPERATOR_TEMPLATE(partially_ordered)
-#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
-template
-struct is_chained_base< ::boost::indexable > {
- typedef ::boost::detail::true_t operator_template_type;
-};
-#endif
+BOOST_OPERATOR_TEMPLATE(totally_ordered)
+BOOST_OPERATOR_TEMPLATE(additive)
+BOOST_OPERATOR_TEMPLATE(multiplicative)
+BOOST_OPERATOR_TEMPLATE(integer_multiplicative)
+BOOST_OPERATOR_TEMPLATE(arithmetic)
+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_TEMPLATE3
#undef BOOST_OPERATOR_TEMPLATE2
#undef BOOST_OPERATOR_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE2
+#undef BOOST_IMPORT_TEMPLATE3
// The following 'operators' classes can only be used portably if the derived class
// declares ALL of the required member operators.
template
struct operators2
- : less_than_comparable2 > > > > > > > > > {};
+ : totally_ordered2 > > {};
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template
@@ -492,31 +681,47 @@ template struct operators
#else
template struct operators
#endif
- : less_than_comparable > > > > > > > > > > > {};
+ : totally_ordered > > > {};
// 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
+struct input_iterator_helper
+ : equality_comparable1 > > > {};
+
+template
+struct output_iterator_helper
+ : incrementable > {};
+
template
struct forward_iterator_helper
- : equality_comparable > > > {};
template
struct bidirectional_iterator_helper
- : equality_comparable > > > > {};
+ : equality_comparable1 > > > {};
template
struct random_access_iterator_helper
- : equality_comparable > > > > > > > >
+ : totally_ordered1 > > > > >
{
-#ifndef __BORLANDC__
friend D requires_difference_operator(const T& x, const T& y) {
return x - y;
}
-#endif
}; // random_access_iterator_helper
} // namespace boost
diff --git a/iterators_test.cpp b/iterators_test.cpp
index e264aff..852bf09 100644
--- a/iterators_test.cpp
+++ b/iterators_test.cpp
@@ -9,16 +9,25 @@
// See http://www.boost.org for most recent version including documentation.
// 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)
-#include
-#include
-using namespace std;
+#define BOOST_INCLUDE_MAIN
+#include // for main
-#include
-using namespace boost;
+#include // for BOOST_STATIC_CONSTANT
+#include // for boost::exit_success
+#include // for boost::random_access_iterator_helper
+
+#include // for std::ptrdiff_t, std::size_t
+#include // for std::strcmp
+#include // for std::cout (std::endl, ends, and flush indirectly)
+#include // for std::string
+#include // for std::ostrstream
+// Iterator test class
template
struct test_iter
: public boost::random_access_iterator_helper<
@@ -29,7 +38,7 @@ struct test_iter
typedef std::ptrdiff_t Distance;
public:
- test_iter(T* i) : _i(i) { }
+ explicit test_iter(T* i =0) : _i(i) { }
test_iter(const self& x) : _i(x._i) { }
self& operator=(const self& x) { _i = x._i; return *this; }
Reference operator*() const { return *_i; }
@@ -43,127 +52,280 @@ public:
return x._i - y._i;
}
protected:
- T* _i;
+ P _i;
};
-
-int
-main()
+// Iterator operator testing classes
+class test_opr_base
{
- string array[] = { "apple", "orange", "pear", "peach", "grape", "plum" };
- {
- test_iter i = array,
- ie = array + sizeof(array)/sizeof(string);
+protected:
+ // Test data and types
+ BOOST_STATIC_CONSTANT( std::size_t, fruit_length = 6u );
+ 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++
- while (i != ie)
- cout << *i++ << " ";
- cout << endl;
- i = array;
+ static fruit_array_type fruit;
+ static scratch_array_type scratch;
- // test i--
- while (ie != i) {
- ie--;
- cout << *ie << " ";
- }
- cout << endl;
- ie = array + sizeof(array)/sizeof(string);
+}; // test_opr_base
- // test i->m
- while (i != ie) {
- cout << i->size() << " ";
- ++i;
- }
- cout << endl;
- i = array;
+template
+class test_opr
+ : public test_opr_base
+{
+ typedef test_opr self_type;
- // test i + n
- while (i < ie) {
- cout << *i << " ";
- i = i + 2;
- }
- cout << endl;
- i = array;
+public:
+ // Types
+ typedef T value_type;
+ typedef R reference;
+ typedef P pointer;
- // test n + i
- while (i < ie) {
- cout << *i << " ";
- i = ptrdiff_t(2) + i;
- }
- cout << endl;
- i = array;
+ typedef test_iter iter_type;
- // test i - n
- while (ie > i) {
- ie = ie - 2;
- cout << *ie << " ";
- }
- cout << endl;
- ie = array + sizeof(array)/sizeof(string);
+ // Test controller
+ static void master_test( char const name[] );
- // test i[n]
- for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j)
- cout << i[j] << " ";
- cout << endl;
- }
- {
- test_iter i = array,
- ie = array + sizeof(array)/sizeof(string);
+private:
+ // Test data
+ static iter_type const fruit_begin, fruit_end;
- // 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++
- while (i != ie)
- cout << *i++ << " ";
- cout << endl;
- i = array;
+}; // test_opr
- // test i--
- while (ie != i) {
- ie--;
- cout << *ie << " ";
- }
- cout << endl;
- ie = array + sizeof(array)/sizeof(string);
- // test i->m
- while (i != ie) {
- cout << i->size() << " ";
- ++i;
- }
- cout << endl;
- i = array;
+// Class-static data definitions
+typename test_opr_base::fruit_array_type
+ test_opr_base::fruit = { "apple", "orange", "pear", "peach", "grape", "plum" };
- // test i + n
- while (i < ie) {
- cout << *i << " ";
- i = i + 2;
- }
- cout << endl;
- i = array;
+typename test_opr_base::scratch_array_type
+ test_opr_base::scratch = "";
- // test n + i
- while (i < ie) {
- cout << *i << " ";
- i = ptrdiff_t(2) + i;
- }
- cout << endl;
- i = array;
+template
+typename test_opr::iter_type const
+ test_opr::fruit_begin( fruit );
- // test i - n
- while (ie > i) {
- ie = ie - 2;
- cout << *ie << " ";
- }
- cout << endl;
- ie = array + sizeof(array)/sizeof(string);
+template
+typename test_opr::iter_type const
+ test_opr::fruit_end( fruit + fruit_length );
- // test i[n]
- for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j)
- cout << i[j] << " ";
- cout << endl;
- }
- return 0;
+
+// Main testing function
+int
+test_main( int , char * [] )
+{
+ using std::string;
+
+ typedef test_opr test1_type;
+ typedef test_opr 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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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
+void
+test_opr::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 );
}
diff --git a/operators.htm b/operators.htm
index 3e9e7bc..8f78f51 100644
--- a/operators.htm
+++ b/operators.htm
@@ -1,28 +1,81 @@
+
-
-
-
-Header boost/operators.hpp Documentation
+
+Header <boost/operators.hpp> Documentation
-
+
+
+
+
+The header <boost/operators.hpp>
+supplies several sets of class templates (in namespace
+boost
). These templates define operators at namespace
+scope in terms of a minimal number of fundamental operators
+provided by the class.
+
+
-
-Header boost/operators.hpp supplies
-(in namespace boost) several sets of templates:
-These templates define many global operators in terms of a minimal number of
-fundamental operators.
-
+
+
+
+Overloaded operators for class types typically occur in groups. If
+you can write x + y
, you probably also want to be able to
+write x += y
. If you can write x < y,
you
+also want x > y, x >= y,
and x <= y
.
+Moreover, unless your class has really surprising behavior, some of
+these related operators can be defined in terms of others (e.g. x
+>= y <=> !(x < y)
). Replicating this boilerplate for
+multiple classes is both tedious and error-prone. The boost/operators.hpp
+templates help by generating operators for you at namespace scope based
+on other operators you've defined in your class.
+
If, for example, you declare a class like this:
+
- class MyInt : boost::operators<MyInt>
+class MyInt
+ : boost::operators<MyInt>
{
bool operator<(const MyInt& x) const;
bool operator==(const MyInt& x) const;
@@ -38,279 +91,172 @@ fundamental operators.
MyInt& operator--();
};
-then the operators<>
template adds more than a dozen
-additional operators, such as operator>, <=, >=, and +. Two-argument
-forms of the templates are also provided to allow interaction with other
-types.
-Dave Abrahams
-started the library and contributed the arithmetic operators in boost/operators.hpp.
-Jeremy Siek
-contributed the dereference operators and iterator
-helpers in boost/operators.hpp.
-Aleksey Gurtovoy
-contributed the code to support base class chaining
-while remaining backward-compatible with old versions of the library.
-Beman Dawes
-contributed test_operators.cpp.
-Rationale
-Overloaded operators for class types typically occur in groups. If you can
-write x + y
, you probably also want to be able to write x +=
-y
. If you can write x < y,
you also want x > y,
-x >= y,
and x <= y
. Moreover, unless your class has
-really surprising behavior, some of these related operators can be defined in
-terms of others (e.g. x >= y <=> !(x < y)
).
-Replicating this boilerplate for multiple classes is both tedious and
-error-prone. The boost/operators.hpp
-templates help by generating operators for you at namespace scope based on other
-operators you've defined in your class.
-
-Two-Argument Template Forms
-
-The arguments to a binary operator commonly have identical types, but it is
-not unusual to want to define operators which combine different types. For example,
-one might want to multiply a mathematical vector by a scalar. The two-argument
-template forms of the arithmetic operator templates are supplied for this
-purpose. When applying the two-argument form of a template, the desired return
-type of the operators typically determines which of the two types in question
-should be derived from the operator template. For example, if the result of T + U
-is of type T
, then T
(not U
) should be
-derived from addable<T,U>
. The comparison templates less_than_comparable<>
-and equality_comparable<>
-are exceptions to this guideline, since the return type of the operators they
-define is bool
.
-On compilers which do not support partial specialization, the two-argument
-forms must be specified by using the names shown below with the trailing '2'
.
-The single-argument forms with the trailing '1'
are provided for
-symmetry and to enable certain applications of the base
-class chaining technique.
-Arithmetic operators table
-The requirements for the types used to instantiate operator templates are
-specified in terms of expressions which must be valid and by the return type of
-the expression. In the following table t
and t1
are
-values of type T
, and u
is a value of type U
.
-Every template in the library other than operators<>
-and operators2<>
has an additional
-optional template parameter B
which is not shown in the table, but
-is explained below
-
-
-
- template |
- template will supply |
- Requirements |
-
-
-
- operators<T> |
- All the other <T> templates in this table. |
- All the <T> requirements in this table. |
-
- operators<T,U>
- operators2<T,U> |
- All the other <T,U> templates in this table, plus incrementable<T>
- and decrementable<T>. |
- All the <T,U> requirements in this table*,
- plus incrementable<T> and decrementable<T>. |
-
-
-
- less_than_comparable<T>
- less_than_comparable1<T> |
- bool operator>(const T&, const T&)
- bool operator<=(const T&, const T&)
- bool operator>=(const T&, const T&) |
- t<t1 . Return convertible to bool |
-
- less_than_comparable<T,U>
- less_than_comparable2<T,U> |
- bool operator<=(const T&, const U&)
- bool operator>=(const T&, const U&)
- bool operator>(const U&, const T&)
- bool operator<(const U&, const T&)
- bool operator<=(const U&, const T&)
- bool operator>=(const U&, const T&) |
- t<u . Return convertible to bool
- t>u . Return convertible to bool |
-
-
-
- equality_comparable<T>
- equality_comparable1<T> |
- bool operator!=(const T&, const T&) |
- t==t1 . Return convertible to bool |
-
- equality_comparable<T,U>
- equality_comparable2<T,U> |
- friend bool operator==(const U&, const T&)
- friend bool operator!=(const U&, const T&)
- friend bool operator!=( const T&, const U&) |
- t==u . Return convertible to bool |
-
-
-
- addable<T>
- addable1<T> |
- T operator+(T, const T&) |
- t+=t1 . Return convertible to T |
-
-
- addable<T,U>
- addable2<T,U> |
- T operator+(T, const U&)
- T operator+(const U&, T ) |
- t+=u . Return convertible to T |
-
-
- subtractable<T>
- subtractable1<T> |
- T operator-(T, const T&) |
- t-=t1 . Return convertible to T |
-
-
- subtractable<T,U>
- subtractable2<T,U> |
- T operator-(T, const U&) |
- t-=u . Return convertible to T |
-
-
- multipliable<T>
- multipliable1<T> |
- T operator*(T, const T&) |
- t*=t1 . Return convertible to T |
-
-
- multipliable<T,U>
- multipliable2<T,U> |
- T operator*(T, const U&)
- T operator*(const U&, T ) |
- t*=u . Return convertible to T |
-
-
- dividable<T>
- dividable1<T> |
- T operator/(T, const T&) |
- t/=t1 . Return convertible to T |
-
-
- dividable<T,U>
- dividable2<T,U> |
- T operator/(T, const U&) |
- t/=u . Return convertible to T |
-
-
- modable<T>
- modable1<T> |
- T operator%(T, const T&) |
- t%=t1 . Return convertible to T |
-
-
- modable<T,U>
- modable2<T,U> |
- T operator%(T, const U&) |
- t%=u . Return convertible to T |
-
-
- orable<T>
- orable1<T> |
- T operator|(T, const T&) |
- t|=t1 . Return convertible to T |
-
-
- orable<T,U>
- orable2<T,U> |
- T operator|(T, const U&)
- T operator|(const U&, T ) |
- t|=u . Return convertible to T |
-
-
- andable<T>
- andable1<T> |
- T operator&(T, const T&) |
- t&=t1 . Return convertible to T |
-
-
- andable<T,U>
- andable2<T,U> |
- T operator&(T, const U&)
- T operator&(const U&, T) |
- t&=u . Return convertible to T |
-
-
- xorable<T>
- xorable1<T> |
- T operator^(T, const T&) |
- t^=t1 . Return convertible to T |
-
-
- xorable<T,U>
- xorable2<T,U> |
- T operator^(T, const U&)
- T operator^(const U&, T ) |
- t^=u . Return convertible to T |
-
-
- incrementable<T>
- incrementable1<T> |
- T operator++(T& x, int) |
- T temp(x); ++x; return temp;
- Return convertible to T |
-
-
- decrementable<T>
- decrementable1<T> |
- T operator--(T& x, int) |
- T temp(x); --x; return temp;
- Return convertible to T |
-
-
-
-
-Portability Note: many compilers (e.g. MSVC6.3,
-GCC 2.95.2) will not enforce the requirements in this table unless the
-operations which depend on them are actually used. This is not
-standard-conforming behavior. If you are trying to write portable code it is
-important not to rely on this bug. In particular, it would be convenient to
-derive all your classes which need binary operators from the operators<>
-and operators2<>
templates,
-regardless of whether they implement all the requirements in the table. Even if
-this works with your compiler today, it may not work tomorrow.
-
-Every template listed in the table except operators<>
-and operators2<>
has an additional
-optional template parameter B
. If supplied, B
-must be a class type; the resulting class will be publicly derived from B. This
-can be used to avoid the object size bloat commonly associated with multiple
-empty base classes (see the note for users of older
-versions below for more details). To provide support for several groups of
-operators, use the additional parameter to chain operator templates into a
-single-base class hierarchy, as in the following example.
-Caveat: to chain to a base class which is not a boost operator
-template when using the single-argument form of a
-boost operator template, you must specify the operator template with the
-trailing '1'
in its name. Otherwise the library will assume you
-mean to define a binary operation combining the class you intend to use as a
-base class and the class you're deriving.
-Borland users: even single-inheritance seems to cause an increase in
-object size in some cases. If you are not defining a template, you may get
-better object-size performance by avoiding derivation altogether, and instead
-explicitly instantiating the operator template as follows:
-
+
+then the operators<>
+template adds more than a dozen additional operators, such as
+operator>
, <=
, >=
, and
+(binary) +
. Two-argument forms of
+the templates are also provided to allow interaction with other types.
+
+Summary of Template Semantics
+
+
+ - Each operator template completes the concept(s) it describes by
+ defining overloaded operators for its target class.
+
+ - The name of an operator class template indicates the concept that its target class will
+ model.
+
+ - Usually, the target class uses an instantation of the operator class
+ template as a base class. Some operator templates support an
+ alternate method.
+
+ - The concept can be compound, i.e. it may represent a
+ common combination of other, simpler concepts.
+
+ - Most operator templates require their target class to support
+ operations related to the operators supplied by the template. In
+ accordance with widely accepted coding style
+ recommendations, the target class is often required to
+ supply the assignment counterpart operator of the concept's
+ "main operator." For example, the
addable
+ template requires operator+=(T const&)
and
+ in turn supplies operator+(T const&, T
+ const&)
.
+
+
+
+
+The discussed concepts are not necessarily the standard library's
+concepts (CopyConstructible, etc.), although some of them could
+be; they are what we call concepts with a small 'c'. In
+particular, they are different from the former ones in that they do
+not describe precise semantics of the operators they require to
+be defined, except the requirements that (a) the semantics of the
+operators grouped in one concept should be consistent (e.g.
+effects of evaluating of a += b
and a = a + b
+expressions should be the same), and (b) that the return types of the
+operators should follow semantics of return types of corresponding
+operators for built-in types (e.g. operator<
+should return a type convertible to bool
, and
+T::operator-=
should return type convertible to
+T
). Such "loose" requirements make operators
+library applicable to broader set of target classes from different
+domains, i.e. eventually more useful.
+
+
+
+
+
+The arguments to a binary operator commonly have identical types, but
+it is not unusual to want to define operators which combine different
+types. For example, one might want to multiply a
+mathematical vector by a scalar. The two-argument template forms of the
+arithmetic operator templates are supplied for this purpose. When
+applying the two-argument form of a template, the desired return type of
+the operators typically determines which of the two types in question
+should be derived from the operator template. For example, if the
+result of T + U
is of type T
, then
+T
(not U
) should be derived from addable<T, U>
. The comparison
+templates (less_than_comparable<T,
+U>
, equality_comparable<T,
+U>
, equivalent<T, U>
,
+and partially_ordered<T, U>
)
+are exceptions to this guideline, since the return type of the operators
+they define is bool
.
+
+On compilers which do not support partial specialization, the
+two-argument forms must be specified by using the names shown below with
+the trailing '2'
. The single-argument forms with the
+trailing '1'
are provided for symmetry and to enable
+certain applications of the base class chaining
+technique.
+
+Base Class Chaining and Object Size
+
+Every operator class template, except the arithmetic
+examples and the iterator helpers, has an
+additional, but optional, template type parameter B
. This
+parameter will be a publicly-derived base class of the instantiated template.
+This means it must be a class type. It can be used to avoid the bloating of
+object sizes that is commonly associated with multiple-inheritance from
+several empty base classes (see the note for users of
+older versions for more details). To provide support for a group of
+operators, use the B
parameter to chain operator templates
+into a single-base class hierarchy, demostrated in the usage
+example. The technique is also used by the composite operator templates
+to group operator definitions. If a chain becomes too long for the compiler to
+support, try replacing some of the operator templates with a single grouped
+operator template that chains the old templates together; the length limit only
+applies to the number of templates directly in the chain, not those hidden in
+group templates.
+
+Caveat: to chain to a base class which is
+not a Boost operator template when using the single-argument form of a Boost operator template,
+you must specify the operator template with the trailing
+'1'
in its name. Otherwise the library will assume you
+mean to define a binary operation combining the class you intend to use
+as a base class and the class you're deriving.
+
+
+
+On some compilers (e.g. Borland, GCC) even single-inheritance seems
+to cause an increase in object size in some cases. If you are not defining
+a class template, you may get better object-size performance by avoiding
+derivation altogether, and instead explicitly instantiating the operator
+template as follows:
+
+
class myclass // lose the inheritance...
{
//...
};
+
// explicitly instantiate the operators I need.
- template class less_than_comparable<myclass>;
- template class equality_comparable<myclass>;
- template class incrementable<myclass>;
- template class decrementable<myclass>;
- template class addable<myclass,long>;
- template class subtractable<myclass,long>;
-
-
-Usage example
-
-template <class T>
+ template struct less_than_comparable<myclass>;
+ template struct equality_comparable<myclass>;
+ template struct incrementable<myclass>;
+ template struct decrementable<myclass>;
+ template struct addable<myclass,long>;
+ template struct subtractable<myclass,long>;
+
+
+Note that some operator templates cannot use this workaround and must
+be a base class of their primary operand type. Those templates define
+operators which must be member functions, and the workaround needs the
+operators to be independent friend functions. The relevant templates are:
+
+
+
+
+
+Many compilers (e.g. MSVC 6.3, GCC 2.95.2) will not enforce
+the requirements in the operator template tables unless the operations
+which depend on them are actually used. This is not standard-conforming
+behavior. In particular, although it would be convenient to derive all
+your classes which need binary operators from the
+operators<>
+and operators2<>
+templates, regardless of whether they implement all the requirements
+of those templates, this shortcut is not portable. Even if this currently
+works with your compiler, it may not work later.
+
+
+
+This example shows how some of the arithmetic
+operator templates can be used with a geometric point class (template).
+
+
+template <class T>
class point // note: private inheritance is OK here!
: boost::addable< point<T> // point + point
, boost::subtractable< point<T> // point - point
@@ -355,165 +301,692 @@ T length(const point<T> p)
const point<float> right(0, 1);
const point<float> up(1, 0);
const point<float> pi_over_4 = up + right;
-const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);
-Arithmetic operators demonstration and test program
-The operators_test.cpp
-program demonstrates the use of the arithmetic operator templates, and can also
-be used to verify correct operation.
-The test program has been compiled and run successfully with:
-
- - GCC 2.95.2
-
- GCC 2.95.2 / STLport 4.0b8.
-
- Metrowerks Codewarrior 5.3
-
- KAI C++ 3.3
-
- Microsoft Visual C++ 6.0 SP3.
-
- Microsoft Visual C++ 6.0 SP3 / STLport 4.0b8.
-
-Dereference operators and iterator helpers
-The iterator helper templates ease the task
-of creating a custom iterator. Similar to arithmetic types, a complete iterator
-has many operators that are "redundant" and can be implemented in
-terms of the core set of operators.
-The dereference operators were motivated by the iterator
-helpers, but are often useful in non-iterator contexts as well. Many of the
-redundant iterator operators are also arithmetic operators, so the iterator
-helper classes borrow many of the operators defined above. In fact, only two new
-operators need to be defined! (the pointer-to-member operator->
-and the subscript operator[]
).
-
Notation
-
-
-
- T |
- is the user-defined type for which the operations are
- being supplied. |
-
-
- V |
- is the type which the resulting dereferenceable
- type "points to", or the value_type of the custom
- iterator. |
-
-
- D |
- is the type used to index the resulting indexable
- type or the difference_type of the custom iterator. |
-
-
- P |
- is a type which can be dereferenced to access V ,
- or the pointer type of the custom iterator. |
-
-
- R |
- is the type returned by indexing the indexable
- type or the reference type of the custom iterator. |
-
-
- i |
- is short for static_cast<const T&>(*this) ,
- where this is a pointer to the helper class.
- Another words, i should be an object of the custom iterator
- type. |
-
-
- x,x1,x2 |
- are objects of type T . |
-
-
- n |
- is an object of type D . |
-
-
+const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);
+
+
+
+
+The arithmetic operator templates ease the task of creating a custom
+numeric type. Given a core set of operators, the templates add related
+operators to the numeric class. These operations are like the ones the
+standard arithmetic types have, and may include comparisons, adding,
+incrementing, logical and bitwise manipulations, etc. Further, since
+most numeric types need more than one of these operators, some
+templates are provided to combine several of the basic operator
+templates in one declaration.
+
+The requirements for the types used to instantiate the simple operator
+templates are specified in terms of expressions which must be valid and
+the expression's return type. The composite operator templates only list
+what other templates they use. The supplied operations and requirements
+of the composite operator templates can be inferred from the operations and
+requirements of the listed components.
+
+
+
+These templates are "simple" since they provide operators
+based on a single operation the base type has to provide. They have an
+additional optional template parameter B
, which is not shown,
+for the base class chaining technique.
+
+
+ Simple Arithmetic Operator Template Classes
+
+
+ Key
+
+ T : primary operand type |
+ U : alternate operand type |
+
+
+ t , t1 : values of type
+ T |
+ u : value of type U |
+
+ |
+
+
+ Template |
+ Supplied Operations |
+ Requirements |
+
+
+ less_than_comparable<T>
+ less_than_comparable1<T> |
+ bool operator>(const T&, const T&)
+ bool operator<=(const T&, const T&)
+ bool operator>=(const T&, const T&) |
+ t < t1 .
+ Return convertible to bool . See the Ordering Note. |
+
+
+ less_than_comparable<T, U>
+ less_than_comparable2<T, U> |
+ bool operator<=(const T&, const U&)
+ bool operator>=(const T&, const U&)
+ bool operator>(const U&, const T&)
+ bool operator<(const U&, const T&)
+ bool operator<=(const U&, const T&)
+ bool operator>=(const U&, const T&) |
+ t < u . t > u .
+ Returns convertible to bool . See the Ordering Note. |
+
+
+ equality_comparable<T>
+ equality_comparable1<T> |
+ bool operator!=(const T&, const T&) |
+ t == t1 .
+ Return convertible to bool . |
+
+
+ equality_comparable<T, U>
+ equality_comparable2<T, U> |
+ friend bool operator==(const U&, const T&)
+ friend bool operator!=(const U&, const T&)
+ friend bool operator!=( const T&, const U&) |
+ t == u .
+ Return convertible to bool . |
+
+
+ addable<T>
+ addable1<T> |
+ T operator+(T, const T&) |
+ t += t1 .
+ Return convertible to T . |
+
+
+ addable<T, U>
+ addable2<T, U> |
+ T operator+(T, const U&)
+ T operator+(const U&, T ) |
+ t += u .
+ Return convertible to T . |
+
+
+ subtractable<T>
+ subtractable1<T> |
+ T operator-(T, const T&) |
+ t -= t1 .
+ Return convertible to T . |
+
+
+ subtractable<T, U>
+ subtractable2<T, U> |
+ T operator-(T, const U&) |
+ t -= u .
+ Return convertible to T . |
+
+
+ multipliable<T>
+ multipliable1<T> |
+ T operator*(T, const T&) |
+ t *= t1 .
+ Return convertible to T . |
+
+
+ multipliable<T, U>
+ multipliable2<T, U> |
+ T operator*(T, const U&)
+ T operator*(const U&, T ) |
+ t *= u .
+ Return convertible to T . |
+
+
+ dividable<T>
+ dividable1<T> |
+ T operator/(T, const T&) |
+ t /= t1 .
+ Return convertible to T . |
+
+
+ dividable<T, U>
+ dividable2<T, U> |
+ T operator/(T, const U&) |
+ t /= u .
+ Return convertible to T . |
+
+
+ modable<T>
+ modable1<T> |
+ T operator%(T, const T&) |
+ t %= t1 .
+ Return convertible to T . |
+
+
+ modable<T, U>
+ modable2<T, U> |
+ T operator%(T, const U&) |
+ t %= u .
+ Return convertible to T . |
+
+
+ orable<T>
+ orable1<T> |
+ T operator|(T, const T&) |
+ t |= t1 .
+ Return convertible to T . |
+
+
+ orable<T, U>
+ orable2<T, U> |
+ T operator|(T, const U&)
+ T operator|(const U&, T ) |
+ t |= u .
+ Return convertible to T . |
+
+
+ andable<T>
+ andable1<T> |
+ T operator&(T, const T&) |
+ t &= t1 .
+ Return convertible to T . |
+
+
+ andable<T, U>
+ andable2<T, U> |
+ T operator&(T, const U&)
+ T operator&(const U&, T) |
+ t &= u .
+ Return convertible to T . |
+
+
+ xorable<T>
+ xorable1<T> |
+ T operator^(T, const T&) |
+ t ^= t1 .
+ Return convertible to T . |
+
+
+ xorable<T, U>
+ xorable2<T, U> |
+ T operator^(T, const U&)
+ T operator^(const U&, T ) |
+ t ^= u .
+ Return convertible to T . |
+
+
+ incrementable<T> |
+ T operator++(T& x, int) |
+ T temp(x); ++x; return temp;
+ Return convertible to T . |
+
+
+ decrementable<T> |
+ T operator--(T& x, int) |
+ T temp(x); --x; return temp;
+ Return convertible to T . |
+
+
+ left_shiftable<T>
+ left_shiftable1<T> |
+ T operator<<(T, const T&) |
+ t <<= t1 .
+ Return convertible to T . |
+
+
+ left_shiftable<T, U>
+ left_shiftable2<T, U> |
+ T operator<<(T, const U&) |
+ t <<= u .
+ Return convertible to T . |
+
+
+ right_shiftable<T>
+ right_shiftable1<T> |
+ T operator>>(T, const T&) |
+ t >>= t1 .
+ Return convertible to T . |
+
+
+ right_shiftable<T, U>
+ right_shiftable2<T, U> |
+ T operator>>(T, const U&) |
+ t >>= u .
+ Return convertible to T . |
+
+
+ equivalent<T>
+ equivalent1<T> |
+ bool operator==(const T&, const T&) |
+ t < t1 .
+ Return convertible to bool . See the Ordering Note. |
+
+
+ equivalent<T, U>
+ equivalent2<T, U> |
+ bool operator==(const T&, const U&) |
+ t < u . t > u .
+ Returns convertible to bool . See the Ordering Note. |
+
+
+ partially_ordered<T>
+ partially_ordered1<T> |
+ bool operator>(const T&, const T&)
+ bool operator<=(const T&, const T&)
+ bool operator>=(const T&, const T&) |
+ t < t1 . t == t1 .
+ Returns convertible to bool . See the Ordering Note. |
+
+
+ partially_ordered<T, U>
+ partially_ordered2<T, U> |
+ bool operator<=(const T&, const U&)
+ bool operator>=(const T&, const U&)
+ bool operator>(const U&, const T&)
+ bool operator<(const U&, const T&)
+ bool operator<=(const U&, const T&)
+ bool operator>=(const U&, const T&) |
+ t < u . t > u . t == u .
+ Returns convertible to bool . See the Ordering Note. |
+
-The requirements for the types used to instantiate the dereference operators
-and iterator helpers are specified in terms of expressions which must be valid
-and their return type.
-
-The dereference operator templates in this table all accept an optional
-template parameter (not shown) to be used for base class
-chaining.
-
-
-
- template |
- template will supply |
- Requirements |
-
-
- dereferenceable<T,P> |
- P operator->() const |
- (&*i.) . Return convertible to P . |
-
-
- indexable<T,D,R> |
- R operator[](D n) const |
- *(i + n) . Return of type R . |
-
-
+
+Ordering Note
+The less_than_comparable<T>
+and partially_ordered<T>
+templates provide the same set of operations. However, the workings of
+less_than_comparable<T>
+assume that all values of type T
can be placed in a total order. If
+that is not true (e.g. Not-a-Number values in IEEE floating point
+arithmetic), then
+partially_ordered<T>
+should be used. The
+partially_ordered<T>
+template can be used for a totally-ordered type, but it is not as efficient as
+less_than_comparable<T>
.
+This rule also applies for
+less_than_comparable<T,
+U>
and partially_ordered<T,
+U>
with respect to the ordering of all T
and
+U
values, and for both versions of
+equivalent<>
. The solution for
+equivalent<>
is to write a
+custom operator==
for the target class.
+
+
+
+The following templates provide common groups of related operations.
+For example, since a type which is addable is usually also subractable, the
+additive
template provides the combined
+operators of both. The grouped operator templates have an additional
+optional template parameter B
, which is not shown, for the
+base class chaining technique.
+
+
+ Grouped Arithmetic Operator Template Classes
+
+
+ Key
+
+ T : primary operand type |
+ U : alternate operand type |
+
+ |
+
+
+ Template |
+ Component Operator Templates |
+
+
+ totally_ordered<T>
+ totally_ordered1<T> |
+ |
+
+
+ totally_ordered<T, U>
+ totally_ordered2<T, U> |
+ |
+
+
+ additive<T>
+ additive1<T> |
+ |
+
+
+ additive<T, U>
+ additive2<T, U> |
+ |
+
+
+ multiplicative<T>
+ multiplicative1<T> |
+ |
+
+
+ multiplicative<T, U>
+ multiplicative2<T, U> |
+ |
+
+
+ integer_multiplicative<T>
+ integer_multiplicative1<T> |
+ |
+
+
+ integer_multiplicative<T, U>
+ integer_multiplicative2<T, U> |
+ |
+
+
+ arithmetic<T>
+ arithmetic1<T> |
+ |
+
+
+ arithmetic<T, U>
+ arithmetic2<T, U> |
+ |
+
+
+ integer_arithmetic<T>
+ integer_arithmetic1<T> |
+ |
+
+
+ integer_arithmetic<T, U>
+ integer_arithmetic2<T, U> |
+ |
+
+
+ bitwise<T>
+ bitwise1<T> |
+ |
+
+
+ bitwise<T, U>
+ bitwise2<T, U> |
+ |
+
+
+ unit_steppable<T> |
+ |
+
+
+ shiftable<T>
+ shiftable1<T> |
+ |
+
+
+ shiftable<T, U>
+ shiftable2<T, U> |
+ |
+
-
-There are three separate iterator helper classes, each for a different
-category of iterator. Here is a summary of the core set of operators that the
-custom iterator must define, and the extra operators that are created by the
-helper classes. For convenience, the helper classes also fill in all of the
-typedef's required of iterators by the C++ standard (iterator_category
,
-value_type
, etc.).
-
-
-
- template |
- template will supply |
- Requirements |
-
-
- forward_iterator_helper
- <T,V,D,P,R> |
- bool operator!=(const T& x1, const T& x2)
- T operator++(T& x, int)
- V* operator->() const
- |
- x1==x2 . Return convertible to bool
- T temp(x); ++x; return temp;
- (&*i.) . Return convertible to V* . |
-
-
- bidirectional_iterator_helper
- <T,V,D,P,R> |
- Same as above, plus
- T operator--(T& x, int) |
- Same as above, plus
- T temp(x); --x; return temp; |
-
-
- random_access_iterator_helper
- <T,V,D,P,R> |
- Same as above, plus
- T operator+(T x, const D&)
- T operator+(const D& n, T x)
- T operator-(T x, const D& n)
- R operator[](D n) const
- bool operator>(const T& x1, const T& x2)
- bool operator<=(const T& x1, const T& x2)
- bool operator>=(const T& x1, const T& x2) |
- Same as above, plus
- x+=n . Return convertible to T
- x-=n . Return convertible to T
- x1<x2 . Return convertible to bool
- And to satisfy RandomAccessIterator:
- x1-x2 . Return convertible to D |
-
-
+
+
+
+The arithmetic operator class templates operators<>
and operators2<>
are examples of
+non-extensible operator grouping classes. These legacy class templates,
+from previous versions of the header, cannot be used for
+base class chaining.
+
+
+ Final Arithmetic Operator Template Classes
+
+
+ Key
+
+ T : primary operand type |
+ U : alternate operand type |
+
+ |
+
+
+ Template |
+ Component Operator Templates |
+
+
+ operators<T> |
+ |
+
+
+ operators<T, U>
+ operators2<T, U> |
+ |
+
-Iterator demonstration and test program
-The iterators_test.cpp
-program demonstrates the use of the iterator templates, and can also be used to
-verify correct operation. The following is the custom iterator defined in the
-test program. It demonstrates a correct (though trivial) implementation of the
-core operations that must be defined in order for the iterator helpers to
-"fill in" the rest of the iterator operations.
+
+
+
+The operators_test.cpp
+program demonstrates the use of the arithmetic operator templates, and
+can also be used to verify correct operation. Check the compiler status report for the test results
+with selected platforms.
+
+Dereference Operators and Iterator Helpers
+
+The iterator helper templates ease the task
+of creating a custom iterator. Similar to arithmetic types, a complete
+iterator has many operators that are "redundant" and can be
+implemented in terms of the core set of operators.
+
+The dereference operators were motivated
+by the iterator helpers, but are often useful in
+non-iterator contexts as well. Many of the redundant iterator operators
+are also arithmetic operators, so the iterator helper classes borrow
+many of the operators defined above. In fact, only two new operators
+need to be defined (the pointer-to-member operator->
and
+the subscript operator[]
)!
+
+The requirements for the types used to instantiate the dereference
+operators are specified in terms of expressions which must be valid and
+their return type. The composite operator templates list their component
+templates, which the instantiating type must support, and possibly other
+requirements.
+
+
+
+All the dereference operator templates in this table accept an
+optional template parameter (not shown) to be used for base class chaining.
+
+
+ Dereference Operator Template Classes
+
+
+ Key
+
+ T : operand type |
+ P : pointer type |
+
+
+ D : difference_type |
+ R : reference type |
+
+
+ i : object of type T (an iterator) |
+ n : object of type D (an index) |
+
+ |
+
+
+ Template |
+ Supplied Operations |
+ Requirements |
+
+
+ dereferenceable<T, P> |
+ P operator->() const |
+ (&*i) . Return convertible to P . |
+
+
+ indexable<T, D, R> |
+ R operator[](D n) const |
+ *(i + n) . Return of type R . |
+
+
+
+
+
+There are three separate iterator helper classes, each for a
+different category of iterator. Here is a summary of the core set of
+operators that the custom iterator must define, and the extra operators
+that are created by the helper classes. These classes cannot be used for base class chaining. For convenience, the helper
+classes also fill in all of the typedef's required of iterators by the
+C++ standard (iterator_category
, value_type
,
+etc.).
+
+
+ Iterator Helper Template Classes
+
+
+ Key
+
+ T : operand type |
+ P : pointer type |
+
+
+ D : difference_type |
+ R : reference type |
+
+
+ V : value_type |
+ x1, x2 : objects of type T |
+
+ |
+
+
+ Template |
+ Operations & Requirements |
+
+
+ input_iterator_helper<T, V, D, P, R> |
+ Supports the operations and has the requirements of
+ |
+
+
+ output_iterator_helper<T, V, D, P, R> |
+ Supports the operations and has the requirements of
+ |
+
+
+ forward_iterator_helper<T, V, D, P, R> |
+ Supports the operations and has the requirements of
+ |
+
+
+ bidirectional_iterator_helper<T, V, D, P, R> |
+ Supports the operations and has the requirements of
+ |
+
+
+ random_access_iterator_helper<T, V, D, P, R> |
+ Supports the operations and has the requirements of
+
+ To satisfy RandomAccessIterator,
+ x1 - x2 with return convertible to D
+ is also required. |
+
+
+
+
+
+The iterators_test.cpp
+program demonstrates the use of the iterator templates, and can also be
+used to verify correct operation. The following is the custom iterator
+defined in the test program. It demonstrates a correct (though trivial)
+implementation of the core operations that must be defined in order for
+the iterator helpers to "fill in" the rest of the iterator
+operations.
+
- template <class T, class R, class P>
+template <class T, class R, class P>
struct test_iter
: public boost::random_access_iterator_helper<
test_iter<T,R,P>, T, std::ptrdiff_t, P, R>
@@ -523,75 +996,109 @@ struct test_iter
typedef std::ptrdiff_t Distance;
public:
- test_iter(T* i) : _i(i) { }
- test_iter(const self& x) : _i(x._i) { }
- self& operator=(const self& x) { _i = x._i; return *this; }
- Reference operator*() const { return *_i; }
- self& operator++() { ++_i; return *this; }
- self& operator--() { --_i; return *this; }
- self& operator+=(Distance n) { _i += n; return *this; }
- self& operator-=(Distance n) { _i -= n; return *this; }
- bool operator==(const self& x) const { return _i == x._i; }
- bool operator<(const self& x) const { return _i < x._i; }
- friend Distance operator-(const self& x, const self& y) {
- return x._i - y._i;
- }
-protected:
- T* _i;
+ explicit test_iter(T* i =0);
+ test_iter(const self& x);
+ self& operator=(const self& x);
+ Reference operator*() const;
+ self& operator++();
+ self& operator--();
+ self& operator+=(Distance n);
+ self& operator-=(Distance n);
+ bool operator==(const self& x) const;
+ bool operator<(const self& x) const;
+ friend Distance operator-(const self& x, const self& y);
};
-It has been compiled and run successfully with:
-
- - GCC 2.95.2
-
- Metrowerks Codewarrior 5.2
-
- Microsoft Visual C++ 6.0 SP3
-
-Jeremy Siek
-contributed the iterator operators and helpers. He also contributed iterators_test.cpp.
+
+Check the compiler status report for
+the test results with selected platforms.
+
-
-The changes in the library interface and recommended
-usage were motivated by some practical issues described below. The new
-version of the library is still backward-compatible with the former one (so
-you're not forced change any existing code), but the old usage is
-deprecated. Though it was arguably simpler and more intuitive than using base
-class chaining, it has been discovered that the old practice of deriving
-from multiple operator templates can cause the resulting classes to be much
-larger than they should be. Most modern C++ compilers significantly bloat the
-size of classes derived from multiple empty base classes, even though the base
-classes themselves have no state. For instance, the size of point<int>
-from the example above was 12-24 bytes on various compilers
-for the Win32 platform, instead of the expected 8 bytes.
-
Strictly speaking, it was not the library's fault - the language rules allow
-the compiler to apply the empty base class optimization in that situation. In
-principle an arbitrary number of empty base classes can be allocated at the same
-offset, provided that none of them have a common ancestor (see section 10.5 [class.derived],
-par. 5 of the standard). But the language definition also doesn't require
-implementations to do the optimization, and few if any of today's compilers
-implement it when multiple inheritance is involved. What's worse, it is very
-unlikely that implementors will adopt it as a future enhancement to existing
-compilers, because it would break binary compatibility between code generated by
-two different versions of the same compiler. As Matt Austern said, "One of
-the few times when you have the freedom to do this sort of thing is when you're
-targeting a new architecture...". On the other hand, many common compilers
-will use the empty base optimization for single inheritance hierarchies.
-Given the importance of the issue for the users of the library (which aims to
-be useful for writing light-weight classes like MyInt
or point<>
),
-and the forces described above, we decided to change the library interface so
-that the object size bloat could be eliminated even on compilers that support
-only the simplest form of the empty base class optimization. The current library
-interface is the result of those changes. Though the new usage is a bit more
-complicated than the old one, we think it's worth it to make the library more
-useful in real world. Alexy Gurtovoy contributed the code which supports the new
-usage idiom while allowing the library remain backward-compatible.
+
+
+
+
+ - Dave Abrahams
+
- Started the library and contributed the arithmetic operators in
+ boost/operators.hpp.
+
+
- Jeremy Siek
+
- Contributed the dereference operators and
+ iterator helpers in boost/operators.hpp.
+ Also contributed iterators_test.cpp.
+
+
- Aleksey Gurtovoy
+
- Contributed the code to support base class
+ chaining while remaining backward-compatible with old
+ versions of the library.
+
+
- Beman Dawes
+
- Contributed operators_test.cpp.
+
+
- Daryle Walker
+
- Contributed classes for the shift operators, equivalence,
+ partial ordering, and arithmetic conversions. Added the
+ grouped operator classes. Added helper classes for
+ input and output iterators.
+
+
+
+
+The changes in the library interface and
+recommended usage were motivated by some practical issues described
+below. The new version of the library is still backward-compatible with
+the former one (so you're not forced change any existing code),
+but the old usage is deprecated. Though it was arguably simpler and
+more intuitive than using base class chaining,
+it has been discovered that the old practice of deriving from multiple
+operator templates can cause the resulting classes to be much larger
+than they should be. Most modern C++ compilers significantly bloat the
+size of classes derived from multiple empty base classes, even though
+the base classes themselves have no state. For instance, the size of
+point<int>
from the example
+above was 12-24 bytes on various compilers for the Win32 platform,
+instead of the expected 8 bytes.
+
+Strictly speaking, it was not the library's fault--the language
+rules allow the compiler to apply the empty base class optimization in
+that situation. In principle an arbitrary number of empty base classes
+can be allocated at the same offset, provided that none of them have a
+common ancestor (see section 10.5 [class.derived] paragraph 5 of the
+standard). But the language definition also doesn't require
+implementations to do the optimization, and few if any of today's
+compilers implement it when multiple inheritance is involved. What's
+worse, it is very unlikely that implementors will adopt it as a future
+enhancement to existing compilers, because it would break binary
+compatibility between code generated by two different versions of the
+same compiler. As Matt Austern said, "One of the few times when you
+have the freedom to do this sort of thing is when you're targeting a new
+architecture...". On the other hand, many common compilers will use
+the empty base optimization for single inheritance hierarchies.
+
+Given the importance of the issue for the users of the library (which
+aims to be useful for writing light-weight classes like
+MyInt
or point<>
), and the forces
+described above, we decided to change the library interface so that the
+object size bloat could be eliminated even on compilers that support
+only the simplest form of the empty base class optimization. The
+current library interface is the result of those changes. Though the
+new usage is a bit more complicated than the old one, we think it's
+worth it to make the library more useful in real world. Alexy Gurtovoy
+contributed the code which supports the new usage idiom while allowing
+the library remain backward-compatible.
+
-Revised 10 Feb 2001
-© Copyright David Abrahams and Beman Dawes 1999-2000. Permission to copy,
-use, modify, sell and distribute this document is granted provided this
-copyright notice appears in all copies. This document is provided "as
-is" without express or implied warranty, and with no claim as to its
-suitability for any purpose.
+
+Revised: 20 May 2001
+
+Copyright © David Abrahams and Beman Dawes 1999-2001.
+Permission to copy, use, modify, sell and distribute this document is
+granted provided this copyright notice appears in all copies. This
+document is provided "as is" without express or implied
+warranty, and with no claim as to its suitability for any purpose.
-
diff --git a/operators_test.cpp b/operators_test.cpp
index a194521..ce03e87 100644
--- a/operators_test.cpp
+++ b/operators_test.cpp
@@ -8,18 +8,26 @@
// See http://www.boost.org for most recent version including documentation.
// 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)
// 17 Jun 00 Fix for broken compilers (Aleksey Gurtovoy)
// ?? ??? 00 Major update to randomly test all one- and two- argument forms by
-// wrapping integral types and comparing the results of operations to
-// the results for the raw types (David Abrahams)
+// wrapping integral types and comparing the results of operations
+// to the results for the raw types (David Abrahams)
// 12 Dec 99 Minor update, output confirmation message.
// 15 Nov 99 Initial version
-#include
-#include
-#include
-#include
+#define BOOST_INCLUDE_MAIN
+
+#include // for BOOST_MSVC
+#include // for boost::exit_success
+#include // for the tested items
+#include // for boost::minstd_rand
+#include // for main
+
+#include // for std::cout (std::endl indirectly)
namespace
@@ -28,14 +36,18 @@ namespace
int true_value(int x) { return x; }
long true_value(long 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 long true_value(unsigned long 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
- // compiler bugs
+ // The use of operators<> here tended to obscure
+ // interactions with certain compiler bugs
template
- class Wrapped1 : boost::operators >
+ class Wrapped1
+ : boost::operators >
+ , boost::shiftable >
{
public:
explicit Wrapped1( T v = T() ) : _value(v) {}
@@ -60,6 +72,10 @@ namespace
{ _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>>=(const Wrapped1& x)
+ { _value >>= x._value; return *this; }
Wrapped1& operator++() { ++_value; return *this; }
Wrapped1& operator--() { --_value; return *this; }
@@ -70,9 +86,11 @@ namespace
T true_value(Wrapped1 x) { return x.value(); }
template
- class Wrapped2 :
- boost::operators >,
- boost::operators2, U>
+ class Wrapped2
+ : boost::operators >
+ , boost::operators2, U>
+ , boost::shiftable1
+ , boost::shiftable2, U > >
{
public:
explicit Wrapped2( T v = T() ) : _value(v) {}
@@ -97,6 +115,10 @@ namespace
{ _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>>=(const Wrapped2& x)
+ { _value >>= x._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; }
private:
T _value;
@@ -118,203 +142,268 @@ namespace
template
T true_value(Wrapped2 x) { return x.value(); }
+ template
+ class Wrapped3
+ : boost::equivalent >
+ , boost::partially_ordered >
+ , boost::equality_comparable >
+ {
+ 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
+ T true_value(Wrapped3 x) { return x.value(); }
+
+ template
+ class Wrapped4
+ : boost::equality_comparable1
+ , boost::equivalent1
+ , boost::partially_ordered1 > > >
+ , boost::partially_ordered2, U
+ , boost::equivalent2, U
+ , boost::equality_comparable2, 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
+ T true_value(Wrapped4 x) { return x.value(); }
+
// MyInt uses only the single template-argument form of all_operators<>
typedef Wrapped1 MyInt;
typedef Wrapped2 MyLong;
+ typedef Wrapped3 MyChar;
+
+ typedef Wrapped4 MyShort;
+
template
void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- assert(true_value(y1) == true_value(y2));
- assert(true_value(x1) == true_value(x2));
+ BOOST_TEST( true_value(y1) == true_value(y2) );
+ BOOST_TEST( true_value(x1) == true_value(x2) );
}
template
void test_less_than_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- assert((x1 < y1) == (x2 < y2));
- assert((x1 <= y1) == (x2 <= y2));
- assert((x1 >= y1) == (x2 >= y2));
- assert((x1 > y1) == (x2 > y2));
+ BOOST_TEST( (x1 < y1) == (x2 < y2) );
+ BOOST_TEST( (x1 <= y1) == (x2 <= y2) );
+ BOOST_TEST( (x1 >= y1) == (x2 >= y2) );
+ BOOST_TEST( (x1 > y1) == (x2 > y2) );
}
template
void test_less_than_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_less_than_comparable_aux(x1, y1, x2, y2);
- test_less_than_comparable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_less_than_comparable_aux( x1, y1, x2, y2 );
+ test_less_than_comparable_aux( y1, x1, y2, x2 );
}
template
void test_equality_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- assert((x1 == y1) == (x2 == y2));
- assert((x1 != y1) == (x2 != y2));
+ BOOST_TEST( (x1 == y1) == (x2 == y2) );
+ BOOST_TEST( (x1 != y1) == (x2 != y2) );
}
template
void test_equality_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_equality_comparable_aux(x1, y1, x2, y2);
- test_equality_comparable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_equality_comparable_aux( x1, y1, x2, y2 );
+ test_equality_comparable_aux( y1, x1, y2, x2 );
}
template
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
void test_multipliable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_multipliable_aux(x1, y1, x2, y2);
- test_multipliable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_multipliable_aux( x1, y1, x2, y2 );
+ test_multipliable_aux( y1, x1, y2, x2 );
}
template
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
void test_addable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_addable_aux(x1, y1, x2, y2);
- test_addable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_addable_aux( x1, y1, x2, y2 );
+ test_addable_aux( y1, x1, y2, x2 );
}
template
void test_subtractable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- assert((x1 - y1).value() == x2 - y2);
+ sanity_check( x1, y1, x2, y2 );
+ BOOST_TEST( (x1 - y1).value() == (x2 - y2) );
}
template
void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- if (y2 != 0)
- assert((x1 / y1).value() == x2 / y2);
+ sanity_check( x1, y1, x2, y2 );
+ if ( y2 != 0 )
+ BOOST_TEST( (x1 / y1).value() == (x2 / y2) );
}
template
void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- if (y2 != 0)
- assert((x1 / y1).value() == x2 / y2);
+ sanity_check( x1, y1, x2, y2 );
+ if ( y2 != 0 )
+ BOOST_TEST( (x1 % y1).value() == (x2 % y2) );
}
template
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
void test_xorable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_xorable_aux(x1, y1, x2, y2);
- test_xorable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_xorable_aux( x1, y1, x2, y2 );
+ test_xorable_aux( y1, x1, y2, x2 );
}
template
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
void test_andable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_andable_aux(x1, y1, x2, y2);
- test_andable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_andable_aux( x1, y1, x2, y2 );
+ test_andable_aux( y1, x1, y2, x2 );
}
template
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
void test_orable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- sanity_check(x1, y1, x2, y2);
- test_orable_aux(x1, y1, x2, y2);
- test_orable_aux(y1, x1, y2, x2);
+ sanity_check( x1, y1, x2, y2 );
+ test_orable_aux( x1, y1, x2, y2 );
+ test_orable_aux( y1, x1, y2, x2 );
+ }
+
+ template
+ 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
+ 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
void test_incrementable(X1 x1, X2 x2)
{
- sanity_check(x1, x1, x2, x2);
- assert(x1++.value() == x2++);
- assert(x1.value() == x2);
+ sanity_check( x1, x1, x2, x2 );
+ BOOST_TEST( (x1++).value() == x2++ );
+ BOOST_TEST( x1.value() == x2 );
}
template
void test_decrementable(X1 x1, X2 x2)
{
- sanity_check(x1, x1, x2, x2);
- assert(x1--.value() == x2--);
- assert(x1.value() == x2);
+ sanity_check( x1, x1, x2, x2 );
+ BOOST_TEST( (x1--).value() == x2-- );
+ BOOST_TEST( x1.value() == x2 );
}
template
void test_all(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
- test_less_than_comparable(x1, y1, x2, y2);
- test_equality_comparable(x1, y1, x2, y2);
- test_multipliable(x1, y1, x2, y2);
- test_addable(x1, y1, x2, y2);
- test_subtractable(x1, y1, x2, y2);
- test_dividable(x1, y1, x2, y2);
- test_modable(x1, y1, x2, y2);
- test_xorable(x1, y1, x2, y2);
- test_andable(x1, y1, x2, y2);
- test_orable(x1, y1, x2, y2);
- test_incrementable(x1, x2);
- test_decrementable(x1, x2);
+ test_less_than_comparable( x1, y1, x2, y2 );
+ test_equality_comparable( x1, y1, x2, y2 );
+ test_multipliable( x1, y1, x2, y2 );
+ test_addable( x1, y1, x2, y2 );
+ test_subtractable( x1, y1, x2, y2 );
+ test_dividable( x1, y1, x2, y2 );
+ test_modable( x1, y1, x2, y2 );
+ test_xorable( x1, y1, x2, y2 );
+ test_andable( x1, y1, x2, y2 );
+ test_orable( x1, y1, x2, y2 );
+ test_left_shiftable( x1, y1, x2, y2 );
+ test_right_shiftable( x1, y1, x2, y2 );
+ test_incrementable( x1, x2 );
+ test_decrementable( x1, x2 );
}
template
struct tester
{
- void operator()(boost::min_rand& randomizer) const
+ void operator()(boost::minstd_rand& randomizer) const
{
- Big b1 = Big(randomizer());
- Big b2 = Big(randomizer());
- Small s = Small(randomizer());
+ Big b1 = Big( randomizer() );
+ Big b2 = Big( randomizer() );
+ Small s = Small( randomizer() );
- test_all(Wrapped1(b1), Wrapped1(b2), b1, b2);
- test_all(Wrapped2(b1), s, b1, s);
+ test_all( Wrapped1(b1), Wrapped1(b2), b1, b2 );
+ test_all( Wrapped2(b1), s, b1, s );
}
};
// added as a regression test. We had a bug which this uncovered.
struct Point
- : boost::addable >
+ : boost::addable >
{
Point( int h, int v ) : h(h), v(v) {}
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 ) { h -= rhs.h; v -= rhs.v; return *this; }
+ const Point& operator+=( const Point& rhs )
+ { 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 v;
};
+
} // unnamed namespace
@@ -340,20 +429,25 @@ template Wrapped2;
template Wrapped2;
#endif
-#ifdef NDEBUG
-#error This program is pointless when NDEBUG disables assert()!
-#endif
+#define PRIVATE_EXPR_TEST(e, t) BOOST_TEST( ((e), (t)) )
-int main()
+
+int
+test_main( int , char * [] )
{
+ using std::cout;
+ using std::endl;
+
// Regression test.
Point x;
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)
{
- boost::min_rand r;
+ boost::minstd_rand r;
tester()(r);
tester()(r);
tester()(r);
@@ -367,115 +461,197 @@ int main()
tester()(r);
}
+ cout << "Did random tester loop." << endl;
+
MyInt i1(1);
MyInt i2(2);
MyInt i;
- assert( i1.value() == 1 );
- assert( i2.value() == 2 );
- assert( i.value() == 0 );
+ BOOST_TEST( i1.value() == 1 );
+ BOOST_TEST( i2.value() == 2 );
+ BOOST_TEST( i.value() == 0 );
- i = i2;
- 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 );
+ cout << "Created MyInt objects.\n";
- i = i1 + i2; assert( i.value() == 3 );
- i = i + i2; assert( i.value() == 5 );
- i = i - i1; assert( i.value() == 4 );
- i = i * i2; assert( i.value() == 8 );
- i = i / i2; assert( i.value() == 4 );
- i = i % (i - i1); assert( i.value() == 1 );
- i = i2 + i2; assert( i.value() == 4 );
- i = i1 | i2 | i; assert( i.value() == 7 );
- i = i & i2; assert( i.value() == 2 );
- i = i + i1; assert( i.value() == 3 );
- i = i ^ i1; assert( i.value() == 2 );
- i = (i+i1)*(i2|i1); assert( i.value() == 9 );
+ PRIVATE_EXPR_TEST( (i = i2), (i.value() == 2) );
+
+ BOOST_TEST( i2 == i );
+ BOOST_TEST( i1 != i2 );
+ BOOST_TEST( i1 < i2 );
+ BOOST_TEST( i1 <= i2 );
+ BOOST_TEST( i <= i2 );
+ BOOST_TEST( i2 > i1 );
+ BOOST_TEST( i2 >= i1 );
+ BOOST_TEST( i2 >= i );
+
+ 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 j2(2);
MyLong j;
- assert( j1.value() == 1 );
- assert( j2.value() == 2 );
- assert( j.value() == 0 );
+ BOOST_TEST( j1.value() == 1 );
+ BOOST_TEST( j2.value() == 2 );
+ BOOST_TEST( j.value() == 0 );
- j = j2;
- 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 );
+ cout << "Created MyLong objects.\n";
- assert( (j1 + 2) == 3 );
- assert( (1 + j2) == 3 );
- j = j1 + j2; assert( j.value() == 3 );
+ PRIVATE_EXPR_TEST( (j = j2), (j.value() == 2) );
- assert( (j + 2) == 5 );
- assert( (3 + j2) == 5 );
- j = j + j2; assert( j.value() == 5 );
+ BOOST_TEST( j2 == j );
+ BOOST_TEST( 2 == j );
+ 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 );
- j = j - j1; assert( j.value() == 4 );
+ BOOST_TEST( (j + 2) == 5 );
+ BOOST_TEST( (3 + j2) == 5 );
+ PRIVATE_EXPR_TEST( (j = j + j2), (j.value() == 5) );
- assert( (j * 2) == 8 );
- assert( (4 * j2) == 8 );
- j = j * j2; assert( j.value() == 8 );
+ BOOST_TEST( (j - 1) == 4 );
+ PRIVATE_EXPR_TEST( (j = j - j1), (j.value() == 4) );
- assert( (j / 2) == 4 );
- j = j / j2; assert( j.value() == 4 );
+ BOOST_TEST( (j * 2) == 8 );
+ BOOST_TEST( (4 * j2) == 8 );
+ PRIVATE_EXPR_TEST( (j = j * j2), (j.value() == 8) );
- assert( (j % 3) == 1 );
- j = j % (j - j1); assert( j.value() == 1 );
+ BOOST_TEST( (j / 2) == 4 );
+ 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 );
- assert( (j1 | 2 | j) == 7 );
- assert( (j1 | j2 | 4) == 7 );
- j = j1 | j2 | j; assert( j.value() == 7 );
+ PRIVATE_EXPR_TEST( (j = j2 + j2), (j.value() == 4) );
- assert( (7 & j2) == 2 );
- assert( (j & 2) == 2 );
- j = j & j2; assert( j.value() == 2 );
+ BOOST_TEST( (1 | j2 | j) == 7 );
+ BOOST_TEST( (j1 | 2 | j) == 7 );
+ 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 );
- assert( (j ^ 1) == 2 );
- j = j ^ j1; assert( j.value() == 2 );
+ PRIVATE_EXPR_TEST( (j = j | j1), (j.value() == 3) );
- 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";
- return 0;
+ PRIVATE_EXPR_TEST( (j = ( j + j1 ) * ( j2 | j1 )), (j.value() == 9) );
+
+ 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;
}