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.
// 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
// parameters, added support for self-proxying, additional
// documentation and tests (Aleksey Gurtovoy)
@ -81,7 +86,14 @@
namespace boost {
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 {};
#endif
} // namespace detail
} // namespace boost
@ -168,6 +180,13 @@ struct subtractable2 : B
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>
struct subtractable1 : B
{
@ -180,6 +199,13 @@ struct dividable2 : B
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>
struct dividable1 : B
{
@ -192,6 +218,13 @@ struct modable2 : B
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>
struct modable1 : B
{
@ -463,12 +496,121 @@ struct shiftable1
, 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
} // namespace boost
#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
// operator template into the boost namespace. BOOST_IMPORT_TEMPLATE1 is used
@ -479,6 +621,7 @@ struct shiftable1
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
// 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_TEMPLATE2(template_name)
# define BOOST_IMPORT_TEMPLATE1(template_name)
@ -489,6 +632,7 @@ struct shiftable1
// Bring the names in with a using-declaration
// 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_TEMPLATE2(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
// 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) \
template <class T, class U, class V, class B = ::boost::detail::empty_base> \
struct template_name : ::template_name<T, U, V, B> {};
@ -542,6 +690,15 @@ template<class T> struct is_chained_base {
} // 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
// provide a specialization of 'is_chained_base<>' for it.
# define BOOST_OPERATOR_TEMPLATE3(template_name3) \
@ -610,6 +767,8 @@ BOOST_OPERATOR_TEMPLATE1(template_name##1)
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
# define BOOST_OPERATOR_TEMPLATE4(template_name4) \
BOOST_IMPORT_TEMPLATE4(template_name4)
# define BOOST_OPERATOR_TEMPLATE3(template_name3) \
BOOST_IMPORT_TEMPLATE3(template_name3)
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \
@ -632,8 +791,11 @@ BOOST_OPERATOR_TEMPLATE(equality_comparable)
BOOST_OPERATOR_TEMPLATE(multipliable)
BOOST_OPERATOR_TEMPLATE(addable)
BOOST_OPERATOR_TEMPLATE(subtractable)
BOOST_OPERATOR_TEMPLATE2(subtractable2_left)
BOOST_OPERATOR_TEMPLATE(dividable)
BOOST_OPERATOR_TEMPLATE2(dividable2_left)
BOOST_OPERATOR_TEMPLATE(modable)
BOOST_OPERATOR_TEMPLATE2(modable2_left)
BOOST_OPERATOR_TEMPLATE(xorable)
BOOST_OPERATOR_TEMPLATE(andable)
BOOST_OPERATOR_TEMPLATE(orable)
@ -658,14 +820,27 @@ BOOST_OPERATOR_TEMPLATE(integer_arithmetic)
BOOST_OPERATOR_TEMPLATE(bitwise)
BOOST_OPERATOR_TEMPLATE1(unit_steppable)
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_TEMPLATE4
#undef BOOST_OPERATOR_TEMPLATE3
#undef BOOST_OPERATOR_TEMPLATE2
#undef BOOST_OPERATOR_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE1
#undef BOOST_IMPORT_TEMPLATE2
#undef BOOST_IMPORT_TEMPLATE3
#undef BOOST_IMPORT_TEMPLATE4
// The following 'operators' classes can only be used portably if the derived class
// declares ALL of the required member operators.
@ -699,20 +874,18 @@ template <class T,
class P = V const *,
class R = V const &>
struct input_iterator_helper
: equality_comparable1<T
, incrementable<T
, dereferenceable<T, P
: input_iteratable<T, P
, boost::iterator<std::input_iterator_tag, V, D, P, R
> > > > {};
> > {};
template<class Derived>
template<class T>
struct output_iterator_helper
: boost::incrementable<Derived
: output_iteratable<T
, boost::iterator<std::output_iterator_tag, void, void, void, void
> >
{
Derived& operator*() { return static_cast<Derived&>(*this); }
Derived& operator++() { return static_cast<Derived&>(*this); }
T& operator*() { return static_cast<T&>(*this); }
T& operator++() { return static_cast<T&>(*this); }
};
template <class T,
@ -721,11 +894,9 @@ template <class T,
class P = V*,
class R = V&>
struct forward_iterator_helper
: equality_comparable1<T
, incrementable<T
, dereferenceable<T, P
: forward_iteratable<T, P
, boost::iterator<std::forward_iterator_tag, V, D, P, R
> > > > {};
> > {};
template <class T,
class V,
@ -733,11 +904,9 @@ template <class T,
class P = V*,
class R = V&>
struct bidirectional_iterator_helper
: equality_comparable1<T
, unit_steppable<T
, dereferenceable<T, P
: bidirectional_iteratable<T, P
, boost::iterator<std::bidirectional_iterator_tag, V, D, P, R
> > > > {};
> > {};
template <class T,
class V,
@ -745,13 +914,9 @@ template <class T,
class P = V*,
class R = V&>
struct random_access_iterator_helper
: totally_ordered1<T
, unit_steppable<T
, dereferenceable<T, P
, additive2<T, D
, indexable<T, D, R
: random_access_iteratable<T, P, D, R
, boost::iterator<std::random_access_iterator_tag, V, D, P, R
> > > > > >
> >
{
friend D requires_difference_operator(const T& x, const T& y) {
return x - y;

View File

@ -30,7 +30,11 @@ provided by the class.</p>
</ul></li>
<li><a href="#usage">Usage</a>
<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="#explicit_instantiation">Separate, Explicit
Instantiation</a></li>
@ -39,7 +43,10 @@ provided by the class.</p>
<li><a href="#example">Example</a></li>
<li><a href="#arithmetic">Arithmetic operators</a>
<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="#ex_oprs">Example Templates</a></li>
<li><a href="#a_demo">Arithmetic Operators Demonstration
@ -49,8 +56,12 @@ provided by the class.</p>
Helpers</a>
<ul>
<li><a href="#dereference">Dereference operators</a></li>
<li><a href="#iterator">Iterator Helpers</a></li>
<li><a href="#iterator_helpers_notes">Iterator Helper Notes</a></li>
<li><a href="#grpd_iter_oprs">Grouped Iterator Operators</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
Program</a></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>
<h4><a name="two_arg_gen">General Considerations</a></h4>
<p>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 <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>
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>
<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>
Return convertible to <code>T</code>.</td>
</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>
<td><code><a name="multipliable1">multipliable&lt;T&gt;</a></code><br>
<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>
Return convertible to <code>T</code>.</td>
</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>
<td><code><a name="modable1">modable&lt;T&gt;</a></code><br>
<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>
Return convertible to <code>T</code>.</td>
</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>
<td><code><a name="orable1">orable&lt;T&gt;</a></code><br>
<code>orable1&lt;T&gt;</code></td>
@ -588,8 +659,9 @@ for the <a href="#chaining">base class chaining</a> technique.
</tr>
</table>
<p><strong><a name="ordering">Ordering Note</a></strong><br>
The <code><a href="#less_than_comparable1">less_than_comparable&lt;T&gt;</a></code>
<h4><a name="ordering">Ordering</a> Note</h4>
<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>
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>
@ -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>
</ul></td>
</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>
<h3><a name="ex_oprs">Example</a> Templates</h3>
@ -888,19 +1063,87 @@ href="#chaining">base class chaining</a>.</p>
</tr>
</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
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 <a
href="#chaining">base class chaining</a>. For convenience, the helper
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>
<p>There are five iterator operator class templates, each for a different
category of iterator. The following table shows the operator groups
for any category that a custom iterator could define. These class
templates have an additional optional template parameter <code>B</code>,
which is not shown, to support <a href="#chaining">base class chaining</a>.</p>
<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>
<td colspan="2"><table align="center" border="1">
<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>Supports the operations and has the requirements of
<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>
<li><code><a href="#input_iteratable">input_iteratable&lt;T, P&gt;</a></code></li>
</ul></td>
</tr>
<tr valign="baseline">
<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
<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>
See also [<a href="#1">1</a>], [<a href="#2">2</a>].
</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>Supports the operations and has the requirements of
<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>
<li><code><a href="#forward_iteratable">forward_iteratable&lt;T, P&gt;</a></code></li>
</ul></td>
</tr>
<tr valign="baseline">
<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
<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="#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="#bidirectional_iteratable">bidirectional_iteratable&lt;T, P&gt;</a></code></li>
</ul></td>
</tr>
<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>Supports the operations and has the requirements of
<ul>
<li><code><a href="#equality_comparable1">equality_comparable&lt;T&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>
<li><code><a href="#random_access_iteratable">random_access_iteratable&lt;T, P, D, R&gt;</a></code></li>
</ul>
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>
@ -978,7 +1207,7 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
</tr>
</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,
<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>void</code> (24.3.1 [lib.iterator.traits]), and
<code>output_iterator_helper</code> template respects this
requirement. Also, output iterators in the standard have void <tt>pointer</tt> and
<tt>reference</tt> types, so the <tt>output_iterator_helper</tt> does the
requirement. Also, output iterators in the standard have void <code>pointer</code> and
<code>reference</code> types, so the <code>output_iterator_helper</code> does the
same.
<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
: 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) {}
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;
}
@ -1093,6 +1322,10 @@ the test results with selected platforms.</p>
partial ordering, and arithmetic conversions. Added the
grouped operator classes. Added helper classes for
input and output iterators.
<dt>Helmut Zeisel
<dd>Contributed the 'left' operators and added some
grouped operator classes.
</dl>
<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>
<p>Revised: 25 Jun 2001</p>
<p>Revised: 30 Oct 2001</p>
<p>Copyright &copy; David Abrahams and Beman Dawes 1999-2001.
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.
// 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
// templates. Updated random number generator. Changed tests to
// use Boost Test Tools library. (Daryle Walker)
@ -184,6 +186,74 @@ namespace
template <class T, class U>
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<>
typedef Wrapped1<int> MyInt;
@ -193,6 +263,10 @@ namespace
typedef Wrapped4<short, short> MyShort;
typedef Wrapped5<double, int> MyDoubleInt;
typedef Wrapped6<long, int> MyLongInt;
template <class X1, class Y1, class X2, class Y2>
void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
@ -267,6 +341,13 @@ namespace
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>
void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
@ -275,6 +356,14 @@ namespace
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>
void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
@ -283,6 +372,14 @@ namespace
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>
void test_xorable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
{
@ -374,6 +471,14 @@ namespace
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>
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.
struct 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 char>;
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
#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 int, unsigned int>()(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;
@ -653,5 +786,106 @@ test_main( int , char * [] )
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;
}