mirror of
https://github.com/boostorg/multi_array.git
synced 2026-01-25 18:32:13 +00:00
Compare commits
15 Commits
boost-1.29
...
boost-1.30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77b637777d | ||
|
|
cd7b6f7c52 | ||
|
|
98f7604258 | ||
|
|
c563bf58fb | ||
|
|
84d65a8402 | ||
|
|
da922535c2 | ||
|
|
b8bf7a5fcd | ||
|
|
ef89b81e7c | ||
|
|
080c2a7c9b | ||
|
|
9c3949fb67 | ||
|
|
0e55920979 | ||
|
|
7683594b36 | ||
|
|
7ed9d30cc9 | ||
|
|
e5909ce409 | ||
|
|
8387e84d8f |
733
doc/iterator_categories.html
Normal file
733
doc/iterator_categories.html
Normal 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&</tt> (or <tt>const T&</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&</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<bool>::iterator</tt> is almost a random access iterator, but
|
||||
the return type is not <tt>bool&</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<bool></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 <typename Iterator>
|
||||
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<Iterator> 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 <typename T>
|
||||
struct return_category<T*>
|
||||
{
|
||||
<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 <typename Iterator>
|
||||
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<Iterator> 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 <typename T>
|
||||
struct traversal_category<T*>
|
||||
{
|
||||
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>-> 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>-> Swappable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>fill</td>
|
||||
<td rowspan="2">Forward Iterator<br>-> Forward Traversal Iterator and
|
||||
Writable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>generate</td></tr>
|
||||
<tr>
|
||||
<td>swap_ranges</td>
|
||||
<td rowspan="2">Forward Iterator<br>-> Forward Traversal Iterator and
|
||||
Swappable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>rotate</td></tr>
|
||||
<tr>
|
||||
<td>replace</td>
|
||||
<td rowspan="5">Forward Iterator<br>-> 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>-> Bidirectional Traversal
|
||||
Iterator and Swappable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>partition</td></tr>
|
||||
<tr>
|
||||
<td>copy_backwards</td>
|
||||
<td>Bidirectional Iterator<br>-> Bidirectional Traversal Iterator and
|
||||
Readable Iterator<br>Bidirectional Iterator<br>-> Bidirectional
|
||||
Traversal Iterator and Writable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>next_permutation</td>
|
||||
<td rowspan="2">Bidirectional Iterator<br>-> 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>-> 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>-> Bidirectional Traversal Iterator and
|
||||
Readable Iterator </td></tr>
|
||||
<tr>
|
||||
<td>random_shuffle</td>
|
||||
<td rowspan="9">Random Access Iterator<br>-> 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<X>::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<X>::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<X>::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<X>::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<X>::reference</tt></td></tr>
|
||||
<tr>
|
||||
<td>Member access</td>
|
||||
<td><tt>x->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<X>::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<X>::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&</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<X>::reference</tt></td>
|
||||
<td>The return type of dereferencing the iterator, which must be <tt>const
|
||||
T&</tt>. </td></tr><!-- I don't think this is needed
|
||||
<tr>
|
||||
<td>Pointer type</td>
|
||||
<td><tt>std::iterator_traits<X>::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<X>::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> </td>
|
||||
<td><tt>std::iterator_traits<X>::reference</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Member access</td>
|
||||
<td><tt>x->m</tt></td>
|
||||
<td><tt>T</tt> is a type with a member named <tt>m</tt>.</td>
|
||||
<td>
|
||||
|
||||
</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&</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<X>::reference</tt></td>
|
||||
<td>The return type of dereferencing the iterator, which must be
|
||||
<tt>T&</tt>.</td></tr><!-- I don't think this is necessary
|
||||
<tr>
|
||||
<td>Pointer type</td>
|
||||
<td><tt>std::iterator_traits<X>::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<X>::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> </td>
|
||||
<td><tt>std::iterator_traits<X>::reference</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Member access</td>
|
||||
<td><tt>x->m</tt></td>
|
||||
<td><tt>T</tt> is a type with a member named <tt>m</tt>.</td>
|
||||
<td>
|
||||
|
||||
</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<X>::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<X>::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&</tt></td></tr>
|
||||
<tr>
|
||||
<td>Postincrement</td>
|
||||
<td><tt>i++</tt></td>
|
||||
<td> </td>
|
||||
<td>convertible to <tt>const X&</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<X>::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&</tt></td></tr>
|
||||
<tr>
|
||||
<td>Postdecrement</td>
|
||||
<td><tt>i--</tt></td>
|
||||
<td> </td>
|
||||
<td>convertible to <tt>const X&</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><</tt> is a total ordering
|
||||
<h3>Associated types</h3>
|
||||
<table border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Traversal Category</td>
|
||||
<td><tt>std::traversal_category<X>::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&</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&</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<X>::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<X>::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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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&) {
|
||||
|
||||
@@ -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
69
test/resize.cpp
Normal 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()));
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user