Compare commits

...

15 Commits

Author SHA1 Message Date
nobody
4769d0f19d This commit was manufactured by cvs2svn to create tag
'Version_1_30_1'.

[SVN r19444]
2003-08-04 17:55:29 +00:00
Ronald Garcia
cd7b6f7c52 Fixed broken patch.
[SVN r17855]
2003-03-12 15:44:35 +00:00
Markus Schöpflin
98f7604258 Merged fix for regression test failure for VA6 from trunk to branch
[SVN r17832]
2003-03-12 10:49:11 +00:00
nobody
c563bf58fb This commit was manufactured by cvs2svn to create branch 'RC_1_30_0'.
[SVN r17693]
2003-03-01 19:43:06 +00:00
Ronald Garcia
84d65a8402 Must have forgot to check in this change.
[SVN r17540]
2003-02-19 23:42:32 +00:00
Ronald Garcia
da922535c2 Repaired some dependent base class issues (found by icc -ansi).
[SVN r17243]
2003-02-05 20:39:13 +00:00
Ronald Garcia
b8bf7a5fcd Fixed a bug in advance.
[SVN r17093]
2003-01-30 16:55:31 +00:00
Ronald Garcia
ef89b81e7c Made some changes as per bug reports regarding calls to dependent base classes.
[SVN r16932]
2003-01-18 19:47:29 +00:00
Ronald Garcia
080c2a7c9b Bug fixes related to calling functions in dependent base classes.
[SVN r16924]
2003-01-17 20:09:54 +00:00
Ronald Garcia
9c3949fb67 Imported from jsiek's submission to the library group, or something like that.
I modified the labels to not use colons because some browser's can't handle
labels with colons in them.


[SVN r16829]
2003-01-09 14:23:05 +00:00
Ronald Garcia
0e55920979 Added a note about upcoming user documentation update.
[SVN r16809]
2003-01-08 23:36:12 +00:00
Beman Dawes
7683594b36 add or update See www.boost.org comments
[SVN r16708]
2002-12-27 16:51:53 +00:00
Ronald Garcia
7ed9d30cc9 Added resizing capability to multi_array (not multi_array_ref!).
[SVN r16505]
2002-12-04 02:03:26 +00:00
Beman Dawes
e5909ce409 Add super_type:: so 2-phase lookup works right
[SVN r16378]
2002-11-23 18:17:43 +00:00
Ronald Garcia
8387e84d8f Patch received from Toon Knapen applied.
[SVN r16034]
2002-10-31 21:26:25 +00:00
10 changed files with 972 additions and 83 deletions

View File

