committing Daryle and Helmut's changes

[SVN r11813]
This commit is contained in:
Dave Abrahams 2001-11-29 21:22:52 +00:00
parent 3e9d0f80c2
commit 18944572b7
3 changed files with 697 additions and 65 deletions

View File

@ -9,6 +9,11 @@
// 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
// 28 Sep 01 Factored out iterator operator groups. (Daryle Walker)
// 27 Aug 01 'left' form for non commutative operators added;
// additional classes for groups of related operators added;
// workaround for empty base class optimization
// bug of GCC 3.0 (Helmut Zeisel)
// 25 Jun 01 output_iterator_helper changes: removed default template // 25 Jun 01 output_iterator_helper changes: removed default template
// parameters, added support for self-proxying, additional // parameters, added support for self-proxying, additional
// documentation and tests (Aleksey Gurtovoy) // documentation and tests (Aleksey Gurtovoy)
@ -81,7 +86,14 @@
namespace boost { namespace boost {
namespace detail { namespace detail {
// Helmut Zeisel, empty base class optimization bug with GCC 3.0.0
#if defined(__GNUCC__) && __GNUC__==3 && __GNUC_MINOR__==0 && __GNU_PATCHLEVEL__==0
class empty_base {
bool dummy;
};
#else
class empty_base {}; class empty_base {};
#endif
} // namespace detail } // namespace detail
} // namespace boost } // namespace boost
@ -168,6 +180,13 @@ struct subtractable2 : B
friend T operator-(T x, const U& y) { return x -= y; } friend T operator-(T x, const U& y) { return x -= y; }
}; };
template <class T, class U, class B = ::boost::detail::empty_base>
struct subtractable2_left : B
{
friend T operator-(const U& x, const T& y)
{ T result(x); return result -= y; }
};
template <class T, class B = ::boost::detail::empty_base> template <class T, class B = ::boost::detail::empty_base>
struct subtractable1 : B struct subtractable1 : B
{ {
@ -180,6 +199,13 @@ struct dividable2 : B
friend T operator/(T x, const U& y) { return x /= y; } friend T operator/(T x, const U& y) { return x /= y; }
}; };
template <class T, class U, class B = ::boost::detail::empty_base>
struct dividable2_left : B
{
friend T operator/(const U& x, const T& y)
{ T result(x); return result /= y; }
};
template <class T, class B = ::boost::detail::empty_base> template <class T, class B = ::boost::detail::empty_base>
struct dividable1 : B struct dividable1 : B
{ {
@ -192,6 +218,13 @@ struct modable2 : B
friend T operator%(T x, const U& y) { return x %= y; } friend T operator%(T x, const U& y) { return x %= y; }
}; };
template <class T, class U, class B = ::boost::detail::empty_base>
struct modable2_left : B
{
friend T operator%(const U& x, const T& y)
{ T result(x); return result %= y; }
};
template <class T, class B = ::boost::detail::empty_base> template <class T, class B = ::boost::detail::empty_base>
struct modable1 : B struct modable1 : B
{ {
@ -463,12 +496,121 @@ struct shiftable1
, right_shiftable1<T, B , right_shiftable1<T, B
> > {}; > > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct ring_operators2
: additive2<T, U
, subtractable2_left<T, U
, multipliable2<T, U, B
> > > {};
template <class T, class B = ::boost::detail::empty_base>
struct ring_operators1
: additive1<T
, multipliable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct ordered_ring_operators2
: ring_operators2<T, U
, totally_ordered2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct ordered_ring_operators1
: ring_operators1<T
, totally_ordered1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct field_operators2
: ring_operators2<T, U
, dividable2<T, U
, dividable2_left<T, U, B
> > > {};
template <class T, class B = ::boost::detail::empty_base>
struct field_operators1
: ring_operators1<T
, dividable1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct ordered_field_operators2
: field_operators2<T, U
, totally_ordered2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct ordered_field_operators1
: field_operators1<T
, totally_ordered1<T, B
> > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct euclidian_ring_operators2
: ring_operators2<T, U
, dividable2<T, U
, dividable2_left<T, U
, modable2<T, U
, modable2_left<T, U, B
> > > > > {};
template <class T, class B = ::boost::detail::empty_base>
struct euclidian_ring_operators1
: ring_operators1<T
, dividable1<T
, modable1<T, B
> > > {};
template <class T, class U, class B = ::boost::detail::empty_base>
struct ordered_euclidian_ring_operators2
: totally_ordered2<T, U
, euclidian_ring_operators2<T, U, B
> > {};
template <class T, class B = ::boost::detail::empty_base>
struct ordered_euclidian_ring_operators1
: totally_ordered1<T
, euclidian_ring_operators1<T, B
> > {};
template <class T, class P, class B = ::boost::detail::empty_base>
struct input_iteratable
: equality_comparable1<T
, incrementable<T
, dereferenceable<T, P, B
> > > {};
template <class T, class B = ::boost::detail::empty_base>
struct output_iteratable
: incrementable<T, B
> {};
template <class T, class P, class B = ::boost::detail::empty_base>
struct forward_iteratable
: input_iteratable<T, P, B
> {};
template <class T, class P, class B = ::boost::detail::empty_base>
struct bidirectional_iteratable
: forward_iteratable<T, P
, decrementable<T, B
> > {};
template <class T, class P, class D, class R, class B = ::boost::detail::empty_base>
struct random_access_iteratable
: bidirectional_iteratable<T, P
, totally_ordered1<T
, additive2<T, D
, indexable<T, D, R, 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_TEMPLATE3 - // BOOST_IMPORT_TEMPLATE1 .. BOOST_IMPORT_TEMPLATE4 -
// //
// 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
@ -479,6 +621,7 @@ struct shiftable1
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
// The template is already in boost so we have nothing to do. // The template is already in boost so we have nothing to do.
# define BOOST_IMPORT_TEMPLATE4(template_name)
# define BOOST_IMPORT_TEMPLATE3(template_name) # define BOOST_IMPORT_TEMPLATE3(template_name)
# define BOOST_IMPORT_TEMPLATE2(template_name) # define BOOST_IMPORT_TEMPLATE2(template_name)
# define BOOST_IMPORT_TEMPLATE1(template_name) # define BOOST_IMPORT_TEMPLATE1(template_name)
@ -489,6 +632,7 @@ struct shiftable1
// Bring the names in with a using-declaration // Bring the names in with a using-declaration
// to avoid stressing the compiler. // to avoid stressing the compiler.
# define BOOST_IMPORT_TEMPLATE4(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE3(template_name) using ::template_name; # define BOOST_IMPORT_TEMPLATE3(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name; # define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name;
# define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name; # define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name;
@ -497,6 +641,10 @@ struct shiftable1
// Otherwise, because a Borland C++ 5.5 bug prevents a using declaration // Otherwise, because a Borland C++ 5.5 bug prevents a using declaration
// from working, we are forced to use inheritance for that compiler. // from working, we are forced to use inheritance for that compiler.
# define BOOST_IMPORT_TEMPLATE4(template_name) \
template <class T, class U, class V, class W, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, U, V, W, B> {};
# define BOOST_IMPORT_TEMPLATE3(template_name) \ # define BOOST_IMPORT_TEMPLATE3(template_name) \
template <class T, class U, class V, class B = ::boost::detail::empty_base> \ template <class T, class U, class V, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, U, V, B> {}; struct template_name : ::template_name<T, U, V, B> {};
@ -542,6 +690,15 @@ template<class T> struct is_chained_base {
} // namespace boost } // namespace boost
// Import a 4-type-argument operator template into boost (if neccessary) and
// provide a specialization of 'is_chained_base<>' for it.
# define BOOST_OPERATOR_TEMPLATE4(template_name4) \
BOOST_IMPORT_TEMPLATE4(template_name4) \
template<class T, class U, class V, class W, class B> \
struct is_chained_base< ::boost::template_name4<T, U, V, W, B> > { \
typedef ::boost::detail::true_t value; \
};
// Import a 3-type-argument operator template into boost (if neccessary) and // Import a 3-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_TEMPLATE3(template_name3) \ # define BOOST_OPERATOR_TEMPLATE3(template_name3) \
@ -610,6 +767,8 @@ BOOST_OPERATOR_TEMPLATE1(template_name##1)
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
# define BOOST_OPERATOR_TEMPLATE4(template_name4) \
BOOST_IMPORT_TEMPLATE4(template_name4)
# define BOOST_OPERATOR_TEMPLATE3(template_name3) \ # define BOOST_OPERATOR_TEMPLATE3(template_name3) \
BOOST_IMPORT_TEMPLATE3(template_name3) BOOST_IMPORT_TEMPLATE3(template_name3)
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \ # define BOOST_OPERATOR_TEMPLATE2(template_name2) \
@ -632,8 +791,11 @@ BOOST_OPERATOR_TEMPLATE(equality_comparable)
BOOST_OPERATOR_TEMPLATE(multipliable) BOOST_OPERATOR_TEMPLATE(multipliable)
BOOST_OPERATOR_TEMPLATE(addable) BOOST_OPERATOR_TEMPLATE(addable)
BOOST_OPERATOR_TEMPLATE(subtractable) BOOST_OPERATOR_TEMPLATE(subtractable)
BOOST_OPERATOR_TEMPLATE2(subtractable2_left)
BOOST_OPERATOR_TEMPLATE(dividable) BOOST_OPERATOR_TEMPLATE(dividable)
BOOST_OPERATOR_TEMPLATE2(dividable2_left)
BOOST_OPERATOR_TEMPLATE(modable) BOOST_OPERATOR_TEMPLATE(modable)
BOOST_OPERATOR_TEMPLATE2(modable2_left)
BOOST_OPERATOR_TEMPLATE(xorable) BOOST_OPERATOR_TEMPLATE(xorable)
BOOST_OPERATOR_TEMPLATE(andable) BOOST_OPERATOR_TEMPLATE(andable)
BOOST_OPERATOR_TEMPLATE(orable) BOOST_OPERATOR_TEMPLATE(orable)
@ -658,14 +820,27 @@ BOOST_OPERATOR_TEMPLATE(integer_arithmetic)
BOOST_OPERATOR_TEMPLATE(bitwise) BOOST_OPERATOR_TEMPLATE(bitwise)
BOOST_OPERATOR_TEMPLATE1(unit_steppable) BOOST_OPERATOR_TEMPLATE1(unit_steppable)
BOOST_OPERATOR_TEMPLATE(shiftable) BOOST_OPERATOR_TEMPLATE(shiftable)
BOOST_OPERATOR_TEMPLATE(ring_operators)
BOOST_OPERATOR_TEMPLATE(ordered_ring_operators)
BOOST_OPERATOR_TEMPLATE(field_operators)
BOOST_OPERATOR_TEMPLATE(ordered_field_operators)
BOOST_OPERATOR_TEMPLATE(euclidian_ring_operators)
BOOST_OPERATOR_TEMPLATE(ordered_euclidian_ring_operators)
BOOST_OPERATOR_TEMPLATE2(input_iteratable)
BOOST_OPERATOR_TEMPLATE1(output_iteratable)
BOOST_OPERATOR_TEMPLATE2(forward_iteratable)
BOOST_OPERATOR_TEMPLATE2(bidirectional_iteratable)
BOOST_OPERATOR_TEMPLATE4(random_access_iteratable)
#undef BOOST_OPERATOR_TEMPLATE #undef BOOST_OPERATOR_TEMPLATE
#undef BOOST_OPERATOR_TEMPLATE4
#undef BOOST_OPERATOR_TEMPLATE3 #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 #undef BOOST_IMPORT_TEMPLATE3
#undef BOOST_IMPORT_TEMPLATE4
// 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.
@ -699,20 +874,18 @@ template <class T,
class P = V const *, class P = V const *,
class R = V const &> class R = V const &>
struct input_iterator_helper struct input_iterator_helper
: equality_comparable1<T : input_iteratable<T, P
, incrementable<T
, dereferenceable<T, P
, boost::iterator<std::input_iterator_tag, V, D, P, R , boost::iterator<std::input_iterator_tag, V, D, P, R
> > > > {}; > > {};
template<class Derived> template<class T>
struct output_iterator_helper struct output_iterator_helper
: boost::incrementable<Derived : output_iteratable<T
, boost::iterator<std::output_iterator_tag, void, void, void, void , boost::iterator<std::output_iterator_tag, void, void, void, void
> > > >
{ {
Derived& operator*() { return static_cast<Derived&>(*this); } T& operator*() { return static_cast<T&>(*this); }
Derived& operator++() { return static_cast<Derived&>(*this); } T& operator++() { return static_cast<T&>(*this); }
}; };
template <class T, template <class T,
@ -721,11 +894,9 @@ template <class T,
class P = V*, class P = V*,
class R = V&> class R = V&>
struct forward_iterator_helper struct forward_iterator_helper
: equality_comparable1<T : forward_iteratable<T, P
, incrementable<T
, 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,
class V, class V,
@ -733,11 +904,9 @@ template <class T,
class P = V*, class P = V*,
class R = V&> class R = V&>
struct bidirectional_iterator_helper struct bidirectional_iterator_helper
: equality_comparable1<T : bidirectional_iteratable<T, P
, unit_steppable<T
, 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,
@ -745,13 +914,9 @@ 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
: totally_ordered1<T : random_access_iteratable<T, P, D, R
, unit_steppable<T
, dereferenceable<T, P
, additive2<T, D
, indexable<T, D, R
, boost::iterator<std::random_access_iterator_tag, V, D, P, R , boost::iterator<std::random_access_iterator_tag, V, D, P, R
> > > > > > > >
{ {
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;

View File

@ -30,7 +30,11 @@ provided by the class.</p>
</ul></li> </ul></li>
<li><a href="#usage">Usage</a> <li><a href="#usage">Usage</a>
<ul> <ul>
<li><a href="#two_arg">Two-Argument Template Forms</a></li> <li><a href="#two_arg">Two-Argument Template Forms</a>
<ul>
<li><a href="#two_arg_gen">General Considerations</a></li>
<li><a href="#mixed_arithmetics">Mixed arithmetics</a></li>
</ul></li>
<li><a href="#chaining">Base Class Chaining and Object Size</a></li> <li><a href="#chaining">Base Class Chaining and Object Size</a></li>
<li><a href="#explicit_instantiation">Separate, Explicit <li><a href="#explicit_instantiation">Separate, Explicit
Instantiation</a></li> Instantiation</a></li>
@ -39,7 +43,10 @@ provided by the class.</p>
<li><a href="#example">Example</a></li> <li><a href="#example">Example</a></li>
<li><a href="#arithmetic">Arithmetic operators</a> <li><a href="#arithmetic">Arithmetic operators</a>
<ul> <ul>
<li><a href="#smpl_oprs">Simple Arithmetic Operators</a></li> <li><a href="#smpl_oprs">Simple Arithmetic Operators</a>
<ul>
<li><a href="#ordering">Ordering Note</a></li>
</ul></li>
<li><a href="#grpd_oprs">Grouped Arithmetic Operators</a></li> <li><a href="#grpd_oprs">Grouped Arithmetic Operators</a></li>
<li><a href="#ex_oprs">Example Templates</a></li> <li><a href="#ex_oprs">Example Templates</a></li>
<li><a href="#a_demo">Arithmetic Operators Demonstration <li><a href="#a_demo">Arithmetic Operators Demonstration
@ -49,8 +56,12 @@ provided by the class.</p>
Helpers</a> Helpers</a>
<ul> <ul>
<li><a href="#dereference">Dereference operators</a></li> <li><a href="#dereference">Dereference operators</a></li>
<li><a href="#iterator">Iterator Helpers</a></li> <li><a href="#grpd_iter_oprs">Grouped Iterator Operators</a></li>
<li><a href="#iterator_helpers_notes">Iterator Helper Notes</a></li> <li><a href="#iterator">Iterator Helpers</a>
<ul>
<li><a href="#iterator_helpers_notes">Iterator Helper
Notes</a></li>
</ul></li>
<li><a href="#i_demo">Iterator Demonstration and Test <li><a href="#i_demo">Iterator Demonstration and Test
Program</a></li> Program</a></li>
</ul></li> </ul></li>
@ -151,6 +162,8 @@ domains, <i>i.e.</i> eventually more useful.</p>
<h3><a name="two_arg">Two-Argument</a> Template Forms</h3> <h3><a name="two_arg">Two-Argument</a> Template Forms</h3>
<h4><a name="two_arg_gen">General Considerations</a></h4>
<p>The arguments to a binary operator commonly have identical types, but <p>The arguments to a binary operator commonly have identical types, but
it is not unusual to want to define operators which combine different it is not unusual to want to define operators which combine different
types. For <a href="#example">example</a>, one might want to multiply a types. For <a href="#example">example</a>, one might want to multiply a
@ -176,6 +189,46 @@ trailing <code>'1'</code> are provided for symmetry and to enable
certain applications of the <a href="#chaining">base class chaining</a> certain applications of the <a href="#chaining">base class chaining</a>
technique.</p> technique.</p>
<h4><a name="mixed_arithmetics">Mixed Arithmetics</a></h4>
<p>Another application of the two-argument template forms is for
mixed arithmetics between a type <code>T</code> and a type <code>U</code>
that is convertible to <code>T</code>. In this case there are two ways
where the two-argument template forms are helpful: one is to provide
the respective signatures for operator overloading, the second is
performance.</p>
<p>With respect to the operator overloading assume <i>e.g.</i> that
<code>U</code> is <code>int</code>, that <code>T</code> is an user-defined
unlimited integer type, and that <code>double operator-(double, const
T&amp;)</code> exists. If one wants to compute <code>int - T</code> and
does not provide <code>T operator-(int, const T&amp;)</code>, the
compiler will consider <code>double operator-(double, const T&amp;)</code>
to be a better match than <code>T operator-(const T&amp;, const
T&amp;)</code>, which will probably be different from the user's intention.
To define a complete set of operator signatures, additional 'left' forms
of the two-argument template forms are provided (<code><a
href="#subtractable2_left">subtractable2_left&lt;T, U&gt;</a></code>,
<code><a href="#dividable2_left">dividable2_left&lt;T, U&gt;</a></code>,
<code><a href="#modable2_left">modable2_left&lt;T, U&gt;</a></code>) that
define the signatures for non-commutative operators where <code>U</code>
appears on the left hand side (<code>operator-(const U&amp;, const
T&amp;)</code>, <code>operator/(const U&amp;, const T&amp;)</code>,
<code>operator%(const U&amp;, const T&amp;)</code>).</p>
<p>With respect to the performance observe that when one uses the
single type binary operator for mixed type arithmetics, the type
<code>U</code> argument has to be converted to type <code>T</code>. In
practice, however, there are often more efficient implementations of,
say <code>T::operator-=(const U&amp;)</code> that avoid unnecessary
conversions from <code>U</code> to <code>T</code>. The two-argument
template forms of the arithmetic operator create additional operator
interfaces that use these more efficient implementations. There is, however,
no performance gain in the 'left' forms: they still need a conversion
from <code>U</code> to <code>T</code> and have an implementation
equivalent to the code that would be automatically created by the compiler
if it considered the single type binary operator to be the best match.</p>
<h3>Base Class <a name="chaining">Chaining</a> and Object Size</h3> <h3>Base Class <a name="chaining">Chaining</a> and Object Size</h3>
<p>Every operator class template, except the <a href="#ex_oprs">arithmetic <p>Every operator class template, except the <a href="#ex_oprs">arithmetic
@ -419,6 +472,12 @@ for the <a href="#chaining">base class chaining</a> technique.
<td><code>t -= u</code>.<br> <td><code>t -= u</code>.<br>
Return convertible to <code>T</code>.</td> Return convertible to <code>T</code>.</td>
</tr> </tr>
<tr>
<td><code><a name="subtractable2_left">subtractable2_left&lt;T, U&gt;</a></code></td>
<td><code>T operator-(const U&amp;, const T&amp;)</code></td>
<td><code>T temp(u); temp -= t</code>.<br>
Return convertible to <code>T</code>.</td>
</tr>
<tr> <tr>
<td><code><a name="multipliable1">multipliable&lt;T&gt;</a></code><br> <td><code><a name="multipliable1">multipliable&lt;T&gt;</a></code><br>
<code>multipliable1&lt;T&gt;</code></td> <code>multipliable1&lt;T&gt;</code></td>
@ -448,6 +507,12 @@ for the <a href="#chaining">base class chaining</a> technique.
<td><code>t /= u</code>.<br> <td><code>t /= u</code>.<br>
Return convertible to <code>T</code>.</td> Return convertible to <code>T</code>.</td>
</tr> </tr>
<tr>
<td><code><a name="dividable2_left">dividable2_left&lt;T, U&gt;</a></code></td>
<td><code>T operator/(const U&amp;, const T&amp;)</code></td>
<td><code>T temp(u); temp /= t</code>.<br>
Return convertible to <code>T</code>.</td>
</tr>
<tr> <tr>
<td><code><a name="modable1">modable&lt;T&gt;</a></code><br> <td><code><a name="modable1">modable&lt;T&gt;</a></code><br>
<code>modable1&lt;T&gt;</code></td> <code>modable1&lt;T&gt;</code></td>
@ -462,6 +527,12 @@ for the <a href="#chaining">base class chaining</a> technique.
<td><code>t %= u</code>.<br> <td><code>t %= u</code>.<br>
Return convertible to <code>T</code>.</td> Return convertible to <code>T</code>.</td>
</tr> </tr>
<tr>
<td><code><a name="modable2_left">modable2_left&lt;T, U&gt;</a></code></td>
<td><code>T operator%(const U&amp;, const T&amp;)</code></td>
<td><code>T temp(u); temp %= t</code>.<br>
Return convertible to <code>T</code>.</td>
</tr>
<tr> <tr>
<td><code><a name="orable1">orable&lt;T&gt;</a></code><br> <td><code><a name="orable1">orable&lt;T&gt;</a></code><br>
<code>orable1&lt;T&gt;</code></td> <code>orable1&lt;T&gt;</code></td>
@ -588,8 +659,9 @@ for the <a href="#chaining">base class chaining</a> technique.
</tr> </tr>
</table> </table>
<p><strong><a name="ordering">Ordering Note</a></strong><br> <h4><a name="ordering">Ordering</a> Note</h4>
The <code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code>
<p>The <code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code>
and <code><a href="#partially_ordered1">partially_ordered&lt;T&gt;</a></code> and <code><a href="#partially_ordered1">partially_ordered&lt;T&gt;</a></code>
templates provide the same set of operations. However, the workings of templates provide the same set of operations. However, the workings of
<code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code> <code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code>
@ -771,6 +843,109 @@ optional template parameter <code>B</code>, which is not shown, for the
<li><code><a href="#right_shiftable2">right_shiftable&lt;T, U&gt;</a></code></li> <li><code><a href="#right_shiftable2">right_shiftable&lt;T, U&gt;</a></code></li>
</ul></td> </ul></td>
</tr> </tr>
<tr>
<td><code><a name="ring_operators1">ring_operators&lt;T&gt;</a></code><br>
<code>ring_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#additive1">additive&lt;T&gt;</a></code></li>
<li><code><a href="#multipliable1">multipliable&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ring_operators2">ring_operators&lt;T, U&gt;</a></code><br>
<code>ring_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#additive2">additive&lt;T, U&gt;</a></code></li>
<li><code><a href="#subtractable2_left">subtractable2_left&lt;T, U&gt;</a></code></li>
<li><code><a href="#multipliable2">multipliable&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_ring_operators1">ordered_ring_operators&lt;T&gt;</a></code><br>
<code>ordered_ring_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators1">ring_operators&lt;T&gt;</a></code></li>
<li><code><a href="#totally_ordered1">totally_ordered&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_ring_operators2">ordered_ring_operators&lt;T, U&gt;</a></code><br>
<code>ordered_ring_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators2">ring_operators&lt;T, U&gt;</a></code></li>
<li><code><a href="#totally_ordered2">totally_ordered&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="field_operators1">field_operators&lt;T&gt;</a></code><br>
<code>field_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators1">ring_operators&lt;T&gt;</a></code></li>
<li><code><a href="#dividable1">dividable&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="field_operators2">field_operators&lt;T, U&gt;</a></code><br>
<code>field_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators2">ring_operators&lt;T, U&gt;</a></code></li>
<li><code><a href="#dividable2">dividable&lt;T, U&gt;</a></code></li>
<li><code><a href="#dividable2_left">dividable2_left&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_field_operators1">ordered_field_operators&lt;T&gt;</a></code><br>
<code>ordered_field_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#field_operators1">field_operators&lt;T&gt;</a></code></li>
<li><code><a href="#totally_ordered1">totally_ordered&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_field_operators2">ordered_field_operators&lt;T, U&gt;</a></code><br>
<code>ordered_field_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#field_operators2">field_operators&lt;T, U&gt;</a></code></li>
<li><code><a href="#totally_ordered2">totally_ordered&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="euclidian_ring_operators1">euclidian_ring_operators&lt;T&gt;</a></code><br>
<code>euclidian_ring_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators1">ring_operators&lt;T&gt;</a></code></li>
<li><code><a href="#dividable1">dividable&lt;T&gt;</a></code></li>
<li><code><a href="#modable1">modable&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="euclidian_ring_operators2">euclidian_ring_operators&lt;T, U&gt;</a></code><br>
<code>euclidian_ring_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#ring_operators2">ring_operators&lt;T, U&gt;</a></code></li>
<li><code><a href="#dividable2">dividable&lt;T, U&gt;</a></code></li>
<li><code><a href="#dividable2_left">dividable2_left&lt;T, U&gt;</a></code></li>
<li><code><a href="#modable2">modable&lt;T, U&gt;</a></code></li>
<li><code><a href="#modable2_left">modable2_left&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_euclidian_ring_operators1">ordered_euclidian_ring_operators&lt;T&gt;</a></code><br>
<code>ordered_euclidian_ring_operators1&lt;T&gt;</code></td>
<td><ul>
<li><code><a href="#euclidian_ring_operators1">euclidian_ring_operators&lt;T&gt;</a></code></li>
<li><code><a href="#totally_ordered1">totally_ordered&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="ordered_euclidian_ring_operators2">ordered_euclidian_ring_operators&lt;T, U&gt;</a></code><br>
<code>ordered_euclidian_ring_operators2&lt;T, U&gt;</code></td>
<td><ul>
<li><code><a href="#euclidian_ring_operators2">euclidian_ring_operators&lt;T, U&gt;</a></code></li>
<li><code><a href="#totally_ordered2">totally_ordered&lt;T, U&gt;</a></code></li>
</ul></td>
</tr>
</table> </table>
<h3><a name="ex_oprs">Example</a> Templates</h3> <h3><a name="ex_oprs">Example</a> Templates</h3>
@ -888,19 +1063,87 @@ href="#chaining">base class chaining</a>.</p>
</tr> </tr>
</table> </table>
<h3><a name="iterator">Iterator</a> Helpers</h3> <h3><a name="grpd_iter_oprs">Grouped Iterator Operators</a></h3>
<p>There are five separate iterator helper classes, each for a <p>There are five iterator operator class templates, each for a different
different category of iterator. Here is a summary of the core set of category of iterator. The following table shows the operator groups
operators that the custom iterator must define, and the extra operators for any category that a custom iterator could define. These class
that are created by the helper classes. These classes cannot be used for <a templates have an additional optional template parameter <code>B</code>,
href="#chaining">base class chaining</a>. For convenience, the helper which is not shown, to support <a href="#chaining">base class chaining</a>.</p>
classes also fill in all of the typedef's required of iterators by the
C++ standard (<code>iterator_category</code>, <code>value_type</code>,
<i>etc.</i>).</p>
<table cellpadding="5" border="1" align="center"> <table cellpadding="5" border="1" align="center">
<caption>Iterator Helper Template Classes</caption> <caption>Iterator Operator Class Templates</caption>
<tr>
<td colspan="2"><table align="center" border="1">
<caption><em>Key</em></caption>
<tr>
<td><code>T</code>: operand type</td>
<td><code>P</code>: <code>pointer</code> type</td>
</tr>
<tr>
<td><code>D</code>: <code>difference_type</code></td>
<td><code>R</code>: <code>reference</code> type</td>
</tr>
<tr>
<td><code>V</code>: <code>value_type</code></td>
<td></td>
</tr>
</table></td>
</tr>
<tr>
<th>Template</th>
<th>Component Operator Templates</th>
</tr>
<tr>
<td><code><a name="input_iteratable">input_iteratable&lt;T, P&gt;</a></code></td>
<td><ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&gt;</a></code></li>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
<li><code><a href="#dereferenceable">dereferenceable&lt;T, P&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="output_iteratable">output_iteratable&lt;T&gt;</a></code></td>
<td><ul>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="forward_iteratable">forward_iteratable&lt;T, P&gt;</a></code></td>
<td><ul>
<li><code><a href="#input_iteratable">input_iteratable&lt;T, P&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="bidirectional_iteratable">bidirectional_iteratable&lt;T, P&gt;</a></code></td>
<td><ul>
<li><code><a href="#forward_iteratable">forward_iteratable&lt;T, P&gt;</a></code></li>
<li><code><a href="#decrementable">decrementable&lt;T&gt;</a></code></li>
</ul></td>
</tr>
<tr>
<td><code><a name="random_access_iteratable">random_access_iteratable&lt;T, P, D, R&gt;</a></code></td>
<td><ul>
<li><code><a href="#bidirectional_iteratable">bidirectional_iteratable&lt;T, P&gt;</a></code></li>
<li><code><a href="#totally_ordered1">totally_ordered&lt;T&gt;</a></code></li>
<li><code><a href="#additive2">additive&lt;T, D&gt;</a></code></li>
<li><code><a href="#indexable">indexable&lt;T, D, R&gt;</a></code></li>
</ul></td>
</tr>
</table>
<h3><a name="iterator">Iterator</a> Helpers</h3>
<p>There are also five iterator helper class templates, each corresponding
to a different iterator category. These classes cannot be used for <a
href="#chaining">base class chaining</a>. The following summaries
show that these class templates supply both the iterator operators from
the <a href="#grpd_iter_oprs">iterator operator class templates</a> and
the iterator typedef's required by the C++ standard (<code>iterator_category</code>,
<code>value_type</code>, <i>etc.</i>).</p>
<table cellpadding="5" border="1" align="center">
<caption>Iterator Helper Class Templates</caption>
<tr> <tr>
<td colspan="2"><table align="center" border="1"> <td colspan="2"><table align="center" border="1">
<caption><em>Key</em></caption> <caption><em>Key</em></caption>
@ -926,16 +1169,14 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
<td><code><a name="input_iterator_helper">input_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td> <td><code><a name="input_iterator_helper">input_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td>
<td>Supports the operations and has the requirements of <td>Supports the operations and has the requirements of
<ul> <ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&gt;</a></code></li> <li><code><a href="#input_iteratable">input_iteratable&lt;T, P&gt;</a></code></li>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
<li><code><a href="#dereferenceable">dereferenceable&lt;T, P&gt;</a></code></li>
</ul></td> </ul></td>
</tr> </tr>
<tr valign="baseline"> <tr valign="baseline">
<td><code><a name="output_iterator_helper">output_iterator_helper&lt;T&gt;</a></code></td> <td><code><a name="output_iterator_helper">output_iterator_helper&lt;T&gt;</a></code></td>
<td>Supports the operations and has the requirements of <td>Supports the operations and has the requirements of
<ul> <ul>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li> <li><code><a href="#output_iteratable">output_iteratable&lt;T&gt;</a></code></li>
</ul> </ul>
See also [<a href="#1">1</a>], [<a href="#2">2</a>]. See also [<a href="#1">1</a>], [<a href="#2">2</a>].
</td> </td>
@ -944,33 +1185,21 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
<td><code><a name="forward_iterator_helper">forward_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td> <td><code><a name="forward_iterator_helper">forward_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td>
<td>Supports the operations and has the requirements of <td>Supports the operations and has the requirements of
<ul> <ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&gt;</a></code></li> <li><code><a href="#forward_iteratable">forward_iteratable&lt;T, P&gt;</a></code></li>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
<li><code><a href="#dereferenceable">dereferenceable&lt;T, P&gt;</a></code></li>
</ul></td> </ul></td>
</tr> </tr>
<tr valign="baseline"> <tr valign="baseline">
<td><code><a name="bidirectional_iterator_helper">bidirectional_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td> <td><code><a name="bidirectional_iterator_helper">bidirectional_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td>
<td>Supports the operations and has the requirements of <td>Supports the operations and has the requirements of
<ul> <ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&gt;</a></code></li> <li><code><a href="#bidirectional_iteratable">bidirectional_iteratable&lt;T, P&gt;</a></code></li>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
<li><code><a href="#decrementable">decrementable&lt;T&gt;</a></code></li>
<li><code><a href="#dereferenceable">dereferenceable&lt;T, P&gt;</a></code></li>
</ul></td> </ul></td>
</tr> </tr>
<tr valign="baseline"> <tr valign="baseline">
<td><code><a name="random_access_iterator_helper">random_access_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td> <td><code><a name="random_access_iterator_helper">random_access_iterator_helper&lt;T, V, D, P, R&gt;</a></code></td>
<td>Supports the operations and has the requirements of <td>Supports the operations and has the requirements of
<ul> <ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&gt;</a></code></li> <li><code><a href="#random_access_iteratable">random_access_iteratable&lt;T, P, D, R&gt;</a></code></li>
<li><code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code></li>
<li><code><a href="#incrementable">incrementable&lt;T&gt;</a></code></li>
<li><code><a href="#decrementable">decrementable&lt;T&gt;</a></code></li>
<li><code><a href="#dereferenceable">dereferenceable&lt;T, P&gt;</a></code></li>
<li><code><a href="#addable2">addable&lt;T, D&gt;</a></code></li>
<li><code><a href="#subtractable2">subtractable&lt;T, D&gt;</a></code></li>
<li><code><a href="#indexable">indexable&lt;T, D, R&gt;</a></code></li>
</ul> </ul>
To satisfy <cite><a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a></cite>, To satisfy <cite><a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a></cite>,
<code>x1 - x2</code> with return convertible to <code>D</code> <code>x1 - x2</code> with return convertible to <code>D</code>
@ -978,7 +1207,7 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
</tr> </tr>
</table> </table>
<h3><a name="iterator_helpers_notes">Iterator Helper Notes</a></h3> <h4><a name="iterator_helpers_notes">Iterator Helper Notes</a></h4>
<p><a name="1">[1]</a> Unlike other iterator helpers templates, <p><a name="1">[1]</a> Unlike other iterator helpers templates,
<code>output_iterator_helper</code> takes only one template parameter - the type of <code>output_iterator_helper</code> takes only one template parameter - the type of
@ -987,8 +1216,8 @@ restriction, the standard requires <code>difference_type</code> and
<code>value_type</code> of any output iterator to be <code>value_type</code> of any output iterator to be
<code>void</code> (24.3.1 [lib.iterator.traits]), and <code>void</code> (24.3.1 [lib.iterator.traits]), and
<code>output_iterator_helper</code> template respects this <code>output_iterator_helper</code> template respects this
requirement. Also, output iterators in the standard have void <tt>pointer</tt> and requirement. Also, output iterators in the standard have void <code>pointer</code> and
<tt>reference</tt> types, so the <tt>output_iterator_helper</tt> does the <code>reference</code> types, so the <code>output_iterator_helper</code> does the
same. same.
<p><a name="2">[2]</a> As self-proxying is the easiest and most common way to <p><a name="2">[2]</a> As self-proxying is the easiest and most common way to
@ -1008,13 +1237,13 @@ template&lt;class UnaryFunction&gt;
struct function_output_iterator struct function_output_iterator
: boost::output_iterator_helper&lt; function_output_iterator&lt;UnaryFunction&gt; &gt; : boost::output_iterator_helper&lt; function_output_iterator&lt;UnaryFunction&gt; &gt;
{ {
explicit function_output_iterator(UnaryFunction const& f = UnaryFunction()) explicit function_output_iterator(UnaryFunction const&amp; f = UnaryFunction())
: func(f) {} : func(f) {}
template&lt;typename T&gt; template&lt;typename T&gt;
function_output_iterator& operator=(T const& value) function_output_iterator&amp; operator=(T const&amp; value)
{ {
this->func(value); this-&gt;func(value);
return *this; return *this;
} }
@ -1093,6 +1322,10 @@ the test results with selected platforms.</p>
partial ordering, and arithmetic conversions. Added the partial ordering, and arithmetic conversions. Added the
grouped operator classes. Added helper classes for grouped operator classes. Added helper classes for
input and output iterators. input and output iterators.
<dt>Helmut Zeisel
<dd>Contributed the 'left' operators and added some
grouped operator classes.
</dl> </dl>
<h2>Note for Users of <a name="old_lib_note">Older Versions</a></h2> <h2>Note for Users of <a name="old_lib_note">Older Versions</a></h2>
@ -1142,7 +1375,7 @@ the library remain backward-compatible.</p>
<hr> <hr>
<p>Revised: 25 Jun 2001</p> <p>Revised: 30 Oct 2001</p>
<p>Copyright &copy; David Abrahams and Beman Dawes 1999-2001. <p>Copyright &copy; David Abrahams and Beman Dawes 1999-2001.
Permission to copy, use, modify, sell and distribute this document is Permission to copy, use, modify, sell and distribute this document is

View File

@ -8,6 +8,8 @@
// 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
// 01 Oct 01 Added tests for "left" operators
// and new grouped operators. (Helmut Zeisel)
// 20 May 01 Output progress messages. Added tests for new operator // 20 May 01 Output progress messages. Added tests for new operator
// templates. Updated random number generator. Changed tests to // templates. Updated random number generator. Changed tests to
// use Boost Test Tools library. (Daryle Walker) // use Boost Test Tools library. (Daryle Walker)
@ -184,6 +186,74 @@ namespace
template <class T, class U> template <class T, class U>
T true_value(Wrapped4<T,U> x) { return x.value(); } T true_value(Wrapped4<T,U> x) { return x.value(); }
// U must be convertible to T
template <class T, class U>
class Wrapped5
: boost::ordered_field_operators2<Wrapped5<T, U>, U>
, boost::ordered_field_operators1<Wrapped5<T, U> >
{
public:
explicit Wrapped5( T v = T() ) : _value(v) {}
// Conversion from U to Wrapped5<T,U>
Wrapped5(U u) : _value(u) {}
T value() const { return _value; }
bool operator<(const Wrapped5& x) const { return _value < x._value; }
bool operator<(U u) const { return _value < u; }
bool operator>(U u) const { return _value > u; }
bool operator==(const Wrapped5& u) const { return _value == u._value; }
bool operator==(U u) const { return _value == u; }
Wrapped5& operator/=(const Wrapped5& u) { _value /= u._value; return *this;}
Wrapped5& operator/=(U u) { _value /= u; return *this;}
Wrapped5& operator*=(const Wrapped5& u) { _value *= u._value; return *this;}
Wrapped5& operator*=(U u) { _value *= u; return *this;}
Wrapped5& operator-=(const Wrapped5& u) { _value -= u._value; return *this;}
Wrapped5& operator-=(U u) { _value -= u; return *this;}
Wrapped5& operator+=(const Wrapped5& u) { _value += u._value; return *this;}
Wrapped5& operator+=(U u) { _value += u; return *this;}
private:
T _value;
};
template <class T, class U>
T true_value(Wrapped5<T,U> x) { return x.value(); }
// U must be convertible to T
template <class T, class U>
class Wrapped6
: boost::ordered_euclidian_ring_operators2<Wrapped6<T, U>, U>
, boost::ordered_euclidian_ring_operators1<Wrapped6<T, U> >
{
public:
explicit Wrapped6( T v = T() ) : _value(v) {}
// Conversion from U to Wrapped6<T,U>
Wrapped6(U u) : _value(u) {}
T value() const { return _value; }
bool operator<(const Wrapped6& x) const { return _value < x._value; }
bool operator<(U u) const { return _value < u; }
bool operator>(U u) const { return _value > u; }
bool operator==(const Wrapped6& u) const { return _value == u._value; }
bool operator==(U u) const { return _value == u; }
Wrapped6& operator%=(const Wrapped6& u) { _value %= u._value; return *this;}
Wrapped6& operator%=(U u) { _value %= u; return *this;}
Wrapped6& operator/=(const Wrapped6& u) { _value /= u._value; return *this;}
Wrapped6& operator/=(U u) { _value /= u; return *this;}
Wrapped6& operator*=(const Wrapped6& u) { _value *= u._value; return *this;}
Wrapped6& operator*=(U u) { _value *= u; return *this;}
Wrapped6& operator-=(const Wrapped6& u) { _value -= u._value; return *this;}
Wrapped6& operator-=(U u) { _value -= u; return *this;}
Wrapped6& operator+=(const Wrapped6& u) { _value += u._value; return *this;}
Wrapped6& operator+=(U u) { _value += u; return *this;}
private:
T _value;
};
template <class T, class U>
T true_value(Wrapped6<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;
@ -193,6 +263,10 @@ namespace
typedef Wrapped4<short, short> MyShort; typedef Wrapped4<short, short> MyShort;
typedef Wrapped5<double, int> MyDoubleInt;
typedef Wrapped6<long, int> MyLongInt;
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)
{ {
@ -267,6 +341,13 @@ namespace
BOOST_TEST( (x1 - y1).value() == (x2 - y2) ); BOOST_TEST( (x1 - y1).value() == (x2 - y2) );
} }
template <class X1, class Y1, class X2, class Y2>
void test_subtractable_left(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
sanity_check( x1, y1, x2, y2 );
BOOST_TEST( (y1 - x1).value() == (y2 - x2) );
}
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)
{ {
@ -275,6 +356,14 @@ namespace
BOOST_TEST( (x1 / y1).value() == (x2 / y2) ); BOOST_TEST( (x1 / y1).value() == (x2 / y2) );
} }
template <class X1, class Y1, class X2, class Y2>
void test_dividable_left(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
sanity_check( x1, y1, x2, y2 );
if ( x2 != 0 )
BOOST_TEST( (y1 / x1).value() == (y2 / x2) );
}
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)
{ {
@ -283,6 +372,14 @@ namespace
BOOST_TEST( (x1 % y1).value() == (x2 % y2) ); BOOST_TEST( (x1 % y1).value() == (x2 % y2) );
} }
template <class X1, class Y1, class X2, class Y2>
void test_modable_left(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
sanity_check( x1, y1, x2, y2 );
if ( x2 != 0 )
BOOST_TEST( (y1 % x1).value() == (y2 % x2) );
}
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)
{ {
@ -374,6 +471,14 @@ namespace
test_decrementable( x1, x2 ); test_decrementable( x1, x2 );
} }
template <class X1, class Y1, class X2, class Y2>
void test_left(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
test_subtractable_left( x1, y1, x2, y2 );
test_dividable_left( x1, y1, x2, y2 );
test_modable_left( x1, y1, x2, y2 );
}
template <class Big, class Small> template <class Big, class Small>
struct tester struct tester
{ {
@ -388,6 +493,19 @@ namespace
} }
}; };
template <class Big, class Small>
struct tester_left
{
void operator()(boost::minstd_rand& randomizer) const
{
Big b1 = Big( randomizer() );
Big b2 = Big( randomizer() );
Small s = Small( randomizer() );
test_left( Wrapped6<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
@ -427,6 +545,13 @@ template Wrapped2<unsigned int, unsigned char>;
template Wrapped2<unsigned long, unsigned int>; template Wrapped2<unsigned long, unsigned int>;
template Wrapped2<unsigned long, unsigned char>; template Wrapped2<unsigned long, unsigned char>;
template Wrapped2<unsigned long, unsigned long>; template Wrapped2<unsigned long, unsigned long>;
template Wrapped6<long, int>;
template Wrapped6<long, signed char>;
template Wrapped6<int, signed char>;
template Wrapped6<unsigned long, unsigned int>;
template Wrapped6<unsigned long, unsigned char>;
template Wrapped6<unsigned int, unsigned char>;
#endif #endif
#define PRIVATE_EXPR_TEST(e, t) BOOST_TEST( ((e), (t)) ) #define PRIVATE_EXPR_TEST(e, t) BOOST_TEST( ((e), (t)) )
@ -459,6 +584,14 @@ test_main( int , char * [] )
tester<unsigned long, unsigned long>()(r); tester<unsigned long, unsigned long>()(r);
tester<unsigned int, unsigned int>()(r); tester<unsigned int, unsigned int>()(r);
tester<unsigned int, unsigned char>()(r); tester<unsigned int, unsigned char>()(r);
tester_left<long, int>()(r);
tester_left<long, signed char>()(r);
tester_left<int, signed char>()(r);
tester_left<unsigned long, unsigned int>()(r);
tester_left<unsigned long, unsigned char>()(r);
tester_left<unsigned int, unsigned char>()(r);
} }
cout << "Did random tester loop." << endl; cout << "Did random tester loop." << endl;
@ -653,5 +786,106 @@ test_main( int , char * [] )
cout << "Performed tests on MyShort objects.\n"; cout << "Performed tests on MyShort objects.\n";
MyDoubleInt di1(1);
MyDoubleInt di2(2.);
MyDoubleInt half(0.5);
MyDoubleInt di;
MyDoubleInt tmp;
BOOST_TEST( di1.value() == 1 );
BOOST_TEST( di2.value() == 2 );
BOOST_TEST( di2.value() == 2 );
BOOST_TEST( di.value() == 0 );
cout << "Created MyDoubleInt objects.\n";
PRIVATE_EXPR_TEST( (di = di2), (di.value() == 2) );
BOOST_TEST( di2 == di );
BOOST_TEST( 2 == di );
BOOST_TEST( di == 2 );
BOOST_TEST( di1 < di2 );
BOOST_TEST( 1 < di2 );
BOOST_TEST( di1 <= di2 );
BOOST_TEST( 1 <= di2 );
BOOST_TEST( di2 > di1 );
BOOST_TEST( di2 > 1 );
BOOST_TEST( di2 >= di1 );
BOOST_TEST( di2 >= 1 );
BOOST_TEST( di1 / di2 == half );
BOOST_TEST( di1 / 2 == half );
BOOST_TEST( 1 / di2 == half );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp/=2) == half) );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp/=di2) == half) );
BOOST_TEST( di1 * di2 == di2 );
BOOST_TEST( di1 * 2 == di2 );
BOOST_TEST( 1 * di2 == di2 );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp*=2) == di2) );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp*=di2) == di2) );
BOOST_TEST( di2 - di1 == di1 );
BOOST_TEST( di2 - 1 == di1 );
BOOST_TEST( 2 - di1 == di1 );
PRIVATE_EXPR_TEST( (tmp=di2), ((tmp-=1) == di1) );
PRIVATE_EXPR_TEST( (tmp=di2), ((tmp-=di1) == di1) );
BOOST_TEST( di1 + di1 == di2 );
BOOST_TEST( di1 + 1 == di2 );
BOOST_TEST( 1 + di1 == di2 );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp+=1) == di2) );
PRIVATE_EXPR_TEST( (tmp=di1), ((tmp+=di1) == di2) );
cout << "Performed tests on MyDoubleInt objects.\n";
MyLongInt li1(1);
MyLongInt li2(2);
MyLongInt li;
MyLongInt tmp2;
BOOST_TEST( li1.value() == 1 );
BOOST_TEST( li2.value() == 2 );
BOOST_TEST( li.value() == 0 );
cout << "Created MyLongInt objects.\n";
PRIVATE_EXPR_TEST( (li = li2), (li.value() == 2) );
BOOST_TEST( li2 == li );
BOOST_TEST( 2 == li );
BOOST_TEST( li == 2 );
BOOST_TEST( li1 < li2 );
BOOST_TEST( 1 < li2 );
BOOST_TEST( li1 <= li2 );
BOOST_TEST( 1 <= li2 );
BOOST_TEST( li2 > li1 );
BOOST_TEST( li2 > 1 );
BOOST_TEST( li2 >= li1 );
BOOST_TEST( li2 >= 1 );
BOOST_TEST( li1 % li2 == li1 );
BOOST_TEST( li1 % 2 == li1 );
BOOST_TEST( 1 % li2 == li1 );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2%=2) == li1) );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2%=li2) == li1) );
BOOST_TEST( li1 / li2 == 0 );
BOOST_TEST( li1 / 2 == 0 );
BOOST_TEST( 1 / li2 == 0 );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2/=2) == 0) );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2/=li2) == 0) );
BOOST_TEST( li1 * li2 == li2 );
BOOST_TEST( li1 * 2 == li2 );
BOOST_TEST( 1 * li2 == li2 );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2*=2) == li2) );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2*=li2) == li2) );
BOOST_TEST( li2 - li1 == li1 );
BOOST_TEST( li2 - 1 == li1 );
BOOST_TEST( 2 - li1 == li1 );
PRIVATE_EXPR_TEST( (tmp2=li2), ((tmp2-=1) == li1) );
PRIVATE_EXPR_TEST( (tmp2=li2), ((tmp2-=li1) == li1) );
BOOST_TEST( li1 + li1 == li2 );
BOOST_TEST( li1 + 1 == li2 );
BOOST_TEST( 1 + li1 == li2 );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2+=1) == li2) );
PRIVATE_EXPR_TEST( (tmp2=li1), ((tmp2+=li1) == li2) );
cout << "Performed tests on MyLongInt objects.\n";
return boost::exit_success; return boost::exit_success;
} }