@@ -0,0 +1,733 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><!-- saved from url=(0022)http://internet.e-mail --><title>Improved Iterator Categories and Requirements</title>
<meta content="text/html; charset=windows-1252" http-equiv="Content-Type">
<meta content="MSHTML 5.00.2919.6307" name="GENERATOR"></head>
<body bgcolor="#ffffff">
<p align="right">
<table border="0">
<tbody>
<tr>
<td width="125">
<p align="right">Document number: </p></td>
<td width="190">
<p>J16/01-0011 = WG21 N1297 </p></td></tr>
<tr>
<td width="125">
<p align="right">Date: </p></td>
<td width="190">
<p>March 21, 2001 </p></td></tr>
<tr>
<td width="125">
<p align="right">Author: </p></td>
<td width="190">
<p>Jeremy Siek, <br>University of Notre Dame </p></td></tr>
<tr>
<td width="125">
<p></p></td>
<td width="190">
<p><a href="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</a>
</p></td></tr></tbody></table></p>
<h1>
<center>Improved Iterator Categories and Requirements</center></h1>
<h2>Introduction</h2>The standard iterator categories and requirements are
flawed because they use a single hierarchy of requirements to address two
orthogonal issues: <b><i>iterator traversal</i></b> and <b><i>dereference return
type</i></b>. The current iterator requirement hierarchy is mainly geared
towards iterator traversal (hence the category names), while requirements that
address dereference return type sneak in at various places. The following table
gives a summary of the current dereference return type requirements in the
iterator categories.
<p>
</p><center>
<a name="table:2">
<b>Table 1.</b> Summary of current dereference return type
requirements.</a><table border="1">
<tbody>
<tr>
<td>Output Iterator</td>
<td><tt>*i = a</tt> </td></tr>
<tr>
<td>Input Iterator</td>
<td><tt>*i</tt> is convertible to <tt>T</tt></td></tr>
<tr>
<td>Forward Iterator</td>
<td><tt>*i</tt> is <tt>T&amp;</tt> (or <tt>const T&amp;</tt> once <a href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#200">issue
200</a> is resolved)</td></tr>
<tr>
<td>Random Access Iterator</td>
<td><tt>i[n]</tt> is convertible to <tt>T</tt> (which is odd because the
operational semantics say <tt>i[n]</tt> is equivalent to <tt>*(i + n)</tt>
which would have a return type of <tt>T&amp;</tt>) </td></tr></tbody></table></center>
<h2>Examples of useful iterators that do not ``fit''</h2>
<p>Because of the mixing of iterator traversal and dereference return type, many
useful iterators can not be appropriately categorized. For example,
<tt>vector&lt;bool&gt;::iterator</tt> is almost a random access iterator, but
the return type is not <tt>bool&amp;</tt> (see <a href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#96">issue
96</a> and Herb Sutter's paper J16/99-0008 = WG21 N1185). Therefore, the
iterators only meet the requirements of input iterator and output iterator. This
is so nonintuitive that at least one implementation erroneously assigns
<tt>random_access_iterator_tag</tt> as its <tt>iterator_category</tt>. Also,
<tt>vector&lt;bool&gt;</tt> is not the only example of useful iterators that do
not return true references: there is the often cited example of disk-based
collections.
</p><p>Another example is a counting iterator, an iterator the returns a sequence of
integers when incremented and dereferenced (see <a href="http://www.boost.org/libs/utility/counting_iterator.htm"><tt>boost::counting_iterator</tt></a>).
There are two ways to implement this iterator, 1) make the <tt>reference</tt>
type be a true reference (a reference to an integer data member of the counting
iterator) or 2) make the <tt>reference</tt> type be the same as the
<tt>value_type</tt>. Option 1) runs into the problems discussed in <a href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#198">Issue
198</a>, the reference will not be valid after the iterator is destroyed. Option
2) is therefore a better choice, but then we have a counting iterator that
cannot be a random access iterator.
</p><p>Yet another example is a transform iterator, an iterator adaptor that applies
a unary function object to the dereference value of the wrapped iterator (see <a href="http://www.boost.org/libs/utility/transform_iterator.htm"><tt>boost::transform_iterator</tt></a>).
For unary functions such as <tt>std::times</tt> the return type of
<tt>operator*</tt> clearly needs to be the <tt>result_type</tt> of the function
object, which is typically not a reference. However, with the current iterator
requirements, if you wrap <tt>int*</tt> with a transform iterator, you do not
get a random access iterator as expected, but an input iterator.
</p><p>A fourth example is found in the vertex and edge iterators of the <a href="http://www.boost.org/libs/graph/doc/table_of_contents.html">Boost Graph
Library</a>. These iterators return vertex and edge descriptors, which are
lightweight handles created on-the-fly. They must be returned by-value. As a
result, their current standard iterator category is
<tt>std::input_iterator_tag</tt>, which means that, strictly speaking, you could
not use these iterators with algorithms like <tt>std::min_element()</tt>. As a
temporary solution, we introduced the concept <a href="http://www.boost.org/libs/utility/MultiPassInputIterator.html">Multi-Pass
Input Iterator</a> to describe the vertex and edge descriptors, but as the
design notes for concept suggest, a better solution is needed.
</p><p>In short, there are many useful iterators that do not fit into the current
standard iterator categories. As a result, the following bad things happen:
</p><ul>
<li>Iterators are often miss-categorized.
</li><li>Algorithm requirements are more strict than necessary, because they can
not separate out the need for random-access from the need for a true reference
return type. </li></ul>
<h2>Proposal for new iterator categories and requirements</h2>The iterator
requirements should be separated into two hierarchies. One set of concepts
handles the return type semantics:
<ul>
<li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ReadableIterator">Readable
Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_WritableIterator">Writable
Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_SwappableIterator">Swappable
Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ConstantLvalueIterator">Constant
Lvalue Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_MutableLvalueIterator">Mutable
Lvalue Iterator</a> </li></ul>The other set of concepts handles iterator
traversal:
<ul>
<li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ForwardTraversalIterator">Forward
Traversal Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_BidirectionalTraversalIterator">Bidirectional
Traversal Iterator</a>
</li><li><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_RandomAccessTraversalIterator">Random
Access Traversal Iterator</a> </li></ul>The current Input Iterator and Output
Iterator requirements will continue to be used as is. Note that Input Iterator
implies Readable Iterator and Output Iterator implies Writable Iterator.
<p>Note: we considered defining a Single-Pass Iterator, which could be combined
with Readable or Writable Iterator to replace the Input and Output Iterator
requirements. We rejected this idea because there are several differences
between Input and Output Iterators that make it hard to merge them: Input
Iterator requires Equality Comparable while Output Iterator does not and Input
Iterator requires Assignable while Output Iterator does not.
</p><h3>New categories and traits classes</h3>Each of the new iterator requirements
will need a category tag. <pre>namespace std {
// Return Type Categories
struct readable_iterator_tag { };
struct writable_iterator_tag { };
struct swappable_iterator_tag { };
struct mutable_lvalue_iterator_tag : virtual public writable_iterator_tag,
virtual public readable_iterator_tag { };
struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
// Traversal Categories
struct forward_traversal_tag { };
struct bidirectional_traversal_tag : public forward_traversal_tag { };
struct random_access_traversal_tag : public bidirectional_traversal_tag { };
}
</pre>And there will need to be a way to access these category tags using a
traits mechanism. Adding new typedefs to <tt>std::iterator_traits</tt> is not an
acceptable solution because that would break every existing iterator. Instead,
we propose two new traits classes. It is important that these traits classes are
<b>backward compatible</b>, that is, they should work with any iterator for
which there is a valid definition of <tt>std::iterator_traits</tt>. This can be
accomplished by making the default behavior of the traits classes map the
<tt>iterator_category</tt> of the iterator to the appropriate return or
traversal category. For new iterators, either specializations of these traits
classes can be defined, or the iterator can provide nested typedefs, and inherit
from <tt>new_iterator_base</tt> (which is just a signal to the traits class that
it is a new iterator). As with <tt>std::iterator_traits</tt>, specializations
for <tt>T*</tt> are provided. <pre>namespace std {
struct new_iterator_base { };
template &lt;typename Iterator&gt;
struct return_category
{
<b><i>// Pseudo-code</i></b>
if (Iterator inherits from new_iterator_base) {
typedef typename Iterator::return_category type;
} else {
typedef std::iterator_traits&lt;Iterator&gt; OldTraits;
typedef typename OldTraits::iterator_category Cat;
if (Cat inherits from std::forward_iterator_tag)
if (is-const(T))
typedef boost::constant_lvalue_iterator_tag type;
else
typedef boost::mutable_lvalue_iterator_tag type;
else if (Cat inherits from std::input_iterator_tag)
typedef boost::readable_iterator_tag type;
else if (Cat inherits from std::output_iterator_tag)
typedef boost::writable_iterator_tag type;
}
};
template &lt;typename T&gt;
struct return_category&lt;T*&gt;
{
<b><i>// Pseudo-code</i></b>
if (is-const(T))
typedef boost::constant_lvalue_iterator_tag type;
else
typedef boost::mutable_lvalue_iterator_tag type;
};
template &lt;typename Iterator&gt;
struct traversal_category
{
<b><i>// Pseudo-code</i></b>
if (Iterator inherits from new_iterator_base) {
typedef typename Iterator::traversal_category type;
} else {
typedef std::iterator_traits&lt;Iterator&gt; OldTraits;
typedef typename OldTraits::iterator_category Cat;
if (Cat inherits from std::random_access_iterator_tag)
typedef boost::random_access_traversal_tag type;
else if (Cat inherits from std::bidirectional_iterator_tag)
typedef boost::bidirectional_traversal_tag type;
else if (Cat inherits from std::forward_iterator_tag)
typedef boost::forward_traversal_tag type;
}
};
template &lt;typename T&gt;
struct traversal_category&lt;T*&gt;
{
typedef boost::random_access_traversal_tag type;
};
}
</pre>
<h2>Impact on the Standard Algorithms</h2>Many of the standard algorithms place
more requirements than necessary on their iterator parameters due to the
coarseness of the current iterator categories. By using the new iterator
categories a better fit can be achieved, thereby increasing the reusability of
the algorithms. These changes will not affect user-code, though they will
require changes by standard implementers: dispatching should be based on the new
categories, and in places return values may need to be handled more carefully.
In particular, uses of <tt>std::swap()</tt> will need to be replaced with
<tt>std::iter_swap()</tt>, and <tt>std::iter_swap()</tt> will need to call
<tt>std::swap()</tt>.
<p>
</p><center>
<a name="table:2">
<b>Table 2.</b> Requirement changes for standard
algorithms.</a><table border="1">
<tbody>
<tr>
<th>Algorithm</th>
<th>Requirement Change</th></tr>
<tr>
<td>find_end</td>
<td rowspan="12">Forward Iterator<br>-&gt; Forward Traversal Iterator and
Readable Iterator </td></tr>
<tr>
<td>find_first_of</td></tr>
<tr>
<td>adjacent_find</td></tr>
<tr>
<td>search</td></tr>
<tr>
<td>search_n</td></tr>
<tr>
<td>rotate_copy</td></tr>
<tr>
<td>lower_bound</td></tr>
<tr>
<td>upper_bound</td></tr>
<tr>
<td>equal_range</td></tr>
<tr>
<td>binary_search</td></tr>
<tr>
<td>min_element</td></tr>
<tr>
<td>max_element</td></tr>
<tr>
<td>iter_swap</td>
<td>Forward Iterator<br>-&gt; Swappable Iterator </td></tr>
<tr>
<td>fill</td>
<td rowspan="2">Forward Iterator<br>-&gt; Forward Traversal Iterator and
Writable Iterator </td></tr>
<tr>
<td>generate</td></tr>
<tr>
<td>swap_ranges</td>
<td rowspan="2">Forward Iterator<br>-&gt; Forward Traversal Iterator and
Swappable Iterator </td></tr>
<tr>
<td>rotate</td></tr>
<tr>
<td>replace</td>
<td rowspan="5">Forward Iterator<br>-&gt; Forward Traversal Iterator
and<br>Readable Iterator and Writable Iterator </td>
</tr><tr>
<td>replace_if</td></tr>
<tr>
<td>remove</td></tr>
<tr>
<td>remove_if</td></tr>
<tr>
<td>unique</td></tr>
<tr>
<td>reverse</td>
<td rowspan="2">Bidirectional Iterator<br>-&gt; Bidirectional Traversal
Iterator and Swappable Iterator </td></tr>
<tr>
<td>partition</td></tr>
<tr>
<td>copy_backwards</td>
<td>Bidirectional Iterator<br>-&gt; Bidirectional Traversal Iterator and
Readable Iterator<br>Bidirectional Iterator<br>-&gt; Bidirectional
Traversal Iterator and Writable Iterator </td></tr>
<tr>
<td>next_permutation</td>
<td rowspan="2">Bidirectional Iterator<br>-&gt; Bidirectional Traversal
Iterator and <br>Swappable Iterator and Readable Iterator </td>
</tr><tr>
<td>prev_permutation</td></tr>
<tr>
<td>stable_partition</td>
<td rowspan="2">Bidirectional Iterator<br>-&gt; Bidirectional Traversal
Iterator and <br>Readable Iterator and Writable Iterator </td>
</tr><tr>
<td>inplace_merge</td></tr>
<tr>
<td>reverse_copy</td>
<td>Bidirectional Iterator<br>-&gt; Bidirectional Traversal Iterator and
Readable Iterator </td></tr>
<tr>
<td>random_shuffle</td>
<td rowspan="9">Random Access Iterator<br>-&gt; Random Access Traversal
Iterator and Swappable Iterator </td></tr>
<tr>
<td>sort</td></tr>
<tr>
<td>stable_sort</td></tr>
<tr>
<td>partial_sort</td></tr>
<tr>
<td>nth_element</td></tr>
<tr>
<td>push_heap</td></tr>
<tr>
<td>pop_heap</td></tr>
<tr>
<td>make_heap</td></tr>
<tr>
<td>sort_heap</td></tr></tbody></table></center>
<h2>The New Iterator Requirements</h2>
<h3>Notation</h3>
<table>
<tbody>
<tr>
<td><tt>X</tt></td>
<td>The iterator type.</td></tr>
<tr>
<td><tt>T</tt></td>
<td>The value type of <tt>X</tt>, i.e.,
<tt>std::iterator_traits&lt;X&gt;::value_type</tt>.</td></tr>
<tr>
<td><tt>x</tt>, <tt>y</tt></td>
<td>An object of type <tt>X</tt>.</td></tr>
<tr>
<td><tt>t</tt></td>
<td>An object of type <tt>T</tt>.</td></tr></tbody></table>
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_ReadableIterator"></a>Readable Iterator </h3>A Readable
Iterator is an iterator that dereferences to produce an rvalue that is
convertible to the <tt>value_type</tt> of the iterator.
<h3>Associated Types</h3>
<table border="1">
<tbody>
<tr>
<td>Value type</td>
<td><tt>std::iterator_traits&lt;X&gt;::value_type</tt></td>
<td>The type of the objects pointed to by the iterator.</td></tr>
<tr>
<td>Reference type</td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td>
<td>The return type of dereferencing the iterator. This type must be
convertible to <tt>T</tt>. </td></tr>
<tr>
<td>Return Category</td>
<td><tt>std::return_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::readable_iterator_tag</tt>
</td></tr></tbody></table>
<h3>Refinement of</h3><a href="http://www.boost.org/libs/utility/CopyConstructible.html">Copy
Constructible</a>
<h3>Valid expressions</h3>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Type requirements</th>
<th>Return type</th></tr>
<tr>
<td>Dereference</td>
<td><tt>*x</tt></td>
<td> </td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td></tr>
<tr>
<td>Member access</td>
<td><tt>x-&gt;m</tt></td>
<td><tt>T</tt> is a type with a member named <tt>m</tt>.</td>
<td>If <tt>m</tt> is a data member, the type of <tt>m</tt>. If <tt>m</tt>
is a member function, the return type of <tt>m</tt>. </td></tr></tbody></table>
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_WritableIterator"></a>Writable Iterator </h3>A Writable
Iterator is an iterator that can be used to store a value using the
dereference-assignment expression.
<h3>Definitions</h3>If <tt>x</tt> is an Writable Iterator of type <tt>X</tt>,
then the expression <tt>*x = a;</tt> stores the value <tt>a</tt> into
<tt>x</tt>. Note that <tt>operator=</tt>, like other C++ functions, may be
overloaded; it may, in fact, even be a template function. In general, then,
<tt>a</tt> may be any of several different types. A type <tt>A</tt> belongs to
the <i>set of value types</i> of <tt>X</tt> if, for an object <tt>a</tt> of type
<tt>A</tt>, <tt>*x = a;</tt> is well-defined and does not require performing any
non-trivial conversions on <tt>a</tt>.
<h3>Associated Types</h3>
<table border="1">
<tbody>
<tr>
<td>Return Category</td>
<td><tt>std::return_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::writable_iterator_tag</tt>
</td></tr></tbody></table>
<h3>Refinement of</h3><a href="http://www.boost.org/libs/utility/CopyConstructible.html">Copy
Constructible</a>
<h3>Valid expressions</h3>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Return type</th></tr>
<tr>
<td>Dereference assignment</td>
<td><tt>*x = a</tt></td>
<td>unspecified</td></tr></tbody></table>
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_SwappableIterator"></a>Swappable Iterator </h3>A Swappable
Iterator is an iterator whose dereferenced values can be swapped.
<p>Note: the requirements for Swappable Iterator are dependent on the issues
surrounding <tt>std::swap()</tt> being resolved. Here we assume that the issue
will be resolved by allowing the overload of <tt>std::swap()</tt> for
user-defined types.
</p><p>Note: Readable Iterator and Writable Iterator combined implies Swappable
Iterator because of the fully templated <tt>std::swap()</tt>. However, Swappable
Iterator does not imply Readable Iterator nor Writable Iterator.
</p><h3>Associated Types</h3>
<table border="1">
<tbody>
<tr>
<td>Return Category</td>
<td><tt>std::return_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::swappable_iterator_tag</tt>
</td></tr></tbody></table>
<h3>Valid expressions</h3>Of the two valid expressions listed below, only one
<b>OR</b> the other is required. If <tt>std::iter_swap()</tt> is overloaded for
<tt>X</tt> then <tt>std::swap()</tt> is not required. If
<tt>std::iter_swap()</tt> is not overloaded for <tt>X</tt> then the default
(fully templated) version is used, which will call <tt>std::swap()</tt> (this
means changing the current requirements for <tt>std::iter_swap()</tt>).
<p>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Return type</th></tr>
<tr>
<td>Iterator Swap</td>
<td><tt>std::iter_swap(x, y)</tt></td>
<td>void</td></tr>
<tr>
<td>Dereference and Swap</td>
<td><tt>std::swap(*x, *y)</tt></td>
<td>void</td></tr></tbody></table>
</p><p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_ConstantLvalueIterator"></a>Constant Lvalue Iterator </h3>A
Constant Lvalue Iterator is an iterator that dereferences to produce a const
reference to the pointed-to object, i.e., the associated <tt>reference</tt> type
is <tt>const T&amp;</tt>. Changing the value of or destroying an iterator that
models Constant Lvalue Iterator does not invalidate pointers and references
previously obtained from that iterator.
<h3>Refinement of</h3><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ReadableIterator">Readable
Iterator</a>
<h3>Associated Types</h3>
<table border="1">
<tbody>
<tr>
<td>Reference type</td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td>
<td>The return type of dereferencing the iterator, which must be <tt>const
T&amp;</tt>. </td></tr><!-- I don't think this is needed
<tr>
<td>Pointer type</td>
<td><tt>std::iterator_traits&lt;X&gt;::pointer</tt></td>
<td>
The pointer to the value type, which must be <tt>const T*</tt>.
</td>
</tr>
-->
<tr>
<td>Return Category</td>
<td><tt>std::return_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::constant_lvalue_iterator_tag</tt>
</td></tr></tbody></table><!-- these are not necessary now that we use reference as operator* return type
<h3>Valid expressions</h3>
<Table border>
<tr><TH>Name</TH><TH>Expression</TH><TH>Type requirements</TH><TH>Return type</TH></tr>
<tr>
<td>Dereference</td>
<td><tt>*x</tt></td>
<td>&nbsp;</td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td>
</tr>
<tr>
<td>Member access</td>
<td><tt>x-&gt;m</tt></td>
<td><tt>T</tt> is a type with a member named <tt>m</tt>.</td>
<td>
&nbsp;
</td>
</tr>
</table>
-->
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_MutableLvalueIterator"></a>Mutable Lvalue Iterator </h3>A
Mutable Lvalue Iterator is an iterator that dereferences to produce a reference
to the pointed-to object. The associated <tt>reference</tt> type is
<tt>T&amp;</tt>. Changing the value of or destroying an iterator that models
Mutable Lvalue Iterator does not invalidate pointers and references previously
obtained from that iterator.
<h3>Refinement of</h3><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ReadableIterator">Readable
Iterator</a>, <a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_WritableIterator">Writable
Iterator</a>, and <a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_SwappableIterator">Swappable
Iterator</a>.
<h3>Associated Types</h3>
<table border="1">
<tbody>
<tr>
<td>Reference type</td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td>
<td>The return type of dereferencing the iterator, which must be
<tt>T&amp;</tt>.</td></tr><!-- I don't think this is necessary
<tr>
<td>Pointer type</td>
<td><tt>std::iterator_traits&lt;X&gt;::pointer</tt></td>
<td>
The pointer to the value type, which is <tt>T*</tt>.
</td>
</tr>
-->
<tr>
<td>Return Category</td>
<td><tt>std::return_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::mutable_lvalue_iterator_tag</tt>
</td></tr></tbody></table><!-- no longer needed since the return type is specified as reference in the readable iterator
<h3>Valid expressions</h3>
<Table border>
<tr><TH>Name</TH><TH>Expression</TH><TH>Type requirements</TH><TH>Return type</TH></tr>
<tr>
<td>Dereference</td>
<td><tt>*x</tt></td>
<td>&nbsp;</td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td>
</tr>
<tr>
<td>Member access</td>
<td><tt>x-&gt;m</tt></td>
<td><tt>T</tt> is a type with a member named <tt>m</tt>.</td>
<td>
&nbsp;
</td>
</tr>
</table>
-->
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_ForwardTraversalIterator"></a>Forward Traversal Iterator
</h3>The Forward Iterator is an iterator that can be incremented. Also, it is
permissible to make multiple passes through the iterator's range.
<h3>Refinement of</h3><a href="http://www.boost.org/libs/utility/CopyConstructible.html">Copy
Constructible</a>, <a href="http://www.boost.org/libs/utility/Assignable.html">Assignable</a>, <a href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default
Constructible</a>, and <a href="http://www.sgi.com/tech/stl/EqualityComparable.html">Equality
Comparable</a>
<h3>Associated types</h3>
<table border="1">
<tbody>
<tr>
<td>Difference Type</td>
<td><tt>std::iterator_traits&lt;X&gt;::difference_type</tt></td>
<td>A signed integral type used for representing distances between
iterators that point into the same range. </td></tr>
<tr>
<td>Traversal Category</td>
<td><tt>std::traversal_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::forward_traversal_tag</tt>
</td></tr></tbody></table>
<h3>Valid expressions</h3>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Type requirements</th>
<th>Return type</th></tr>
<tr>
<td>Preincrement</td>
<td><tt>++i</tt></td>
<td> </td>
<td><tt>X&amp;</tt></td></tr>
<tr>
<td>Postincrement</td>
<td><tt>i++</tt></td>
<td> </td>
<td>convertible to <tt>const X&amp;</tt></td></tr></tbody></table>
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_BidirectionalTraversalIterator"></a>Bidirectional Traversal
Iterator </h3>An iterator that can be incremented and decremented.
<h3>Refinement of</h3><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ForwardTraversalIterator">Forward
Traversal Iterator</a>
<h3>Associated types</h3>
<table border="1">
<tbody>
<tr>
<td>Traversal Category</td>
<td><tt>std::traversal_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::bidirectional_traversal_tag</tt>
</td></tr></tbody></table>
<h3>Valid expressions</h3>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Type requirements</th>
<th>Return type</th></tr>
<tr>
<td>Predecrement</td>
<td><tt>--i</tt></td>
<td> </td>
<td><tt>X&amp;</tt></td></tr>
<tr>
<td>Postdecrement</td>
<td><tt>i--</tt></td>
<td> </td>
<td>convertible to <tt>const X&amp;</tt></td></tr></tbody></table>
<p>
</p><hr>
<!--------------------------------------------------------------------------->
<h3><a name="concept_RandomAccessTraversalIterator"></a>Random Access Traversal
Iterator </h3>An iterator that provides constant-time methods for moving forward
and backward in arbitrary-sized steps.
<h3>Refinement of</h3><a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_BidirectionalTraversalIterator">Bidirectional
Traversal Iterator</a> and <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">Less Than
Comparable</a> where <tt>&lt;</tt> is a total ordering
<h3>Associated types</h3>
<table border="1">
<tbody>
<tr>
<td>Traversal Category</td>
<td><tt>std::traversal_category&lt;X&gt;::type</tt></td>
<td>A type convertible to <tt>std::random_access_traversal_tag</tt>
</td></tr></tbody></table>
<h3>Valid expressions</h3>
<table border="1">
<tbody>
<tr>
<th>Name</th>
<th>Expression</th>
<th>Type requirements</th>
<th>Return type</th></tr>
<tr>
<td>Iterator addition</td>
<td><tt>i += n</tt></td>
<td> </td>
<td><tt>X&amp;</tt></td></tr>
<tr>
<td>Iterator addition</td>
<td><tt>i + n</tt> or <tt>n + i</tt></td>
<td> </td>
<td><tt>X</tt></td></tr>
<tr>
<td>Iterator subtraction</td>
<td><tt>i -= n</tt></td>
<td> </td>
<td><tt>X&amp;</tt></td></tr>
<tr>
<td>Iterator subtraction</td>
<td><tt>i - n</tt></td>
<td> </td>
<td><tt>X</tt></td></tr>
<tr>
<td>Difference</td>
<td><tt>i - j</tt></td>
<td> </td>
<td><tt>std::iterator_traits&lt;X&gt;::difference_type</tt></td></tr>
<tr>
<td>Element operator</td>
<td><tt>i[n]</tt></td>
<td><tt>X</tt> must also be a model of <a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_ReadableIterator">Readable
Iterator</a>. </td>
<td><tt>std::iterator_traits&lt;X&gt;::reference</tt></td></tr>
<tr>
<td>Element assignment</td>
<td><tt>i[n] = t</tt></td>
<td><tt>X</tt> must also be a model of <a href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept_WritableIterator">Writable
Iterator</a>.</td>
<td>unspecified</td></tr></tbody></table>
<p>
</p><hr>
<!-- LocalWords: HTML BGCOLOR FFFFFF TR TD Siek HREF mailto jsiek
--><!-- LocalWords: lsc edu tt const href http anubis dkuug dk JTC SC WG docs lt
--><!-- LocalWords: lwg html bool gt Sutter's htm Lvalue namespace std struct
--><!-- LocalWords: lvalue typename OldTraits reusability min iter prev inplace
--><!-- LocalWords: rvalue templated Preincrement Postincrement Predecrement
--><!-- LocalWords: Postdecrement
--></body></html>

View File

@@ -58,6 +58,7 @@ The following is a list of work that is intended for the near future
<li> Pursue and document performance issues related to compilers and
implementation.
<li> More comprehensive examples of using the library components.
<li> Extensive rewrite of the user documentation to make it more accessible.
</ol>
<hr>
@@ -67,7 +68,7 @@ The following is a list of work that is intended for the near future
</address>
<!-- Created: Fri Jun 29 10:53:07 EST 2001 -->
<!-- hhmts start -->
Last modified: Mon May 6 16:28:15 EST 2002
Last modified: Wed Jan 8 18:09:46 EST 2003
<!-- hhmts end -->
</body>

View File

@@ -10,6 +10,8 @@
// and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org/libs/multi_array for documentation.
#ifndef BOOST_MULTI_ARRAY_RG071801_HPP
#define BOOST_MULTI_ARRAY_RG071801_HPP
@@ -33,7 +35,20 @@
#include <numeric>
#include <vector>
namespace boost {
namespace detail {
namespace multi_array {
struct populate_index_ranges {
multi_array_types::index_range
operator()(multi_array_types::index base,
multi_array_types::size_type extent) {
return multi_array_types::index_range(base,base+extent);
}
};
} //namespace multi_array
} // namespace detail
template<typename T, std::size_t NumDims,
typename Allocator>
@@ -133,7 +148,7 @@ public:
const_sub_array<T,NumDims,OPtr>& rhs) :
super_type(rhs) {
allocate_space();
std::copy(rhs.begin(),rhs.end(),begin());
std::copy(rhs.begin(),rhs.end(),this->begin());
}
// For some reason, gcc 2.95.2 doesn't pick the above template
@@ -143,7 +158,7 @@ public:
sub_array<T,NumDims>& rhs) :
super_type(rhs) {
allocate_space();
std::copy(rhs.begin(),rhs.end(),begin());
std::copy(rhs.begin(),rhs.end(),this->begin());
}
// Since assignment is a deep copy, multi_array_ref
@@ -162,6 +177,70 @@ public:
}
multi_array& resize(const detail::multi_array
::extent_gen<NumDims>& ranges) {
// build a multi_array with the specs given
multi_array new_array(ranges);
// build a view of tmp with the minimum extents
// Get the minimum extents of the arrays.
boost::array<size_type,NumDims> min_extents;
const size_type& (*min)(const size_type&, const size_type&) =
std::min<size_type>;
std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
this->extent_list_.begin(),
min_extents.begin(),
min);
// typedef boost::array<index,NumDims> index_list;
// Build index_gen objects to create views with the same shape
// these need to be separate to handle non-zero index bases
typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
index_gen old_idxes;
index_gen new_idxes;
std::transform(new_array.index_base_list_.begin(),
new_array.index_base_list_.end(),
min_extents.begin(),old_idxes.ranges_.begin(),
detail::multi_array::populate_index_ranges());
std::transform(this->index_base_list_.begin(),
this->index_base_list_.end(),
min_extents.begin(),new_idxes.ranges_.begin(),
detail::multi_array::populate_index_ranges());
// Build same-shape views of the two arrays
typename multi_array::array_view<3>::type view_old = (*this)[old_idxes];
typename multi_array::array_view<3>::type view_new = new_array[new_idxes];
// Set the right portion of the new array
view_new = view_old;
using std::swap;
// Swap the internals of these arrays.
swap(this->super_type::base_,new_array.super_type::base_);
swap(this->storage_,new_array.storage_);
swap(this->extent_list_,new_array.extent_list_);
swap(this->stride_list_,new_array.stride_list_);
swap(this->index_base_list_,new_array.index_base_list_);
swap(this->origin_offset_,new_array.origin_offset_);
swap(this->directional_offset_,new_array.directional_offset_);
swap(this->num_elements_,new_array.num_elements_);
swap(this->allocator_,new_array.allocator_);
swap(this->base_,new_array.base_);
swap(this->allocated_elements_,new_array.allocated_elements_);
return *this;
}
~multi_array() {
deallocate_space();
}
@@ -169,9 +248,9 @@ public:
private:
void allocate_space() {
typename Allocator::const_pointer no_hint=0;
base_ = allocator_.allocate(super_type::num_elements(),no_hint);
super_type::set_base_ptr(base_);
allocated_elements_ = super_type::num_elements();
base_ = allocator_.allocate(this->num_elements(),no_hint);
this->set_base_ptr(base_);
allocated_elements_ = this->num_elements();
std::uninitialized_fill_n(base_,allocated_elements_,T());
}

View File

@@ -97,7 +97,7 @@ public:
template <class IteratorAdaptor, class DifferenceType>
static void advance(IteratorAdaptor& x, DifferenceType n) {
x.idx_ += n;
x.base().idx_ += n;
}
template <class IteratorAdaptor1, class IteratorAdaptor2>

View File

@@ -142,14 +142,14 @@ public:
detail::multi_array::CollectionConcept<BaseList> >();
boost::copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
this->calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
}
void reindex(index value) {
index_base_list_.assign(value);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
this->calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
}
@@ -162,10 +162,10 @@ public:
size_type(1),std::multiplies<size_type>()));
std::copy(extents.begin(),extents.end(),extent_list_.begin());
compute_strides(stride_list_,extent_list_,storage_);
this->compute_strides(stride_list_,extent_list_,storage_);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
this->calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
}
@@ -368,13 +368,13 @@ private:
1,std::multiplies<index>());
assert(num_elements_ != 0);
compute_strides(stride_list_,extent_list_,storage_);
this->compute_strides(stride_list_,extent_list_,storage_);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
this->calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
directional_offset_ =
calculate_descending_dimension_offset(stride_list_,extent_list_,
this->calculate_descending_dimension_offset(stride_list_,extent_list_,
storage_);
}
};
@@ -455,11 +455,11 @@ public:
ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
std::copy(other.begin(),other.end(),this->begin());
return *this;
}
@@ -467,18 +467,18 @@ public:
if (&other != this) {
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
std::copy(other.begin(),other.end(),this->begin());
}
return *this;
}
element* origin() { return base_+origin_offset_; }
element* origin() { return super_type::base_+super_type::origin_offset_; }
element* data() { return base_; }
element* data() { return super_type::base_; }
template <class IndexList>
element& operator()(const IndexList& indices) {
@@ -486,15 +486,15 @@ public:
detail::multi_array::CollectionConcept<IndexList> >();
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
indices,this->strides());
}
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,origin(),
shape(),strides(),
index_bases());
this->shape(),this->strides(),
this->index_bases());
}
@@ -511,21 +511,22 @@ public:
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
this->shape(),
this->strides(),
this->index_bases(),
origin());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),shape(),
strides(),index_bases()));
return iterator(iter_base(*this->index_bases(),origin(),this->shape(),
this->strides(),this->index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
return iterator(iter_base(*this->index_bases()+*this->shape(),origin(),
this->shape(),this->strides(),
this->index_bases()));
}
// RG - rbegin() and rend() written naively to thwart MSVC ICE.
@@ -555,7 +556,8 @@ public:
const_reference operator[](index idx) const {
return super_type::access(boost::type<const_reference>(),
idx,origin(),
shape(),strides(),index_bases());
this->shape(),this->strides(),
this->index_bases());
}
// See note attached to generate_array_view in base.hpp

View File

@@ -235,9 +235,9 @@ public:
ConstMultiArray, NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
return *this;
@@ -247,21 +247,22 @@ public:
sub_array& operator=(const sub_array& other) {
if (&other != this) {
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
}
return *this;
}
T* origin() { return base_; }
const T* origin() const { return base_; }
T* origin() { return this->base_; }
const T* origin() const { return this->base_; }
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,base_,shape(),strides(),index_bases());
idx,this->base_,this->shape(),this->strides(),
this->index_bases());
}
// see generate_array_view in base.hpp
@@ -277,9 +278,9 @@ public:
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
this->shape(),
this->strides(),
this->index_bases(),
origin());
}
@@ -287,17 +288,17 @@ public:
element& operator()(const IndexList& indices) {
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
indices,this->strides());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
return iterator(iter_base(*this->index_bases(),origin(),
this->shape(),this->strides(),this->index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
return iterator(iter_base(*this->index_bases()+*this->shape(),origin(),
this->shape(),this->strides(),this->index_bases()));
}
// RG - rbegin() and rend() written naively to thwart MSVC ICE.

View File

@@ -76,13 +76,13 @@ public:
void reindex(const BaseList& values) {
boost::copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
origin_offset_ =
calculate_indexing_offset(stride_list_,index_base_list_);
this->calculate_indexing_offset(stride_list_,index_base_list_);
}
void reindex(index value) {
index_base_list_.assign(value);
origin_offset_ =
calculate_indexing_offset(stride_list_,index_base_list_);
this->calculate_indexing_offset(stride_list_,index_base_list_);
}
size_type num_dimensions() const { return NumDims; }
@@ -291,9 +291,9 @@ public:
ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
return *this;
@@ -303,30 +303,30 @@ public:
multi_array_view& operator=(const multi_array_view& other) {
if (&other != this) {
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
assert(other.num_dimensions() == this->num_dimensions());
assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
this->shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
}
return *this;
}
element* origin() { return base_+origin_offset_; }
element* origin() { return this->base_+this->origin_offset_; }
template <class IndexList>
element& operator()(const IndexList& indices) {
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
indices,this->strides());
}
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,origin(),
shape(),strides(),
index_bases());
this->shape(),this->strides(),
this->index_bases());
}
@@ -343,21 +343,23 @@ public:
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
this->shape(),
this->strides(),
this->index_bases(),
origin());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
return iterator(iter_base(*this->index_bases(),origin(),
this->shape(),this->strides(),
this->index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
return iterator(iter_base(*this->index_bases()+*this->shape(),origin(),
this->shape(),this->strides(),
this->index_bases()));
}
reverse_iterator rbegin() {

View File

@@ -9,6 +9,11 @@
#include <algorithm>
#include <iostream>
bool equal(const int& a, const int& b)
{
return a == b;
}
template <typename ArrayA, typename ArrayB>
bool equal(const ArrayA& A, const ArrayB& B)
{
@@ -20,11 +25,6 @@ bool equal(const ArrayA& A, const ArrayB& B)
return true;
}
bool equal(const int& a, const int& b)
{
return a == b;
}
template <typename Array>
void access(Array& A, const mutable_array_tag&) {

View File

@@ -10,9 +10,12 @@
#include <algorithm>
#include <list>
void check_shape(const double&, std::size_t*, int*, unsigned int)
{}
template <class Array>
void check_shape(const Array& A,
unsigned int* sizes,
std::size_t* sizes,
int* strides,
unsigned int num_elements)
{
@@ -23,8 +26,11 @@ void check_shape(const Array& A,
check_shape(A[0], ++sizes, ++strides, num_elements / A.size());
}
void check_shape(const double&, unsigned int*, int*, unsigned int)
{}
bool equal(const double& a, const double& b)
{
return a == b;
}
template <typename ArrayA, typename ArrayB>
bool equal(const ArrayA& A, const ArrayB& B)
@@ -36,10 +42,6 @@ bool equal(const ArrayA& A, const ArrayB& B)
return false;
return true;
}
bool equal(const double& a, const double& b)
{
return a == b;
}
int

69
test/resize.cpp Normal file
View File

@@ -0,0 +1,69 @@
//
// resize.cpp - Test of resizing multi_arrays
//
#include "boost/multi_array.hpp"
#include <iostream>
using namespace std;
template <typename Array>
void print(std::ostream& os, const Array& A)
{
typename Array::const_iterator i;
os << "[";
for (i = A.begin(); i != A.end(); ++i) {
print(os, *i);
if (boost::next(i) != A.end())
os << ',';
}
os << "]";
}
void print(std::ostream& os, const int& x)
{
os << x;
}
int main() {
typedef boost::multi_array<int,3> marray;
int A_data[] = {
0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13,14,15,
16,17,18,19,
20,21,22,23
};
marray A(boost::extents[2][3][4]);
A.assign(A_data,A_data+(2*3*4));
A.resize(boost::extents[4][3][2]);
int A_resize[] = {
0,1,
4,5,
8,9,
12,13,
16,17,
20,21,
0,0,
0,0,
0,0,
0,0,
0,0,
0,0
};
assert(std::equal(A_resize,A_resize+(4*3*2),A.data()));
}