Initial submission to Boost.

[SVN r13915]
This commit is contained in:
Ronald Garcia
2002-05-15 16:08:54 +00:00
commit 685b7e4c37
81 changed files with 12953 additions and 0 deletions

96
.gitattributes vendored Normal file
View File

@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

648
doc/Collection.html Normal file
View File

@@ -0,0 +1,648 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Collection</Title>
</HEAD>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<h1>
<img src="../../../c++boost.gif" alt="boost logo"
width="277" align="middle" height="86">
<br>Collection
</h1>
<h3>Description</h3>
A Collection is a <i>concept</i> similar to the STL <a
href="http://www.sgi.com/Technology/STL/Container.html">Container</a>
concept. A Collection provides iterators for accessing a range of
elements and provides information about the number of elements in the
Collection. However, a Collection has fewer requirements than a
Container. The motivation for the Collection concept is that there are
many useful Container-like types that do not meet the full
requirements of Container, and many algorithms that can be written
with this reduced set of requirements. To summarize the reduction
in requirements:
<UL>
<LI>It is not required to &quot;own&quot; its elements: the lifetime
of an element in a Collection does not have to match the lifetime of
the Collection object, though the lifetime of the element should cover
the lifetime of the Collection object.
<LI>The semantics of copying a Collection object is not defined (it
could be a deep or shallow copy or not even support copying).
<LI>The associated reference type of a Collection does
not have to be a real C++ reference.
</UL>
Because of the reduced requirements, some care must be taken when
writing code that is meant to be generic for all Collection types.
In particular, a Collection object should be passed by-reference
since assumptions can not be made about the behaviour of the
copy constructor.
<p>
<h3>Associated types</h3>
<Table border>
<TR>
<TD VAlign=top>
Value type
</TD>
<TD VAlign=top>
<tt>X::value_type</tt>
</TD>
<TD VAlign=top>
The type of the object stored in a Collection.
If the Collection is <i>mutable</i> then
the value type must be <A
href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</A>.
Otherwise the value type must be <a href="./CopyConstructible.html">CopyConstructible</a>.
</TD>
</TR>
<TR>
<TD VAlign=top>
Iterator type
</TD>
<TD VAlign=top>
<tt>X::iterator</tt>
</TD>
<TD VAlign=top>
The type of iterator used to iterate through a Collection's
elements. The iterator's value type is expected to be the
Collection's value type. A conversion
from the iterator type to the const iterator type must exist.
The iterator type must be an <A href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</A>.
</TD>
</TR>
<TR>
<TD VAlign=top>
Const iterator type
</TD>
<TD VAlign=top>
<tt>X::const_iterator</tt>
</TD>
<TD VAlign=top>
A type of iterator that may be used to examine, but not to modify,
a Collection's elements.
</TD>
</TR>
<TR>
<TD VAlign=top>
Reference type
</TD>
<TD VAlign=top>
<tt>X::reference</tt>
</TD>
<TD VAlign=top>
A type that behaves like a reference to the Collection's value type.
<a href="#1">[1]</a>
</TD>
</TR>
<TR>
<TD VAlign=top>
Const reference type
</TD>
<TD VAlign=top>
<tt>X::const_reference</tt>
</TD>
<TD VAlign=top>
A type that behaves like a const reference to the Collection's value type.
</TD>
</TR>
<TR>
<TD VAlign=top>
Pointer type
</TD>
<TD VAlign=top>
<tt>X::pointer</tt>
</TD>
<TD VAlign=top>
A type that behaves as a pointer to the Collection's value type.
</TD>
</TR>
<TR>
<TD VAlign=top>
Distance type
</TD>
<TD VAlign=top>
<tt>X::difference_type</tt>
</TD>
<TD VAlign=top>
A signed integral type used to represent the distance between two
of the Collection's iterators. This type must be the same as
the iterator's distance type.
</TD>
</TR>
<TR>
<TD VAlign=top>
Size type
</TD>
<TD VAlign=top>
<tt>X::size_type</tt>
</TD>
<TD VAlign=top>
An unsigned integral type that can represent any nonnegative value
of the Collection's distance type.
</TD>
</tr>
</table>
<h3>Notation</h3>
<Table>
<TR>
<TD VAlign=top>
<tt>X</tt>
</TD>
<TD VAlign=top>
A type that is a model of Collection.
</TD>
</TR>
<TR>
<TD VAlign=top>
<tt>a</tt>, <tt>b</tt>
</TD>
<TD VAlign=top>
Object of type <tt>X</tt>.
</TD>
</TR>
<TR>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
The value type of <tt>X</tt>.
</TD>
</tr>
</table>
<h3>Valid expressions</h3>
The following expressions must be valid.
<p>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
</TR>
<TR>
<TD VAlign=top>
Beginning of range
</TD>
<TD VAlign=top>
<tt>a.begin()</tt>
</TD>
<TD VAlign=top>
<tt>iterator</tt> if <tt>a</tt> is mutable, <tt>const_iterator</tt> otherwise
</TD>
</TR>
<TR>
<TD VAlign=top>
End of range
</TD>
<TD VAlign=top>
<tt>a.end()</tt>
</TD>
<TD VAlign=top>
<tt>iterator</tt> if <tt>a</tt> is mutable, <tt>const_iterator</tt> otherwise
</TD>
</TR>
<TR>
<TD VAlign=top>
Size
</TD>
<TD VAlign=top>
<tt>a.size()</tt>
</TD>
<TD VAlign=top>
<tt>size_type</tt>
</TD>
</TR>
<!--
<TR>
<TD VAlign=top>
Maximum size
</TD>
<TD VAlign=top>
<tt>a.max_size()</tt>
</TD>
<TD VAlign=top>
<tt>size_type</tt>
</TD>
</TR>
<TR>
-->
<TD VAlign=top>
Empty Collection
</TD>
<TD VAlign=top>
<tt>a.empty()</tt>
</TD>
<TD VAlign=top>
Convertible to <tt>bool</tt>
</TD>
</TR>
<TR>
<TD VAlign=top>
Swap
</TD>
<TD VAlign=top>
<tt>a.swap(b)</tt>
</TD>
<TD VAlign=top>
<tt>void</tt>
</TD>
</tr>
</table>
<h3>Expression semantics</h3>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Semantics
</TH>
<TH>
Postcondition
</TH>
</TR>
<TD VAlign=top>
<TR>
<TD VAlign=top>
Beginning of range
</TD>
<TD VAlign=top>
<tt>a.begin()</tt>
</TD>
<TD VAlign=top>
Returns an iterator pointing to the first element in the Collection.
</TD>
<TD VAlign=top>
<tt>a.begin()</tt> is either dereferenceable or past-the-end. It is
past-the-end if and only if <tt>a.size() == 0</tt>.
</TD>
</TR>
<TR>
<TD VAlign=top>
End of range
</TD>
<TD VAlign=top>
<tt>a.end()</tt>
</TD>
<TD VAlign=top>
Returns an iterator pointing one past the last element in the
Collection.
</TD>
<TD VAlign=top>
<tt>a.end()</tt> is past-the-end.
</TD>
</TR>
<TR>
<TD VAlign=top>
Size
</TD>
<TD VAlign=top>
<tt>a.size()</tt>
</TD>
<TD VAlign=top>
Returns the size of the Collection, that is, its number of elements.
</TD>
<TD VAlign=top>
<tt>a.size() &gt;= 0
</TD>
</TR>
<!--
<TR>
<TD VAlign=top>
Maximum size
</TD>
<TD VAlign=top>
<tt>a.max_size()</tt>
</TD>
<TD VAlign=top>
&nbsp;
</TD>
<TD VAlign=top>
Returns the largest size that this Collection can ever have. <A href="#8">[8]</A>
</TD>
<TD VAlign=top>
<tt>a.max_size() &gt;= 0 &amp;&amp; a.max_size() &gt;= a.size()</tt>
</TD>
</TR>
-->
<TR>
<TD VAlign=top>
Empty Collection
</TD>
<TD VAlign=top>
<tt>a.empty()</tt>
</TD>
<TD VAlign=top>
Equivalent to <tt>a.size() == 0</tt>. (But possibly faster.)
</TD>
<TD VAlign=top>
&nbsp;
</TD>
</TR>
<TR>
<TD VAlign=top>
Swap
</TD>
<TD VAlign=top>
<tt>a.swap(b)</tt>
</TD>
<TD VAlign=top>
Equivalent to <tt>swap(a,b)</tt>
</TD>
<TD VAlign=top>
&nbsp;
</TD>
</tr>
</table>
<h3>Complexity guarantees</h3>
<tt>begin()</tt> and <tt>end()</tt> are amortized constant time.
<P>
<tt>size()</tt> is at most linear in the Collection's
size. <tt>empty()</tt> is amortized constant time.
<P>
<tt>swap()</tt> is at most linear in the size of the two collections.
<h3>Invariants</h3>
<Table border>
<TR>
<TD VAlign=top>
Valid range
</TD>
<TD VAlign=top>
For any Collection <tt>a</tt>, <tt>[a.begin(), a.end())</tt> is a valid
range.
</TD>
</TR>
<TR>
<TD VAlign=top>
Range size
</TD>
<TD VAlign=top>
<tt>a.size()</tt> is equal to the distance from <tt>a.begin()</tt> to <tt>a.end()</tt>.
</TD>
</TR>
<TR>
<TD VAlign=top>
Completeness
</TD>
<TD VAlign=top>
An algorithm that iterates through the range <tt>[a.begin(), a.end())</tt>
will pass through every element of <tt>a</tt>.
</TD>
</tr>
</table>
<h3>Models</h3>
<UL>
<LI> <tt>array</tt>
<LI> <tt>array_ptr</tt>
<LI> <tt>vector&lt;bool&gt;</tt>
</UL>
<h3>Collection Refinements</h3>
There are quite a few concepts that refine the Collection concept,
similar to the concepts that refine the Container concept. Here
is a brief overview of the refining concepts.
<h4>ForwardCollection</h4>
The elements are arranged in some order that
does not change spontaneously from one iteration to the next. As
a result, a ForwardCollection is
<A
href="http://www.sgi.com/Technology/STL/EqualityComparable.html">EqualityComparable</A>
and
<A
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">LessThanComparable</A>.
In addition, the iterator type of a ForwardCollection is a
MultiPassInputIterator which is just an InputIterator with the added
requirements that the iterator can be used to make multiple passes
through a range, and that if <tt>it1 == it2</tt> and <tt>it1</tt> is
dereferenceable then <tt>++it1 == ++it2</tt>. The ForwardCollection
also has a <tt>front()</tt> method.
<p>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
<TH>
Semantics
</TH>
</TR>
<TR>
<TD VAlign=top>
Font
</TD>
<TD VAlign=top>
<tt>a.front()</tt>
</TD>
<TD VAlign=top>
<tt>reference</tt> if <tt>a</tt> is mutable, <br> <tt>const_reference</tt>
otherwise.
</TD>
<TD VAlign=top>
Equivalent to <tt>*(a.first())</tt>.
</TD>
</TR>
</table>
<h4>ReversibleCollection</h4>
The container provides access to iterators that traverse in both
directions (forward and reverse). The iterator type must meet all of
the requirements of
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">BidirectionalIterator</a>
except that the reference type does not have to be a real C++
reference. The ReversibleCollection adds the following requirements
to those of ForwardCollection.
<p>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
<TH>
Semantics
</TH>
</TR>
<TR>
<TD VAlign=top>
Beginning of range
</TD>
<TD VAlign=top>
<tt>a.rbegin()</tt>
</TD>
<TD VAlign=top>
<tt>reverse_iterator</tt> if <tt>a</tt> is mutable,
<tt>const_reverse_iterator</tt> otherwise.
</TD>
<TD VAlign=top>
Equivalent to <tt>X::reverse_iterator(a.end())</tt>.
</TD>
</TR>
<TR>
<TD VAlign=top>
End of range
</TD>
<TD VAlign=top>
<tt>a.rend()</tt>
</TD>
<TD VAlign=top>
<tt>reverse_iterator</tt> if <tt>a</tt> is mutable,
<tt>const_reverse_iterator</tt> otherwise.
</TD>
<TD VAlign=top>
Equivalent to <tt>X::reverse_iterator(a.begin())</tt>.
</TD>
</tr>
<TR>
<TD VAlign=top>
Back
</TD>
<TD VAlign=top>
<tt>a.back()</tt>
</TD>
<TD VAlign=top>
<tt>reference</tt> if <tt>a</tt> is mutable, <br> <tt>const_reference</tt>
otherwise.
</TD>
<TD VAlign=top>
Equivalent to <tt>*(--a.end())</tt>.
</TD>
</TR>
</table>
<h4>SequentialCollection</h4>
The elements are arranged in a strict linear order. No extra methods
are required.
<h4>RandomAccessCollection</h4>
The iterators of a RandomAccessCollection satisfy all of the
requirements of <a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">RandomAccessIterator</a>
except that the reference type does not have to be a real C++
reference. In addition, a RandomAccessCollection provides
an element access operator.
<p>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
<TH>
Semantics
</TH>
</TR>
<TR>
<TD VAlign=top>
Element Access
</TD>
<TD VAlign=top>
<tt>a[n]</tt>
</TD>
<TD VAlign=top>
<tt>reference</tt> if <tt>a</tt> is mutable,
<tt>const_reference</tt> otherwise.
</TD>
<TD VAlign=top>
Returns the nth element of the Collection.
<tt>n</tt> must be convertible to <tt>size_type</tt>.
Precondition: <tt>0 &lt;= n &lt; a.size()</tt>.
</TD>
</TR>
</table>
<h3>Notes</h3>
<P><A name="1">[1]</A>
The reference type does not have to be a real C++ reference. The
requirements of the reference type depend on the context within which
the Collection is being used. Specifically it depends on the
requirements the context places on the value type of the Collection.
The reference type of the Collection must meet the same requirements
as the value type. In addition, the reference objects must be
equivalent to the value type objects in the collection (which is
trivially true if they are the same object). Also, in a mutable
Collection, an assignment to the reference object must result in an
assignment to the object in the Collection (again, which is trivially
true if they are the same object, but non-trivial if the reference
type is a proxy class).
<h3>See also</h3>
<A href="http://www.sgi.com/Technology/STL/Container.html">Container</A>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame and C++ Library & Compiler Group/SGI (<A HREF="mailto:jsiek@engr.sgi.com">jsiek@engr.sgi.com</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

44
doc/index.html Normal file
View File

@@ -0,0 +1,44 @@
<html><head>
<title>MultiDimensional Array Libary</title></head>
<body bgcolor="#ffffff" text="#000000">
<table border="1" bgcolor="#007f7f" cellpadding="2">
<tbody><tr>
<td bgcolor="#ffffff">
<img src="../../../c++boost.gif" alt="boost logo"
width="277" align="middle" height="86"></td>
<td><a href="http://www.boost.org/index.htm"><font face="Arial" color="#ffffff"><big>Home</big></font></a></td>
<td><a href="http://www.boost.org/libs/libraries.htm"><font face="Arial" color="#ffffff"><big>Libraries</big></font></a></td>
<td><a href="http://www.boost.org/people/people.htm"><font face="Arial" color="#ffffff"><big>People</big></font></a></td>
<td><a href="http://www.boost.org/more/faq.htm"><font face="Arial" color="#ffffff"><big>FAQ</big></font></a></td>
<td><a href="http://www.boost.org/more/index.htm"><font face="Arial" color="#ffffff"><big>More</big></font></a></td>
</tr>
</tbody></table>
<h1>Boost.MultiArray</h1>
<p>Boost.MultiArray provides a generic N-dimensional array concept
definition and common implementations of that interface.
</p>
<ul>
<li><a href="./user.html">User Documentation and Tutorial</a> </li>
<li><a href="./reference.html">Reference Documentation</a> </li>
<li><a href="./test_cases.html">Test Cases and their Descriptions</a> </li>
<li><a href="./notes.html">Miscellaneous Notes</a> </li>
</ul>
<br>
<hr>
<table>
<tr valign=top>
<td nowrap>Copyright &copy 2000-2001</td><td>
<a href=http://www.osl.iu.edu/~garcia>Ronald Garcia</a>,
Indiana University (<a
HREF="mailto:garcia@osl.iu.edu">garcia@osl.iu.edu</a>)<br>
<a href="../../../people/jeremy_siek.htm">Jeremy Siek</a>,
Indiana University (<a
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>)<br>
<a href=http://www.osl.iu.edu/~lums>Andrew Lumsdaine</a>,
Indiana University (<a
HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>)
</td></tr></table>
</body></html>

BIN
doc/matrix.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

74
doc/notes.html Normal file
View File

@@ -0,0 +1,74 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
== Copyright (c) Ronald Garcia, Jeremy Siek 2001
==
== Permission to use, copy, modify, distribute and sell this software
== and its documentation for any purpose is hereby granted without fee,
== provided that the above copyright notice appears in all copies and
== that both that copyright notice and this permission notice appear
== in supporting documentation. Jeremy Siek makes no
== representations about the suitability of this software for any
== purpose. It is provided "as is" without express or implied warranty.
-->
<head>
<title>Boost.MultiArray: Extra Notes</title>
</head>
<body>
<h1>
<img src="../../../c++boost.gif" alt="boost logo"
width="277" align="middle" height="86">
<br>Boost.MultiArray: Extra Notes
<br>
</h1>
<a name="sec_compilers"></a>
<h2>Compiler Support</h2>
Boost.MultiArray was designed with compiler support in mind.
Interface compromises were kept to a minimum, but efforts were
made to account for C++ Standard compliance issues in compilers
that were popular at the time the library was written. That said,
Boost.MultiArray has been tested with the following compilers:
<ol>
<li> Gnu C++ Compiler v2.95.2 (compile with <tt>-ftemplate-depth-50</tt>)
<li> Gnu C++ Compiler v3.0.2
<li> Kuck and Associates C++ Compiler v4.0f
<li> Microsoft Visual C++ v6.0 sp5
<li> Comeau C++ Compiler v4.2.45 beta 2 (libcomo beta 14)
<li> Intel C++ Compiler v5.0 (with MS lib v6.0 sp5)
<li> Metrowerks CodeWarrior C++ Compiler v7.1
</ol>
Boost.MultiArray is known to NOT work with Borland C++ v5.5.1.
Support for this compiler is forthcoming.
<h2>Future Work</h2>
The following is a list of work that is intended for the near future
-- following the initial addition of the library to the Boost
distribution:
<ol>
<li> Pursue and document performance issues related to compilers and
implementation.
<li> More comprehensive examples of using the library components.
</ol>
<hr>
<address>
<a href="mailto:garcia@.cs.indiana.edu">Ronald Garcia</a>
</address>
<!-- Created: Fri Jun 29 10:53:07 EST 2001 -->
<!-- hhmts start -->
Last modified: Mon May 6 16:28:15 EST 2002
<!-- hhmts end -->
</body>
</html>

1265
doc/reference.html Normal file

File diff suppressed because it is too large Load Diff

294
doc/test_cases.html Normal file
View File

@@ -0,0 +1,294 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
== Copyright (c) Ronald Garcia, Jeremy Siek 2001
==
== Permission to use, copy, modify, distribute and sell this software
== and its documentation for any purpose is hereby granted without fee,
== provided that the above copyright notice appears in all copies and
== that both that copyright notice and this permission notice appear
== in supporting documentation. Jeremy Siek makes no
== representations about the suitability of this software for any
== purpose. It is provided "as is" without express or implied warranty.
-->
<head>
<title>
Boost.MultiArray: Test Descriptions
</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<IMG SRC="http://www.boost.org/c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<h1>Boost.MultiArray: Test Descriptions</h1>
The following is a description of the test cases that are included with
Boost.Multi_Array (B.M).
<h2>Terminology</h2>
The following list is to clarify the use of terms in the following
descriptions:
<ul>
<li> <b>B.M</b> - abbreviation for Boost.MultiArray.
<li><b>primary components</b> - refers to <tt>boost::multi_array</tt>,
<tt>boost::const_multi_array_ref</tt>, and
<tt>boost::multi_array_ref</tt>.
<li><b>array types</b> - refers to all the primary components, plus for each
primary component "array", the types <tt>array::const_subarray</tt>,
<tt>array::subarray</tt>, <tt>array::const_array_view</tt>, and
<tt>array::array_view </tt>
</ul>
<h2>Acceptance Tests</h2>
The following tests exercise various features of Boost.Multi_Array to
ensure proper operation at run time.
<table border="1" cellspacing="0" cellpadding="5"
summary="This table describes the test cases in the multi-array test
suite that should compile and run.">
<tr>
<td>Program</td>
<td>Description</td>
</tr>
<tr>
<td><a href="../test/constructors.cpp">libs/multi_array/test/constructors.cpp</a></td>
<td>
Exercises all of the constructors for B.M primary components.
</td>
</tr>
<tr>
<td><a href="../test/access.cpp">libs/multi_array/test/access.cpp</a></td>
<td>
Tests <tt>operator[]</tt> and <tt>operator()</tt> on all B.M array types.
</td>
</tr>
<tr>
<td><a href="../test/compare.cpp">libs/multi_array/test/compare.cpp</a></td>
<td>
Tests all comparison operators for the B.M primary components.
</td>
</tr>
<tr>
<td><a href="../test/iterators.cpp">libs/multi_array/test/iterators.cpp</a></td>
<td>
Test all iterator traversal and access functionality for all B.M array types.
</td>
</tr>
<tr>
<td><a href="../test/slice.cpp">libs/multi_array/test/slice.cpp</a></td>
<td>
Test all variations of subview generation for all B.M array types.
</td>
</tr>
<tr>
<td><a href="../test/assign.cpp">libs/multi_array/test/assign.cpp</a></td>
<td>
Tests out <tt>operator=()</tt> on the various B.M array types.
</td>
</tr>
<tr>
<td><a href="../test/index_bases.cpp">libs/multi_array/test/index_bases.cpp</a></td>
<td>
Test re-indexing functionality for the B.M primary components.
</td>
</tr>
<tr>
<td><a href="../test/storage_order.cpp">libs/multi_array/test/storage_order.cpp</a></td>
<td>
Test variations on storage_order for the B.M primary components.
</td>
</tr>
<tr>
<td><a href="../test/reshape.cpp">libs/multi_array/test/reshape.cpp</a></td>
<td>
Test re-shaping functionality for the B.M primary components.
</td>
</tr>
<tr>
<td><a href="../test/range1.cpp">libs/multi_array/test/range1.cpp</a></td>
<td>
Test the various syntaxes for specifying index ranges using
<tt>array::index_range</tt>.
</td>
</tr>
<tr>
<td><a href="../test/idxgen1.cpp">libs/multi_array/test/idxgen1.cpp</a></td>
<td>
Test the <tt>array::index_gen</tt> objects.
</td>
</tr>
<tr>
<td><a href="../test/stl_interaction.cpp">libs/multi_array/test/stl_interaction.cpp</a></td>
<td>
Test interaction between array types and STL containers.
</td>
</tr>
<tr>
<td><a href="../test/concept_checks.cpp">libs/multi_array/test/concept_checks.cpp</a></td>
<td>
Ensure that all the array types meet the defined Concepts.
</td>
</tr>
<tr>
<td><a href="../test/generative_tests.hpp">libs/multi_array/test/generative_tests.hpp</a></td>
<td>
A test harness used to simplify testing operations upon all array
types. Used by slice.cpp, iterators.cpp, and access.cpp.
</td>
</tr>
</table>
<h2>Compile-Fail Tests</h2>
The following tests check to make sure that various constructs not
accepted by the library fail to compile. Each test checks only
one fault in order to more easily ensure the cause of the
compilation failure.
<p>
<table border="1" cellspacing="0" cellpadding="5"
summary="This table describes the tests in the multi array test suite
that should fail to compile">
<tr>
<td>Program</td>
<td>Description</td>
</tr>
<tr>
<td><a href="../test/fail_cbracket.cpp">libs/multi_array/test/fail_cbracket.cpp</a>
<br><a href="../test/fail_ref_cbracket.cpp">libs/multi_array/test/fail_ref_cbracket.cpp</a></td>
<td>
<tt>operator[]</tt> on a const array must not modify elements.
</td>
</tr>
<tr>
<td><a href="../test/fail_cdata.cpp">libs/multi_array/test/fail_cdata.cpp</a>
<br><a href="../test/fail_ref_cdata.cpp">libs/multi_array/test/fail_ref_cdata.cpp</a></td>
<td>
<tt>array::data() const</tt> must return a pointer to const data.
</td>
</tr>
<tr>
<td><a href="../test/fail_citerator.cpp">libs/multi_array/test/fail_citerator.cpp</a>
<br><a href="../test/fail_ref_citerator.cpp">libs/multi_array/test/fail_ref_citerator.cpp</a></td>
<td>
<tt>const_iterator</tt> must not be convertible to <tt>iterator</tt>.
</td>
</tr>
<tr>
<td><a href="../test/fail_cparen.cpp">libs/multi_array/test/fail_cparen.cpp</a>
<br><a href="../test/fail_ref_cparen.cpp">libs/multi_array/test/fail_ref_cparen.cpp</a></td>
<td>
<tt>operator()</tt> on a const array must not modify elements.
</td>
</tr>
<tr>
<td><a href="../test/fail_criterator.cpp">libs/multi_array/test/fail_criterator.cpp</a>
<br><a href="../test/fail_ref_criterator.cpp">libs/multi_array/test/fail_ref_criterator.cpp</a></td>
<td>
<tt>const_reverse_iterator</tt> must not be convertible to
<tt>reverse_iterator</tt>.
</td>
</tr>
<tr>
<td><a href="../test/fail_csubarray.cpp">libs/multi_array/test/fail_csubarray.cpp</a>
<br><a href="../test/fail_ref_csubarray.cpp">libs/multi_array/test/fail_ref_csubarray.cpp</a></td>
<td>
<tt>const_subarray</tt> must not be convertible to <tt>subarray</tt>.
</td>
</tr>
<tr>
<td><a href="../test/fail_csubarray2.cpp">libs/multi_array/test/fail_csubarray2.cpp</a>
<br><a href="../test/fail_ref_csubarray2.cpp">libs/multi_array/test/fail_ref_csubarray2.cpp</a></td>
<td>
<tt>array::operator[] const</tt> must not be convertible to <tt>subarray</tt>.
</td>
</tr>
<tr>
<td><a href="../test/fail_csubarray3.cpp">libs/multi_array/test/fail_csubarray3.cpp</a>
<br><a href="../test/fail_ref_csubarray3.cpp">libs/multi_array/test/fail_ref_csubarray3.cpp</a></td>
<td>
<tt>const_subarray</tt> into an array must not modify elements.
</td>
</tr>
<tr>
<td><a href="../test/fail_cview.cpp">libs/multi_array/test/fail_cview.cpp</a>
<br><a href="../test/fail_ref_cview.cpp">libs/multi_array/test/fail_ref_cview.cpp</a></td>
<td>
<tt>const_array_view</tt> of an array must not modify elements.
</td>
</tr>
<tr>
<td><a href="../test/fail_cview2.cpp">libs/multi_array/test/fail_cview2.cpp</a>
<br><a href="../test/fail_ref_cview2.cpp">libs/multi_array/test/fail_ref_cview2.cpp</a></td>
<td>
<tt>array::operator[] const</tt> must not be convertible to
<tt>array_view</tt>.
</td>
</tr>
<tr>
<td><a href="../test/fail_cview3.cpp">libs/multi_array/test/fail_cview3.cpp</a>
<br><a href="../test/fail_ref_cview3.cpp">libs/multi_array/test/fail_ref_cview3.cpp</a></td>
<td>
<tt>const_array_view</tt> of an array must not modify elements.
</td>
</tr>
</table>
<br>
<table summary="Copyright information">
<tr valign="top">
<td nowrap>Copyright &copy; 2001</td>
<td><a href="../../../people/ronald_garcia.htm">Ronald Garcia</a>,
Indiana University (<a href=
"mailto:garcia@cs.indiana.edu">garcia@cs.indiana.edu</a>)<br>
<a href="../../../people/jeremy_siek.htm">Jeremy Siek</a>, Indiana
University (<a href=
"mailto:jsiek@cs.indiana.edu">jsiek@cs.indiana.edu</a>)<br>
<a href="http://www.lsc.nd.edu/~lums">Andrew Lumsdaine</a>, Indiana
University (<a href=
"mailto:lums@cs.indiana.edu">lums@cs.indiana.edu</a>)</td>
</tr>
</table>
<hr>
<address>
<a href="mailto:garcia@.cs.indiana.edu">Ronald Garcia</a>
</address>
<!-- hhmts start -->
Last modified: Wed Oct 31 19:46:44 EST 2001
<!-- hhmts end -->
</body>
</html>

624
doc/user.html Normal file
View File

@@ -0,0 +1,624 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
== Copyright (c) Ronald Garcia, Jeremy Siek 2001
==
== Permission to use, copy, modify, distribute and sell this software
== and its documentation for any purpose is hereby granted without fee,
== provided that the above copyright notice appears in all copies and
== that both that copyright notice and this permission notice appear
== in supporting documentation. Jeremy Siek makes no
== representations about the suitability of this software for any
== purpose. It is provided "as is" without express or implied warranty.
-->
<head>
<title>The Boost Multidimensional Array Library (Boost.MultiArray)</title>
</head>
<body>
<h1>
<img src="../../../c++boost.gif" alt="boost logo"
width="277" align="middle" height="86">
<br>The Boost Multidimensional Array Library
<br>(Boost.MultiArray)
</h1>
<h2>Synopsis</h2>
<p>
The Boost Multidimensional Array Library provides
a multidimensional container of elements and semantically equivalent
adaptors for arrays of contiguous data. The classes in this library
behave as closely as possible to STL Containers, providing a more
convenient and efficient implementation than the equivalent "vectors
of vectors" formulation of N-dimensional arrays. Arrays are not
re-sizable once constructed, but may be sliced and shaped, providing
alternate views of the contained data.
<h2>Table of Contents</h2>
<ol>
<li><a href="#sec_rationale">Rationale</a>
<li><a href="#sec_related">Related Work</a>
<li><a href="#sec_example">Short Example</a>
<li><a href="#sec_components">MultiArray Components</a>
<li><a href="#sec_assignment">Construction and Assignment</a>
<li><a href="#sec_types">Associated Types</a>
<li><a href="#sec_generators">Array View and Subarray Type Generators</a>
<li><a href="#sec_dimensions">Specifying Array Dimensions</a>
<li><a href="#sec_access">Accessing Elements</a>
<li><a href="#sec_views">Creating Views</a>
<li><a href="#sec_storage">Storage Ordering</a>
<li><a href="#sec_base">Setting the Array Base</a>
<li><a href="#sec_reshape">Changing an Array's Shape</a>
<li><a href="#sec_concepts">MultiArray Concepts</a>
<li><a href="#sec_testcases">Test Cases</a>
</ol>
<a name="sec_rationale"></a>
<h2>Rationale</h2>
The C++ standard library provides several generic containers, but
it does not provide any multidimensional array types.
Using <tt>std::vector</tt>, you can simulate N-dimensional arrays as
"nested vectors", but the
interface is unwieldy and the memory overhead can be quite high. You can also
use a native C++ arrays (i.e. <tt>int arr[2][2][2];</tt>),
or a dynamically allocated array of contigous data which you treat as
a multidimensional array. Using
<a href="../../array_traits/index.html">array_traits</a>,
you can extract from a statically defined C++ array
iterators over its dimensions.
In either case, however, dimensional data may be lost if it is
passed to a function that is not properly specialized to accept
it. Beyond the above, neither the <tt>std::vector</tt> nor C++ array-based
solution provides a convenient method of honing in upon a specific
subset or "view" of a multi-dimensional array.
<p>Boost.MultiArray defines the MultiArray concept, a generic
interface for N-dimensional containers. The primary components of
this library model MultiArray and support adapting user data
to model MultiArray as well.
<a name="sec_related"></a>
<h2>Related Work</h2>
<a href="../../array/index.html">boost::array</a>
and <a href="http://www.sgi.com/tech/stl/Vector.html">std::vector</a> are
one-dimensional containers of user data. Both manage their own
memory. <tt>std::valarray</tt> is a low-level
C++ Standard Library component
meant to provide portable high performance for numerical applications.
<a href="http://www.oonumerics.org/blitz/">Blitz++</a> is
an array library developed by Todd
Veldhuizen. It uses
advanced C++ techniques to provide near-Fortran performance for
array-based numerical applications.
<a href="../../array_traits/index.html">array_traits</a> is a beta
library distributed with Boost that provides a means to create
iterators over native C++ arrays.
This library is analogous to
<a href="">boost::array</a> in that it augments C style N-dimensional
arrays, as <tt>boost::array</tt> does for C one-dimensional arrays.
<a name="sec_example"></a>
<h2>Short Example</h2>
What follows is a brief example of the use of <tt>multi_array</tt>:
<blockquote>
<pre>
#include "boost/multi_array.hpp"
#include &lt;cassert&gt;
int
main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array&lt;double, 3&gt; array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
</pre>
</blockquote>
<a name="sec_components"></a>
<h2>MultiArray Components</h2>
Boost.MultiArray provides three user-level class templates:
<ol>
<li><a href="multi_array.html"><tt>multi_array</tt></a> -
defined in "boost/multi_array.hpp",
<li><a href="multi_array_ref.html"><tt>multi_array_ref</tt></a> -
defined in "boost/multi_array_ref.hpp", and
<li><a href="const_multi_array_ref.html"><tt>const_multi_array_ref</tt></a> -
defined in "boost/multi_array_ref.hpp"
</ol>
<tt>multi_array</tt> is a container template. When instantiated, it
allocates space for the number of elements corresponding to the
dimensions specified at construction time.
<p>
<tt>multi_array_ref</tt> adapts an existing array of data to provide
the <tt>multi_array</tt> interface. <tt>multi_array_ref</tt> does not own the
data passed to it.
<p>
<tt>const_multi_array_ref</tt> is similar to <tt>multi_array_ref</tt>
but guarantees that the contents of the array are immutable. It can
thus wrap pointers of type <i>T const*</i>.
<p>
The three components exhibit very similar behavior. Aside from
constructor parameters, <tt>multi_array</tt> and
<tt>multi_array_ref</tt> export the same interface.
<tt>const_multi_array_ref</tt> provides only the const portions
of the <tt>multi_array_ref</tt> interface.
<a name="sec_assignment"></a>
<h2>Construction and Assignment</h2>
<p>Each of the array types -
<a href="multi_array.html"><tt>multi_array</tt></a>,
<a href="multi_array_ref.html"><tt>multi_array_ref</tt></a>, and
<a href="const_multi_array_ref.html"><tt>const_multi_array_ref</tt></a> -
provides a specialized set of constructors. For further information,
consult their reference pages.
<p>All of the non-const array types in this library provide assignment
operators<tt>operator=()</tt>. Each of the array types <tt>multi_array</tt>,
<tt>multi_array_ref</tt>, <tt>subarray</tt>, and
<tt>array_view</tt> can be assigned from any
of the others, so long as their shapes match. The
const variants, <tt>const_multi_array_ref</tt>,
<tt>const_subarray</tt>, and <tt>const_array_view</tt>, can be the
source of a copy to an array with matching shape.
Assignment results in a deep (element by element) copy of the data
contained within an array.
<a name="sec_generators"></a>
<h2>Array View and Subarray Type Generators</h2>
In some situations, the use of nested generators for array_view and
subarray types is inconvenient. For example, inside a
function template parameterized upon array type, the extra
"template" keywords can be obfuscating. More likely though, some
compilers cannot handle templates nested within template parameters.
For this reason the type generators, <tt>subarray_gen</tt>,
<tt>const_subarray_gen</tt>, <tt>array_view_gen</tt>, and
<tt>const_array_view_gen</tt> are provided. Thus, the two typedefs
in the following example result in the same type:
<blockquote>
<pre>
template &lt;typename Array&gt;
void my_function() {
typedef typename Array::template array_view&lt;3&gt;::type view1_t;
typedef typename boost::array_view_gen&lt;Array,3&gt;::type view2_t;
// ...
}
</pre>
</blockquote>
<a name="sec_dimensions"></a>
<h2>Specifying Array Dimensions</h2>
When creating one of the Boost.MultiArray components, it is necessary
to specify both the number of dimensions and the extent of each.
Though the number of dimensions is always specified as a template
parameter, two separate mechanisms have been provided to specify the
extent of each.
<p>The first method involves passing a
<a href="./Collection.html">
Collection</a> of extents to a
constructor, most commonly a <tt>boost::array</tt>. The constructor
will retrieve the beginning iterator from the container and retrieve N
elements, corresponding to extents for the N dimensions. This is
useful for writing dimension-independent code.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
boost::array&lt;array_type::index, 3&gt; shape = {{ 3, 4, 2 }};
array_type A(shape);
</pre>
</blockquote>
<p>The second method involves passing the constructor an <tt>extent_gen</tt>
object, specifying the matrix dimensions. By default, the library constructs a
global <tt>extent_gen</tt> object <tt>boost::extents</tt>. In case of
concern about memory used by these objects, defining
<tt>BOOST_MULTI_ARRAY_NO_GENERATORS</tt> before including the library
header inhibits its construction.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
array_type A(boost::extents[3][4][2]);
</pre>
</blockquote>
<a name="sec_access"></a>
<h2>Accessing Elements</h2>
The Boost.MultiArray components provide two ways of accessing
specific elements within a container. The first uses the traditional
C array notation, provided by <tt>operator[]</tt>.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
array_type A(boost::extents[3][4][2]);
A[0][0][0] = 3.14;
assert(A[0][0][0] == 3.14);
</pre>
</blockquote>
<p> The second method involves passing a
<a href="./Collection.html">
Collection</a> of indices to <tt>operator()</tt>. N indices will be retrieved
from the Collection for the N dimensions of the container.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
array_type A(boost::extents[3][4][2]);
boost::array&lt;array_type::index,3&gt; idx = {{0,0,0}};
A(idx) = 3.14;
assert(A(idx) == 3.14);
</pre>
</blockquote>
This can be useful for writing dimension-independent code, and under
some compilers may yield higher performance than <tt>operator[].</tt>
<a name="sec_views:"></a>
<h2>Creating Views</h2>
Boost.MultiArray provides the facilities for creating a sub-view of an
already existing array component. It allows you to create a sub-view that
retains the same number of dimensions as the original array or one
that has less dimensions than the original as well.
<p>Sub-view creation occurs by placing a call to operator[], passing it
an <tt>index_gen</tt> type. The <tt>index_gen</tt> is populated by
passing <tt>index_range</tt> objects to its <tt>operator[]</tt>.
Similar to <tt>boost::extents</tt>, the library by default constructs
the object <tt>boost::indices</tt>. You can suppress this object
by defining <tt>BOOST_MULTI_ARRAY_NO_GENERATORS</tt> before
including the library header. A simple sub-view creation example follows.
<h3>Example</h3>
<blockquote>
<pre>
// myarray = 2 x 3 x 4
//
// array_view dims: [base,bound) (dimension striding default = 1)
// dim 0: [0,2)
// dim 1: [1,3)
// dim 2: [0,4) (strided by 2),
//
typedef array_type::index_range range;
array_type::array_view&lt;3&gt;::type myview =
myarray[ boost::indices[range(0,2)][range(1,3)][range(0,4,2)] ];
for (array_type::index i = 0; i != 2; ++i)
for (array_type::index j = 0; j != 2; ++j)
for (array_type::index k = 0; k != 2; ++k)
assert(myview[i][j][k] == myarray[i][j+1][k*2]);
</pre>
</blockquote>
<p>By passing an integral value to the index_gen, one may create a
subview with fewer dimensions than the original array component (also
called slicing).
<h3>Example</h3>
<blockquote>
<pre>
// myarray = 2 x 3 x 4
//
// array_view dims:
// [base,stride,bound)
// [0,1,2), 1, [0,2,4)
//
typedef array_type::index_range range;
array_type::index_gen indices;
array_type::array_view&lt;2&gt;::type myview =
myarray[ indices[range(0,2)][1][range(0,4,2)] ];
for (array_type::index i = 0; i != 2; ++i)
for (array_type::index j = 0; j != 2; ++j)
assert(myview[i][j] == myarray[i][1][j*2]);
</pre>
</blockquote>
<h3>More on <tt>index_range</tt></h3>
The <tt>index_range</tt> type provides several methods of specifying
ranges for subview generation. Here are a few range instantiations
that specify the same range.
<h3>Example</h3>
<blockquote>
<pre>
// [base,stride,bound)
// [0,2,4)
typedef array_type::index_range range;
range a_range;
a_range = range(0,4,2);
a_range = range().start(0).finish(4).stride(2);
a_range = range().start(0).stride(2).finish(4);
a_range = 0 &lt;= range().stride(2) &lt; 4;
a_range = 0 &lt;= range().stride(2) &lt;= 3;
</pre>
</blockquote>
An <tt>index_range</tt> object passed to a slicing operation will
inherit its start and/or finish value from the array being sliced if
you do not supply one. This conveniently prevents you from having to
know the bounds of the array dimension in certain cases. For example,
the default-constructed range will take the full extent of the
dimension it is used to specify.
<h3>Example</h3>
<blockquote>
<pre>
typedef array_type::index_range range;
range a_range;
// All elements in this dimension
a_range = range();
// indices i where 3 &lt;= i
a_range = range().start(3)
a_range = 3 &lt;= range();
a_range = 2 &lt; range();
// indices i where i &lt; 7
a_range = range().finish(7)
a_range = range() &lt; 7;
a_range = range() &lt;= 6;
</pre>
</blockquote>
The following example slicing operations exhibit some of the
alternatives shown above
<blockquote>
<pre>
// take all of dimension 1
// take i &lt; 5 for dimension 2
// take 4 &lt;= j &lt;= 7 for dimension 3 with stride 2
myarray[ boost::indices[range()][range() &lt; 5 ][4 &lt;= range().stride(2) &lt;= 7] ];
</pre>
</blockquote>
<a name="sec_storage"></a>
<h2>Storage Ordering</h2>
Each array class provides constructors that accept a storage ordering
parameter. This is most
useful when interfacing with legacy codes that require an ordering
different from standard C, such as FORTRAN. The possibilities are
<tt>c_storage_order</tt>, <tt>fortran_storage_order</tt>, and
<tt>general_storage_order</tt>.
<p><tt>c_storage_order</tt>, which is the default, will store elements
in memory in the same order as a C array would, that is, the
dimensions are stored from last to first.
<p><tt>fortran_storage_order</tt> will store elements in memory in the same order
as FORTRAN would: from the first dimension to
the last. Note that with use of this parameter, the array
indices will remain zero-based.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double,3&gt; array_type;
array_type A(boost::extents[3][4][2],boost::fortran_storage_order);
call_fortran_function(A.data());
</pre>
</blockquote>
<p><tt>general_storage_order</tt> allows one to customize both the order in
which dimensions are stored in memory and whether dimensions are
stored in ascending or descending order.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::general_storage_order&lt;3&gt; storage;
typedef boost::multi_array&lt;int,3&gt; array_type;
// Store last dimension, then first, then middle
array_type::size_type ordering[] = {2,0,1};
// Store the first dimension(dimension 0) in descending order
bool ascending[] = {false,true,true};
array_type A(extents[3][4][2],storage(ordering,ascending));
</pre>
</blockquote>
<a name="sec_base"></a>
<h2>Setting The Array Base</h2>
In some situations, it may be inconvenient or awkward to use an
array that is zero-based.
the Boost.MultiArray components provide two facilities for changing the
bases of an array. One may specify a pair of range values to
the extent_gen constructor in order to set the base value.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
typedef array_type::extent_range range;
array_type::extent_gen extents;
// dimension 0: 0-based
// dimension 1: 1-based
// dimension 2: -1 - based
array_type A(extents[2][range(1,4)][range(-1,3)]);
</pre>
</blockquote>
<p>
An alternative is to first construct the array normally then
reset the bases. To set all bases to the same value, use the
<tt>reindex</tt> member function, passing it a single new index value.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
typedef array_type::extent_range range;
array_type::extent_gen extents;
array_type A(extents[2][3][4]);
// change to 1-based
A.reindex(1)
</pre>
</blockquote>
<p>
An alternative is to set each base separately using the
<tt>reindex</tt> member function, passing it a Collection of index bases.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
typedef array_type::extent_range range;
array_type::extent_gen extents;
// dimension 0: 0-based
// dimension 1: 1-based
// dimension 2: (-1)-based
array_type A(extents[2][3][4]);
boost::array&lt;array_type::index,ndims&gt; bases = {{0, 1, -1}};
A.reindex(bases);
</pre>
</blockquote>
<a name="sec_reshape"></a>
<h2>Changing an Array's Shape</h2>
The Boost.MultiArray arrays provide a reshape operation. While the
number of dimensions must remain the same, the shape of the array may
change so long as the total number of
elements contained remains the same.
<h3>Example</h3>
<blockquote>
<pre>
typedef boost::multi_array&lt;double, 3&gt; array_type;
typedef array_type::extent_range range;
array_type::extent_gen extents;
array_type A(extents[2][3][4]);
boost::array&lt;array_type::index,ndims&gt; dims = {{4, 3, 2}};
A.reshape(dims);
</pre>
</blockquote>
<p>
Note that reshaping an array does not affect the indexing.
<a name="sec_concepts"></a>
<h2>MultiArray Concepts</h2>
Boost.MultiArray defines and uses several concepts throughout:
<ul>
<li><a href="Mutable_Multi_Array.html">Mutable Multi-Array</a> -
Specifies N-dimensional containers whose values can be
altered. Both <tt>multi_array</tt> and <tt>multi_array_ref</tt>
model this.
<li><a href="Const_Multi_Array.html">Const Multi-Array</a> -
Specifies N-dimensional containers whose contents cannot be
modified. <tt>const_multi_array_ref</tt> models this.
</ul>
<a name="sec_testcases"></a>
<h2>Test Cases</h2>
Boost.MultiArray comes with a suite of test cases meant to exercise
the features and semantics of the library. A description of the test
cases can be found <a href="./test_cases.html">here</a>.
<h2>Credits</h2>
<ul>
<li><a href="mailto:garcia@osl.iu.edu">Ronald Garcia</a>
is the primary author of the library.
<li><a href="../../../people/jeremy_siek.htm">Jeremy Siek</a>
helped with the library and provided a sounding board for ideas,
advice, and assistance porting to Microsoft Visual C++.
<li><a href="mailto:gbavestrelli@yahoo.com">Giovanni Bavestrelli</a>
provided an early implementation of an
N-dimensional array which inspired feedback from the
<a href="http://www.boost.org/">Boost</a> mailing list
members. Some design decisions in this work were based upon this
implementation and the comments it elicited.
<li><a href="mailto:tveldhui@acm.org">Todd Veldhuizen</a> wrote
<a href="http://oonumerics.org/blitz/">Blitz++</a>, which
inspired some aspects of this design. In addition, he supplied
feedback on the design and implementation of the library.
<li><a href="mailto:jewillco@osl.iu.edu">Jeremiah Willcock</a>
provided feedback on the implementation and design of the
library and some suggestions for features.
<li><a href="mailto:bdawes@acm.org">Beman Dawes</a>
helped immensely with porting the library to Microsoft Windows
compilers.
</ul>
<hr>
<address>
<a href="mailto:garcia@.cs.indiana.edu">Ronald Garcia</a>
</address>
<!-- Created: Fri Jun 29 10:53:07 EST 2001 -->
<!-- hhmts start -->
Last modified: Mon May 6 14:48:18 EST 2002
<!-- hhmts end -->
</body>
</html>

1002
doc/xml/MultiArray.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
<sect2 id="const_multi_array_ref">
<title><literal>const_multi_array_ref</literal></title>
<para>
<literal>const_multi_array_ref</literal> is a multi-dimensional container
adaptor. It provides the MultiArray interface over any contiguous
block of elements. <literal>const_multi_array_ref</literal> exports the
same interface as <literal>multi_array</literal>, with the exception
of the constructors.
</para>
<formalpara>
<title>Model Of.</title>
<para>
<literal>const_multi_array_ref</literal> models
<link linkend="MultiArray">MultiArray</link>,
<ulink url="../../../libs/utility/CopyConstructible.html">CopyConstructible</ulink>.
and depending on the element type, it may also model
<ulink url="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</ulink> and <ulink url="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</ulink>.
Detailed descriptions are provided here only for operations that are
not described in the <literal>multi_array</literal> reference.
</para>
</formalpara>
<formalpara>
<title>Synopsis</title>
<programlisting>
<![CDATA[
namespace boost {
template <typename ValueType,
std::size_t NumDims,
typename Allocator = std::allocator<ValueType> >
class const_multi_array_ref {
public:
// types:
typedef ValueType element;
typedef *implementation-defined* value_type;
typedef *implementation-defined* reference;
typedef *implementation-defined* const_reference;
typedef *implementation-defined* difference_type;
typedef *implementation-defined* iterator;
typedef *implementation-defined* const_iterator;
typedef *implementation-defined* reverse_iterator;
typedef *implementation-defined* const_reverse_iterator;
typedef multi_array_types::size_type size_type;
typedef multi_array_types::index index;
typedef multi_array_types::index_gen index_gen;
typedef multi_array_types::index_range index_range;
typedef multi_array_types::extent_gen extent_gen;
typedef multi_array_types::extent_range extent_range;
// template typedefs
template <std::size_t Dims> struct subarray;
template <std::size_t Dims> struct const_subarray;
template <std::size_t Dims> struct array_view;
template <std::size_t Dims> struct const_array_view;
// structors
template <typename ExtentList>
explicit const_multi_array_ref(const element* data, const ExtentList& sizes,
const storage_order& store = c_storage_order());
explicit const_multi_array_ref(const element* data, const extents_tuple& ranges,
const storage_order& store = c_storage_order());
const_multi_array_ref(const const_multi_array_ref& x);
~const_multi_array_ref();
// iterators:
const_iterator begin() const;
const_iterator end() const;
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
// capacity:
size_type size() const;
size_type num_elements() const;
size_type num_dimensions() const;
// element access:
template <typename IndexList>
const element& operator()(const IndexList& indices) const;
const_reference operator[](index i) const;
const_array_view<Dims>::type operator[](const indices_tuple& r) const;
// queries
const element* data() const;
const element* origin() const;
const size_type* shape() const;
const index* strides() const;
const index* index_bases() const;
// comparators
bool operator==(const const_multi_array_ref& rhs);
bool operator!=(const const_multi_array_ref& rhs);
bool operator<(const const_multi_array_ref& rhs);
bool operator>(const const_multi_array_ref& rhs);
bool operator>=(const const_multi_array_ref& rhs);
bool operator<=(const const_multi_array_ref& rhs);
// modifiers:
template <typename SizeList>
void reshape(const SizeList& sizes)
template <typename BaseList> void reindex(const BaseList& values);
void reindex(index value);
};
]]>
</programlisting>
</formalpara>
<formalpara>
<title>Constructors</title>
<variablelist>
<varlistentry>
<term><programlisting>template &lt;typename ExtentList&gt;
explicit const_multi_array_ref(const element* data,
const ExtentList&amp; sizes,
const storage_order&amp; store = c_storage_order());
</programlisting></term>
<listitem>
<para>
This constructs a <literal>const_multi_array_ref</literal> using the specified
parameters. <literal>sizes</literal> specifies the shape of the
constructed <literal>const_multi_array_ref</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions.
</para>
<formalpara><title><literal>ExtentList</literal> Requirements</title>
<para>
<literal>ExtentList</literal> must model <ulink url="./Collection.html">Collection</ulink>.
</para>
</formalpara>
<formalpara><title>Preconditions</title>
<para><literal>sizes.size() == NumDims;</literal></para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting><![CDATA[explicit const_multi_array_ref(const element* data,
extent_gen::gen_type<NumDims>::type ranges,
const storage_order& store = c_storage_order());]]>
</programlisting></term>
<listitem>
<formalpara><title>Effects</title>
<para>
This constructs a <literal>const_multi_array_ref</literal> using the specified
parameters. <literal>ranges</literal> specifies the shape and
index bases of the constructed const_multi_array_ref. It is the result of
<literal>NumDims</literal> chained calls to
<literal>extent_gen::operator[]</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions.
</para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term><programlisting>
<![CDATA[const_multi_array_ref(const const_multi_array_ref& x);]]>
</programlisting></term>
<listitem>
<formalpara>
<title>Effects</title>
<para>This constructs a shallow copy of <literal>x</literal>.
</para></formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
</sect2>

71
doc/xml/main.xml Normal file
View File

@@ -0,0 +1,71 @@
<?xml version='1.0' encoding="ISO-Latin-1" ?>
<!DOCTYPE article
PUBLIC "-//OASIS//DTD DocBook XML MathML V4.1.2//EN"
"/home/rgarcia/docbook-xml/docbookx.dtd"
>
<article>
<articleinfo>
<title>Class template <literal>multi_array</literal></title>
<author>
<surname>Garcia</surname><firstname>Ronald</firstname>
<affiliation>
<orgname>Indiana University</orgname>
<orgdiv>Open Systems Lab</orgdiv>
</affiliation>
</author>
<orgname>BOOST</orgname>
<copyright>
<year>2002</year>
<holder>Ronald Garcia</holder>
</copyright>
<legalnotice>
<para>blah blah legal blah blah</para>
</legalnotice>
<revhistory>
<revision>
<revnumber>1</revnumber>
<date>1/18/2002</date>
<revdescription>
<simpara>Initial Revision.</simpara>
</revdescription>
</revision>
</revhistory>
</articleinfo>
Boost.MultiArray
Headers boost/multi_array.hpp and
boost/multi_array_ref.hpp
Motivation
Examples
Tutorial
Reference Manual
Comparison to Other Libraries
Performance
Portability
Design Rationale
Acknowledgements
FAQ
Motivation
Examples
*Insert examples here*
(External Tutorial)
(External Reference Manual)
Comparison to Other Libraries
Performance
Portability
Design Rationale
Acknowledgements
FAQ

299
doc/xml/multi_array.xml Normal file
View File

@@ -0,0 +1,299 @@
<sect2 id="multi_array">
<title><literal>multi_array</literal></title>
<para>
<literal>multi_array</literal> is a multi-dimensional container that
supports random access iteration. Its number of dimensions is
fixed at compile time, but its shape and the number of elements it
contains are specified during its construction. The number of elements
will remain fixed for the duration of a
<literal>multi_array</literal>'s lifetime, but the shape of the container can
be changed. A <literal>multi_array</literal> manages its data elements
using a replaceable allocator.
</para>
<formalpara>
<title>Model Of.</title>
<para>
<link linkend="MultiArray">MultiArray</link>,
<ulink url="../../../libs/utility/CopyConstructible.html">CopyConstructible</ulink>. Depending on the element type,
it may also model <ulink url="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</ulink> and <ulink url="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</ulink>.
</para>
</formalpara>
<formalpara>
<title>Synopsis</title>
<programlisting>
<![CDATA[
namespace boost {
template <typename ValueType,
std::size_t NumDims,
typename Allocator = std::allocator<ValueType> >
class multi_array {
public:
// types:
typedef ValueType element;
typedef *implementation-defined* value_type;
typedef *implementation-defined* reference;
typedef *implementation-defined* const_reference;
typedef *implementation-defined* difference_type;
typedef *implementation-defined* iterator;
typedef *implementation-defined* const_iterator;
typedef *implementation-defined* reverse_iterator;
typedef *implementation-defined* const_reverse_iterator;
typedef multi_array_types::size_type size_type;
typedef multi_array_types::index index;
typedef multi_array_types::index_gen index_gen;
typedef multi_array_types::index_range index_range;
typedef multi_array_types::extent_gen extent_gen;
typedef multi_array_types::extent_range extent_range;
// template typedefs
template <std::size_t Dims> struct subarray;
template <std::size_t Dims> struct const_subarray;
template <std::size_t Dims> struct array_view;
template <std::size_t Dims> struct const_array_view;
// constructors and destructors
template <typename ExtentList>
explicit multi_array(const ExtentList& sizes,
const storage_order& store = c_storage_order(),
const Allocator& alloc = Allocator());
explicit multi_array(const extents_tuple& ranges,
const storage_order& store = c_storage_order(),
const Allocator& alloc = Allocator());
multi_array(const multi_array& x);
~multi_array();
// modifiers
multi_array& operator=(const multi_array& x);
template <class Array> multi_array& operator=(const Array& x);
// iterators:
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
// capacity:
size_type size() const;
size_type num_elements() const;
size_type num_dimensions() const;
// element access:
template <typename IndexList>
element& operator()(const IndexList& indices);
template <typename IndexList>
const element& operator()(const IndexList& indices) const;
reference operator[](index i);
const_reference operator[](index i) const;
array_view<Dims>::type operator[](const indices_tuple& r);
const_array_view<Dims>::type operator[](const indices_tuple& r) const;
// queries
element* data();
const element* data() const;
element* origin();
const element* origin() const;
const size_type* shape() const;
const index* strides() const;
const index* index_bases() const;
// comparators
bool operator==(const multi_array& rhs);
bool operator!=(const multi_array& rhs);
bool operator<(const multi_array& rhs);
bool operator>(const multi_array& rhs);
bool operator>=(const multi_array& rhs);
bool operator<=(const multi_array& rhs);
// modifiers:
template <typename InputIterator>
void assign(InputIterator begin, InputIterator end);
template <typename SizeList>
void reshape(const SizeList& sizes)
template <typename BaseList> void reindex(const BaseList& values);
void reindex(index value);
};
]]>
</programlisting>
</formalpara>
<formalpara>
<title>Constructors</title>
<variablelist>
<varlistentry>
<term><programlisting>template &lt;typename ExtentList&gt;
explicit multi_array(const ExtentList&amp; sizes,
const storage_order&amp; store = c_storage_order(),
const Allocator&amp; alloc = Allocator());
</programlisting></term>
<listitem>
<para>
This constructs a <literal>multi_array</literal> using the specified
parameters. <literal>sizes</literal> specifies the shape of the
constructed <literal>multi_array</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions. <literal>alloc</literal> is used to
allocate the contained elements.
</para>
<formalpara><title><literal>ExtentList</literal> Requirements</title>
<para>
<literal>ExtentList</literal> must model <ulink url="./Collection.html">Collection</ulink>.
</para>
</formalpara>
<formalpara><title>Preconditions</title>
<para><literal>sizes.size() == NumDims;</literal></para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting><![CDATA[explicit multi_array(extent_gen::gen_type<NumDims>::type ranges,
const storage_order& store = c_storage_order(),
const Allocator& alloc = Allocator());]]>
</programlisting></term>
<listitem>
<para>
This constructs a <literal>multi_array</literal> using the specified
parameters. <literal>ranges</literal> specifies the shape and
index bases of the constructed multi_array. It is the result of
<literal>NumDims</literal> chained calls to
<literal>extent_gen::operator[]</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions. <literal>alloc</literal> is the allocator used to
allocate the memory used to store <literal>multi_array</literal>
elements.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><programlisting>
<![CDATA[multi_array(const multi_array& x);]]>
</programlisting></term>
<listitem>
<para>This constructs a <literal>multi_array</literal> and performs a deep
copy of <literal>x</literal>.
</para>
<formalpara>
<title>Complexity</title>
<para> This performs O(<literal>x.num_elements()</literal>) calls to
<literal>element</literal>'s copy
constructor.
</para></formalpara>
</listitem>
</varlistentry>
</variablelist>
<formalpara><title>Note on Constructors</title>
<para>
The <literal>multi_array</literal> construction expressions,
<programlisting>
multi_array&lt;int,3&gt; A(boost::extents[5][4][3]);
</programlisting>
and
<programlisting>
boost::array&lt;multi_array_base::index,3&gt; my_extents = {{5, 4, 3}};
multi_array&lt;int,3&gt; A(my_extents);
</programlisting>
are equivalent.
</para>
</formalpara>
</formalpara>
<formalpara>
<title>Modifiers</title>
<variablelist>
<varlistentry>
<term><programlisting>
<![CDATA[multi_array& operator=(const multi_array& x);
template <class Array> multi_array& operator=(const Array& x);]]>
</programlisting>
</term>
<listitem>
<para>This performs an element-wise copy of <literal>x</literal>
into the current <literal>multi_array</literal>.</para>
<formalpara>
<title><literal>Array</literal> Requirements</title>
<para><literal>Array</literal> must model MultiArray.
</para></formalpara>
<formalpara>
<title>Preconditions</title>
<para>
<programlisting>std::equal(this->shape(),this->shape()+this->num_dimensions(),
x.shape());</programlisting></para>
</formalpara>
<formalpara>
<title>Postconditions</title>
<para>
<programlisting>(*.this) == x;</programlisting>
</para>
</formalpara>
<formalpara>
<title>Complexity</title>
<para>The assignment operators perform
O(<literal>x.num_elements()</literal>) calls to <literal>element</literal>'s
copy constructor.</para></formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting>
<![CDATA[
template <typename InputIterator>
void assign(InputIterator begin, InputIterator end);]]>
</programlisting>
</term>
<listitem>
<para>This copies the elements in the range
<literal>[begin,end)</literal> into the array. It is equivalent to
<literal>std::copy(begin,end,this->data())</literal>.
</para>
<formalpara><title>Preconditions</title>
<para><literal>std::distance(begin,end) == this->num_elements();</literal>
</para>
</formalpara>
<formalpara>
<title>Complexity</title>
<para>
The <literal>assign</literal> member function performs
O(<literal>this->num_elements()</literal>) calls to
<literal>ValueType</literal>'s copy constructor.
</para>
</formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
</sect2>

253
doc/xml/multi_array_ref.xml Normal file
View File

@@ -0,0 +1,253 @@
<sect2 id="multi_array_ref">
<title><literal>multi_array_ref</literal></title>
<para>
<literal>multi_array_ref</literal> is a multi-dimensional container
adaptor. It provides the MultiArray interface over any contiguous
block of elements. <literal>multi_array_ref</literal> exports the
same interface as <literal>multi_array</literal>, with the exception
of the constructors.
</para>
<formalpara>
<title>Model Of.</title>
<para>
<literal>multi_array_ref</literal> models
<link linkend="MultiArray">MultiArray</link>,
<ulink url="../../../libs/utility/CopyConstructible.html">CopyConstructible</ulink>.
and depending on the element type, it may also model
<ulink url="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</ulink> and <ulink url="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</ulink>.
Detailed descriptions are provided here only for operations that are
not described in the <literal>multi_array</literal> reference.
</para>
</formalpara>
<formalpara>
<title>Synopsis</title>
<programlisting>
<![CDATA[
namespace boost {
template <typename ValueType,
std::size_t NumDims,
typename Allocator = std::allocator<ValueType> >
class multi_array_ref {
public:
// types:
typedef ValueType element;
typedef *implementation-defined* value_type;
typedef *implementation-defined* reference;
typedef *implementation-defined* const_reference;
typedef *implementation-defined* difference_type;
typedef *implementation-defined* iterator;
typedef *implementation-defined* const_iterator;
typedef *implementation-defined* reverse_iterator;
typedef *implementation-defined* const_reverse_iterator;
typedef multi_array_types::size_type size_type;
typedef multi_array_types::index index;
typedef multi_array_types::index_gen index_gen;
typedef multi_array_types::index_range index_range;
typedef multi_array_types::extent_gen extent_gen;
typedef multi_array_types::extent_range extent_range;
// template typedefs
template <std::size_t Dims> struct subarray;
template <std::size_t Dims> struct const_subarray;
template <std::size_t Dims> struct array_view;
template <std::size_t Dims> struct const_array_view;
// structors
template <typename ExtentList>
explicit multi_array_ref(element* data, const ExtentList& sizes,
const storage_order& store = c_storage_order());
explicit multi_array_ref(element* data, const extents_tuple& ranges,
const storage_order& store = c_storage_order());
multi_array_ref(const multi_array_ref& x);
~multi_array_ref();
// modifiers
multi_array_ref& operator=(const multi_array_ref& x);
template <class Array> multi_array_ref& operator=(const Array& x);
// iterators:
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
// capacity:
size_type size() const;
size_type num_elements() const;
size_type num_dimensions() const;
// element access:
template <typename IndexList>
element& operator()(const IndexList& indices);
template <typename IndexList>
const element& operator()(const IndexList& indices) const;
reference operator[](index i);
const_reference operator[](index i) const;
array_view<Dims>::type operator[](const indices_tuple& r);
const_array_view<Dims>::type operator[](const indices_tuple& r) const;
// queries
element* data();
const element* data() const;
element* origin();
const element* origin() const;
const size_type* shape() const;
const index* strides() const;
const index* index_bases() const;
// comparators
bool operator==(const multi_array_ref& rhs);
bool operator!=(const multi_array_ref& rhs);
bool operator<(const multi_array_ref& rhs);
bool operator>(const multi_array_ref& rhs);
bool operator>=(const multi_array_ref& rhs);
bool operator<=(const multi_array_ref& rhs);
// modifiers:
template <typename InputIterator>
void assign(InputIterator begin, InputIterator end);
template <typename SizeList>
void reshape(const SizeList& sizes)
template <typename BaseList> void reindex(const BaseList& values);
void reindex(index value);
};
]]>
</programlisting>
</formalpara>
<formalpara>
<title>Constructors</title>
<variablelist>
<varlistentry>
<term><programlisting>template &lt;typename ExtentList&gt;
explicit multi_array_ref(element* data,
const ExtentList&amp; sizes,
const storage_order&amp; store = c_storage_order(),
const Allocator&amp; alloc = Allocator());
</programlisting></term>
<listitem>
<para>
This constructs a <literal>multi_array_ref</literal> using the specified
parameters. <literal>sizes</literal> specifies the shape of the
constructed <literal>multi_array_ref</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions. <literal>alloc</literal> is used to
allocate the contained elements.
</para>
<formalpara><title><literal>ExtentList</literal> Requirements</title>
<para>
<literal>ExtentList</literal> must model <ulink url="./Collection.html">Collection</ulink>.
</para>
</formalpara>
<formalpara><title>Preconditions</title>
<para><literal>sizes.size() == NumDims;</literal></para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting><![CDATA[explicit multi_array_ref(element* data,
extent_gen::gen_type<NumDims>::type ranges,
const storage_order& store = c_storage_order());]]>
</programlisting></term>
<listitem>
<para>
This constructs a <literal>multi_array_ref</literal> using the specified
parameters. <literal>ranges</literal> specifies the shape and
index bases of the constructed multi_array_ref. It is the result of
<literal>NumDims</literal> chained calls to
<literal>extent_gen::operator[]</literal>. <literal>store</literal>
specifies the storage order or layout in memory of the array
dimensions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><programlisting>
<![CDATA[multi_array_ref(const multi_array_ref& x);]]>
</programlisting></term>
<listitem>
<para>This constructs a shallow copy of <literal>x</literal>.
</para>
<formalpara>
<title>Complexity</title>
<para> Constant time (for contrast, compare this to
the <literal>multi_array</literal> class copy constructor.
</para></formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
<formalpara>
<title>Modifiers</title>
<variablelist>
<varlistentry>
<term><programlisting>
<![CDATA[multi_array_ref& operator=(const multi_array_ref& x);
template <class Array> multi_array_ref& operator=(const Array& x);]]>
</programlisting>
</term>
<listitem>
<para>This performs an element-wise copy of <literal>x</literal>
into the current <literal>multi_array_ref</literal>.</para>
<formalpara>
<title><literal>Array</literal> Requirements</title>
<para><literal>Array</literal> must model MultiArray.
</para></formalpara>
<formalpara>
<title>Preconditions</title>
<para>
<programlisting>std::equal(this->shape(),this->shape()+this->num_dimensions(),
x.shape());</programlisting></para>
</formalpara>
<formalpara>
<title>Postconditions</title>
<para>
<programlisting>(*.this) == x;</programlisting>
</para>
</formalpara>
<formalpara>
<title>Complexity</title>
<para>The assignment operators perform
O(<literal>x.num_elements()</literal>) calls to <literal>element</literal>'s
copy constructor.</para></formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
</sect2>

786
doc/xml/reference.xml Normal file
View File

@@ -0,0 +1,786 @@
<?xml version='1.0' encoding="ISO-Latin-1" ?>
<!DOCTYPE article
PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd" [
<!ENTITY concepts SYSTEM "MultiArray.xml">
<!ENTITY multi_array SYSTEM "multi_array.xml">
<!ENTITY multi_array_ref SYSTEM "multi_array_ref.xml">
<!ENTITY const_multi_array_ref SYSTEM "const_multi_array_ref.xml">
]>
<article>
<articleinfo>
<title>Boost.MultiArray Reference Manual</title>
<author>
<surname>Garcia</surname><firstname>Ronald</firstname>
<affiliation>
<orgname>Indiana University</orgname>
<orgdiv>Open Systems Lab</orgdiv>
</affiliation>
</author>
<orgname>BOOST</orgname>
<copyright>
<year>2002</year>
<holder>Ronald Garcia</holder>
</copyright>
</articleinfo>
<para>Boost.MultiArray is composed of several components.
The MultiArray concept defines a generic interface to multidimensional
containers.
<literal>multi_array</literal> is a general purpose container class
that models MultiArray. <literal>multi_array_ref</literal>
and <literal>const_multi_array_ref</literal> are adapter
classes. Using them,
you can manipulate any block of contiguous data as though it were a
<literal>multi_array</literal>.
<literal>const_multi_array_ref</literal> differs from
<literal>multi_array_ref</literal> in that its elements cannot
be modified through its interface. Finally, several auxiliary classes are used
to create and specialize arrays and some global objects are defined as
part of the library interface.</para>
<sect1 id="synopsis">
<title>Library Synopsis</title>
<para>To use Boost.MultiArray, you must include the header
<filename>boost/multi_array.hpp</filename> in your source. This file
brings the following declarations into scope:</para>
<programlisting>
<![CDATA[namespace boost {
namespace multi_array_types {
typedef *implementation-defined* index;
typedef *implementation-defined* size_type;
typedef *implementation-defined* difference_type;
typedef *implementation-defined* index_range;
typedef *implementation-defined* extent_range;
typedef *implementation-defined* index_gen;
typedef *implementation-defined* extent_gen;
}
template <typename ValueType,
std::size_t NumDims,
typename Allocator = std::allocator<ValueType> >
class multi_array;
template <typename ValueType,
std::size_t NumDims>
class multi_array_ref;
template <typename ValueType,
std::size_t NumDims>
class const_multi_array_ref;
multi_array_types::extent_gen extents;
multi_array_types::index_gen indices;
template <typename Array, int N> class subarray_gen;
template <typename Array, int N> class const_subarray_gen;
template <typename Array, int N> class array_view_gen;
template <typename Array, int N> class const_array_view_gen;
class c_storage_order;
class fortran_storage_order;
template <std::size_t NumDims> class general_storage_order;
}]]>
</programlisting>
</sect1>
&concepts;
<sect1 id="array_types">
<title>Array Components</title>
<para>
Boost.MultiArray defines an array class,
<literal>multi_array</literal>, and two adapter classes,
<literal>multi_array_ref</literal> and
<literal>const_multi_array_ref</literal>. The three classes model
MultiArray and so they share a lot of functionality.
<literal>multi_array_ref</literal> differs from
<literal>multi_array</literal> in that the
<literal>multi_array</literal> manages its own memory, while
<literal>multi_array_ref</literal> is passed a block of memory that it
expects to be externally managed.
<literal>const_multi_array_ref</literal> differs from
<literal>multi_array_ref</literal> in that the underlying elements it
adapts cannot be modified through its interface, though some array
properties, including the array shape and index bases, can be altered.
Functionality the classes have in common is described
below.
</para>
<formalpara>
<title>Note: Preconditions, Effects, and Implementation</title>
<para>
Throughout the following sections, small pieces of C++ code are
used to specify constraints such as preconditions, effects, and
postconditions. These do not necessarily describe the underlying
implementation of array components; rather, they describe the
expected input to and
behavior of the specified operations. Failure to meet
preconditions results in undefined behavior. Not all effects
(i.e. copy constructors, etc.) must be mimicked exactly. The code
snippets for effects intend to capture the essence of the described
operation.
</para>
</formalpara>
<formalpara>
<title>Queries</title>
<variablelist>
<varlistentry>
<term><programlisting>element* data();
const element* data() const;</programlisting></term>
<listitem>
<para>This returns a pointer to the beginning of the
contiguous block that contains the array's data. If all dimensions of
the array are 0-indexed and stored in ascending order, this is
equivalent to <literal>origin()</literal>. Note that
<literal>const_multi_array_ref</literal> only provides the const
version of this function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><programlisting>element* origin();
const element* origin() const;</programlisting></term>
<listitem>
<para>This returns the origin element of the
<literal>multi_array</literal>. Note that
<literal>const_multi_array_ref</literal> only provides the const
version of this function. (Required by MultiArray)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>const index* index_bases();</function></term>
<listitem>
<para>This returns the index bases for the
<literal>multi_array</literal>. (Required by MultiArray)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>const index* strides();</function></term>
<listitem>
<para>This returns the strides for the
<literal>multi_array</literal>. (Required by MultiArray)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>const size_type* shape();</function></term>
<listitem>
<para>This returns the shape of the
<literal>multi_array</literal>. (Required by MultiArray)
</para>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
<formalpara>
<title>Comparators</title>
<variablelist>
<varlistentry>
<term><programlisting><![CDATA[
bool operator==(const *array-type*& rhs);
bool operator!=(const *array-type*& rhs);
bool operator<(const *array-type*& rhs);
bool operator>(const *array-type*& rhs);
bool operator>=(const *array-type*& rhs);
bool operator<=(const *array-type*& rhs);]]></programlisting></term>
<listitem>
<para>Each comparator executes a lexicographical compare over
the value types of the two arrays.
(Required by MultiArray)
</para>
<formalpara>
<title>Preconditions</title>
<para><literal>element</literal> must support the
comparator corresponding to that called on
<literal>multi_array</literal>.</para>
</formalpara>
<formalpara>
<title>Complexity</title>
<para>O(<literal>num_elements()</literal>).</para>
</formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
<formalpara>
<title>Modifiers</title>
<variablelist>
<varlistentry>
<term>
<programlisting>
<![CDATA[
template <typename SizeList>
void reshape(const SizeList& sizes)
]]>
</programlisting>
</term>
<listitem>
<para>This changes the shape of the <literal>multi_array</literal>. The
number of elements and the index bases remain the same, but the number
of values at each level of the nested container hierarchy may
change.</para>
<formalpara><title><literal>SizeList</literal> Requirements</title>
<para><literal>SizeList</literal> must model
<ulink url="./Collection.html">Collection</ulink>.</para>
</formalpara>
<formalpara><title>Preconditions</title>
<para>
<programlisting>
<![CDATA[std::accumulate(sizes.begin(),sizes.end(),size_type(1),std::times<size_type>()) == this->num_elements();
sizes.size() == NumDims;]]>
</programlisting></para>
</formalpara>
<formalpara><title>Postconditions</title>
<para>
<literal>std::equal(sizes.begin(),sizes.end(),this->shape) == true;</literal>
</para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting>
<![CDATA[
template <typename BaseList>
void reindex(const BaseList& values);
]]>
</programlisting>
</term>
<listitem>
<para>This changes the index bases of the <literal>multi_array</literal> to
correspond to the the values in <literal>values</literal>.</para>
<formalpara>
<title><literal>BaseList</literal> Requirements</title>
<para><literal>BaseList</literal> must model
<ulink url="./Collection.html">Collection</ulink>.</para>
</formalpara>
<formalpara>
<title>Preconditions</title>
<para><literal>values.size() == NumDims;</literal></para>
</formalpara>
<formalpara>
<title>Postconditions</title>
<para><literal>std::equal(values.begin(),values.end(),this->index_bases());
</literal></para>
</formalpara>
</listitem>
</varlistentry>
<varlistentry>
<term>
<programlisting>
<![CDATA[
void reindex(index value);
]]>
</programlisting>
</term>
<listitem>
<para>This changes the index bases of all dimensions of the
<literal>multi_array</literal> to <literal>value</literal>.</para>
<formalpara>
<title>Postconditions</title>
<para>
<programlisting>
<![CDATA[
std::count_if(this->index_bases(),this->index_bases()+this->num_dimensions(),
std::bind_2nd(std::equal_to<index>(),value)) ==
this->num_dimensions();
]]>
</programlisting>
</para>
</formalpara>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
&multi_array;
&multi_array_ref;
&const_multi_array_ref;
</sect1>
<sect1 id="auxiliary">
<title>Auxiliary Components</title>
<sect2 id="multi_array_types">
<title><literal>multi_array_types</literal></title>
<programlisting>
<![CDATA[namespace multi_array_types {
typedef *implementation-defined* index;
typedef *implementation-defined* size_type;
typedef *implementation-defined* difference_type;
typedef *implementation-defined* index_range;
typedef *implementation-defined* extent_range;
typedef *implementation-defined* index_gen;
typedef *implementation-defined* extent_gen;
}]]>
</programlisting>
<para>Namespace <literal>multi_array_types</literal> defines types
associated with <literal>multi_array</literal>,
<literal>multi_array_ref</literal>, and
<literal>const_multi_array_ref</literal> that are not
dependent upon template parameters. These types find common use with
all Boost.Multiarray components. They are defined
in a namespace from which they can be accessed conveniently.
With the exception of <literal>extent_gen</literal> and
<literal>extent_range</literal>, these types fulfill the roles of the
same name required by MultiArray and are described in its
concept definition. <literal>extent_gen</literal> and
<literal>extent_range</literal> are described below.
</para>
</sect2>
<sect2 id="extent_range">
<title><classname>extent_range</classname></title>
<para><classname>extent_range</classname> objects define half open
intervals. They provide shape and index base information to
<literal>multi_array</literal>, <literal>multi_array_ref</literal>,
and <literal>const_multi_array_ref</literal> constructors.
<classname>extent_range</classname>s are passed in
aggregate to an array constructor (see
<classname>extent_gen</classname> for more details).
</para>
<formalpara>
<title>Synopsis</title>
<programlisting><![CDATA[
class extent_range {
public:
typedef multi_array_types::index index;
typedef multi_array_types::size_type size_type;
// Structors
extent_range(index start, index finish);
extent_range(index finish);
~extent_range();
// Queries
index start();
index finish();
size_type size();
};]]></programlisting>
</formalpara>
<formalpara>
<title>Model Of</title>
<para>DefaultConstructible,CopyConstructible</para>
</formalpara>
<formalpara><title>Methods and Types</title>
<variablelist>
<varlistentry>
<term><function>extent_range(index start, index finish)</function></term>
<listitem>
<para> This constructor defines the half open interval
<literal>[start,finish)</literal>. The expression
<literal>finish</literal> must be greater than <literal>start</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry><term><function>extent_range(index finish)</function></term>
<listitem>
<para>This constructor defines the half open interval
<literal>[0,finish)</literal>. The value of <literal>finish</literal>
must be positive.</para>
</listitem>
</varlistentry>
<varlistentry><term><function>index start()</function></term>
<listitem>
<para>This function returns the first index represented by the range</para>
</listitem>
</varlistentry>
<varlistentry><term><function>index finish()</function></term>
<listitem>
<para>This function returns the upper boundary value of the half-open
interval. Note that the range does not include this value.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>size_type size()</function></term>
<listitem>
<para>This function returns the size of the specified range. It is
equivalent to <literal>finish()-start()</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
</sect2>
<sect2 id="extent_gen">
<title><classname>extent_gen</classname></title>
<para>The <classname>extent_gen</classname> class defines an
interface for aggregating array shape and indexing information to be
passed to a <literal>multi_array</literal>,
<literal>multi_array_ref</literal>, or <literal>const_multi_array_ref</literal>
constructor. Its interface mimics
the syntax used to declare built-in array types
in C++. For example, while a 3-dimensional array of
<classname>int</classname> values in C++ would be
declared as:
<programlisting>int A[3][4][5],</programlisting>
a similar <classname>multi_array</classname> would be declared:
<programlisting>multi_array&lt;int,3&gt; A(extents[3][4][5]).</programlisting>
</para>
<formalpara><title>Synopsis</title>
<programlisting><![CDATA[
template <std::size_t NumRanges>
class *implementation_defined* {
public:
typedef multi_array_types::index index;
typedef multi_array_types::size_type size_type;
template <std::size_t NumRanges> class gen_type;
gen_type<NumRanges+1>::type operator[](const range& a_range) const;
gen_type<NumRanges+1>::type operator[](index idx) const;
};
typedef *implementation_defined*<0> extent_gen;
]]></programlisting>
</formalpara>
<formalpara><title>Methods and Types</title>
<variablelist>
<varlistentry>
<term><function>template gen_type::&lt;Ranges&gt;::type</function></term>
<listitem>
<para>This type generator is used to specify the result of
<literal>Ranges</literal> chained calls to
<literal>extent_gen::operator[].</literal> The types
<classname>extent_gen</classname> and
<classname>gen_type&lt;0&gt;::type</classname> are the same.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>gen_type&lt;NumRanges+1&gt;::type
operator[](const extent_range&amp; a_range) const;</function></term>
<listitem>
<para>This function returns a new object containing all previous
<classname>extent_range</classname> objects in addition to
<literal>a_range.</literal> <classname>extent_range</classname>
objects are aggregated by chained calls to
<function>operator[]</function>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>gen_type&lt;NumRanges+1&gt;::type
operator[](index idx) const;</function></term>
<listitem>
<para>This function returns a new object containing all previous
<classname>extent_range</classname> objects in addition to
<literal>extent_range(0,idx).</literal> This function gives the array
constructors a similar syntax to traditional C multidimensional array
declaration.</para>
</listitem>
</varlistentry>
</variablelist>
</formalpara>
</sect2>
<sect2>
<title>Global Objects</title>
<para>For syntactic convenience, Boost.MultiArray defines two
global objects as part of its
interface. These objects play the role of object generators;
expressions involving them create other objects of interest.
</para>
<para> Under some circumstances, the two global objects may be
considered excessive overhead. Their construction can be prevented by
defining the preprocessor symbol
<literal>BOOST_MULTI_ARRAY_NO_GENERATORS</literal> before including
<filename>boost/multi_array.hpp.</filename></para>
<sect3 id="extents">
<title><literal>extents</literal></title>
<programlisting>
<![CDATA[namespace boost {
multi_array_base::extent_gen extents;
}]]>
</programlisting>
<para>Boost.MultiArray's array classes use the
<literal>extents</literal> global object to specify
array shape during their construction.
For example,
a 3 by 3 by 3 <classname>multi_array</classname> is constructed as follows:
<programlisting>multi_array&lt;int,3&gt; A(extents[3][3][3]);</programlisting>
The same array could also be created by explicitly declaring an <literal>extent_gen</literal>
object locally,, but the global object makes this declaration unnecessary.
</para>
</sect3>
<sect3 id="indices">
<title><literal>indices</literal></title>
<programlisting>
<![CDATA[namespace boost {
multi_array_base::index_gen indices;
}]]>
</programlisting>
<para>The MultiArray concept specifies an
<literal>index_gen</literal> associated type that is used to
create views.
<literal>indices</literal> is a global object that serves the role of
<literal>index_gen</literal> for all array components provided by this
library and their associated subarrays and views.
</para>
<para>For example, using the <literal>indices</literal> object,
a view of an array <literal>A</literal> is constructed as follows:
<programlisting>
A[indices[index_range(0,5)][2][index_range(2,4)]];
</programlisting>
</para>
</sect3>
</sect2>
<sect2 id="generators">
<title>View and SubArray Generators</title>
<para>
Boost.MultiArray provides traits classes, <literal>subarray_gen</literal>,
<literal>const_subarray_gen</literal>,
<literal>array_view_gen</literal>,
and <literal>const_array_view_gen</literal>, for naming of
array associated types within function templates.
In general this is no more convenient to use than the nested
type generators, but the library author found that some C++ compilers do not
properly handle templates nested within function template parameter types.
These generators constitute a workaround for this deficit.
The following code snippet illustrates
the correspondence between the <literal>array_view_gen</literal>
traits class and the <literal>array_view</literal> type associated to
an array:
<programlisting>
template &lt;typename Array&gt;
void my_function() {
typedef typename Array::template array_view&lt;3&gt;::type view1_t;
typedef typename boost::array_view_gen&lt;Array,3&gt;::type view2_t;
// ...
}
</programlisting>
In the above example, <literal>view1_t</literal> and
<literal>view2_t</literal> have the same type.
</para>
</sect2>
<sect2 id="memory_layout">
<title>Memory Layout Specifiers</title>
<para>
While a multidimensional array represents a hierarchy of containers of
elements, at some point the elements must be laid out in
memory. As a result, a single multidimensional array
can be represented in memory more than one way.
</para>
<para>For example, consider the two dimensional array shown below in
matrix notation:
<graphic fileref="matrix.gif"/>
Here is how the above array is expressed in C++:
<programlisting>
int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
</programlisting>
This is an example of row-major storage, where elements of each row
are stored contiguously.
While C++ transparently handles accessing elements of an array, you
can also manage the array and its indexing manually. One way that
this may be expressed in memory is as follows:
<programlisting>
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
int s[] = { 4, 1 };
</programlisting>
With the latter declaration of <literal>a</literal> and
strides <literal>s</literal>, element <literal>a(i,j)</literal>
of the array can be
accessed using the expression
<programlisting>*a+i*s[0]+j*s[1]</programlisting>.
</para>
<para>The same two dimensional array could be laid out by column as follows:
<programlisting>
int a[] = { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11 };
int s[] = { 3, 1 };
</programlisting>
Notice that the strides here are different. As a result,
The expression given above to access values will work with this pair
of data and strides as well.
</para>
<para>In addition to dimension order, it is also possible to
store any dimension in descending order. For example, returning to the
first example, the first dimension of the example array, the
rows, could be stored in
reverse, resulting in the following:
<programlisting>
int data[] = { 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 };
int *a = data + 8;
int s[] = { -4, 1 };
</programlisting>
Note that in this example <literal>a</literal> must be explicitly set
to the origin. In the previous examples, the
first element stored in memory was the origin; here this is no longer
the case.
</para>
<para>
Alternatively, the second dimension, or the columns, could be reversed
and the rows stored in ascending order:
<programlisting>
int data[] = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8 };
int *a = data + 3;
int s[] = { 4, -1 };
</programlisting>
</para>
<para>
Finally, both dimensions could be stored in descending order:
<programlisting>
int data[] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
int *a = data + 11;
int s[] = { -4, -1 };
</programlisting>
<literal>
</literal>
</para>
<para>
All of the above arrays are equivalent. The expression
given above for <literal>a(i,j)</literal> will yield the same value
regardless of the memory layout.
Boost.MultiArray arrays can be created with customized storage
parameters as described above. Thus, existing data can be adapted
(with <literal>multi_array_ref</literal> or
<literal>const_multi_array_ref</literal>) as suited to the array
abstraction. A common usage of this feature would be to wrap arrays
that must interoperate with Fortran routines so they can be
manipulated naturally at both the C++ and Fortran levels. The
following sections describe the Boost.MultiArray components used to
specify memory layout.
</para>
<sect3 id="c_storage_order">
<title><literal>c_storage_order</literal></title>
<programlisting>
<![CDATA[class c_storage_order {
c_storage_order();
};]]>
</programlisting>
<para><literal>c_storage_order</literal> is used to specify that an
array should store its elements using the same layout as that used by
primitive C++ multidimensional arrays, that is, from last dimension
to first. This is the default storage order for the arrays provided by
this library.</para>
</sect3>
<sect3 id="fortran_storage_order">
<title><literal>fortran_storage_order</literal></title>
<programlisting>
<![CDATA[class fortran_storage_order {
fortran_storage_order();
};]]>
</programlisting>
<para><literal>fortran_storage_order</literal> is used to specify that
an array should store its elements using the same memory layout as a
Fortran multidimensional array would, that is, from first dimension to
last.</para>
</sect3>
<sect3 id="general_storage_order">
<title><literal>general_storage_order</literal></title>
<programlisting>
<![CDATA[template <std::size_t NumDims>
class general_storage_order {
template <typename OrderingIter, typename AscendingIter>
general_storage_order(OrderingIter ordering, AscendingIter ascending);
};]]>
</programlisting>
<para><literal>general_storage_order</literal> allows the user to
specify an arbitrary memory layout for the contents of an array. The
constructed object is passed to the array constructor in order to
specify storage order.</para>
<para>
<literal>OrderingIter</literal> and <literal>AscendingIter</literal>
must model the <literal>InputIterator</literal> concept. Both
iterators must refer to a range of <literal>NumDims</literal>
elements. <literal>AscendingIter</literal> points to objects
convertible to <literal>bool</literal>. A value of
<literal>true</literal> means that a dimension is stored in ascending
order while <literal>false</literal> means that a dimension is stored
in descending order. <literal>OrderingIter</literal> specifies the
order in which dimensions are stored.
</para>
</sect3>
</sect2>
</sect1>
</article>

13
example/basic1.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include <cassert>
#include "boost/multi_array.hpp"
#include "boost/cstdlib.hpp"
int main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array;
array A(boost::extents[3][4][2]);
// Assign a value to an element in the array
A[0][0][0] = 3.14;
assert(A[0][0][0] == 3.14);
return boost::exit_success;
}

15
example/basic2.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <cassert>
#include "boost/multi_array.hpp"
#include "boost/array.hpp"
#include "boost/cstdlib.hpp"
int main () {
// Create a 3D array that is 3 x 4 x 2
boost::array<int, 3> shape = {{ 3, 4, 2 }};
boost::multi_array<double, 3> A(shape);
// Assign a value to an element in the array
A[0][0][0] = 3.14;
assert(A[0][0][0] == 3.14);
return boost::exit_success;
}

40
example/for_each.hpp Normal file
View File

@@ -0,0 +1,40 @@
#ifndef FOR_EACH_HPP
#define FOR_EACH_HPP
//
// for_each.hpp - Writing an algorithm to transform each element of
// a multi_array
//
#include "boost/type.hpp"
template <typename Array, typename Element, typename Functor>
void for_each (const boost::type<Element>& type_dispatch,
Array A, Functor& xform) {
for_each(type_dispatch,A.begin(),A.end(),xform);
}
template <typename Element, typename Functor>
void for_each (const boost::type<Element>&,Element& Val, Functor& xform) {
Val = xform(Val);
}
template <typename Element, typename Iterator, typename Functor>
void for_each (const boost::type<Element>& type_dispatch,
Iterator begin, Iterator end,
Functor& xform) {
while (begin != end) {
for_each(type_dispatch,*begin,xform);
++begin;
}
}
template <typename Array, typename Functor>
void for_each (Array& A, Functor xform) {
// Dispatch to the proper function
for_each(boost::type<Array::element>(),A.begin(),A.end(),xform);
}
#endif // FOR_EACH_HPP

42
example/foreach_test.cpp Normal file
View File

@@ -0,0 +1,42 @@
// foreach_test.cpp
// Let's see if this stuff works
#include "boost/multi_array.hpp"
#include "for_each.hpp"
#include <algorithm>
struct times_five {
double operator()(const int& val) { return val*5.0; }
};
int main() {
typedef boost::multi_array<double,2> array;
double data[] = {
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
};
const int data_size=9;
array A(boost::extents[3][3]);
A.assign(data,data+data_size);
#if 0
std::copy(A.data(),A.data()+A.num_elements(),
std::ostream_iterator<double>(std::cout,","));
std::cout << "\n";
#endif
for_each(A,times_five());
#if 0
std::copy(A.data(),A.data()+A.num_elements(),
std::ostream_iterator<double>(std::cout,","));
std::cout << "\n";
#endif
return 0;
}

40
example/foreach_test2.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "boost/multi_array.hpp"
#include "for_each.hpp"
#include <algorithm>
struct times_five {
double operator()(const int& val) { return val*5.0; }
};
int main() {
typedef boost::multi_array<double,1> array;
double data[] = {
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
};
const int data_size=9;
array A(boost::extents[9]);
A.assign(data,data+data_size);
#if 0
std::copy(A.begin(),A.end(),
std::ostream_iterator<double>(std::cout,","));
std::cout << "\n";
#endif
for_each(A,times_five());
#if 0
std::copy(A.begin(),A.end(),
std::ostream_iterator<double>(std::cout,","));
std::cout << "\n";
#endif
return 0;
}

17
example/op_paren.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include <cassert>
#include "boost/multi_array.hpp"
#include "boost/array.hpp"
#include "boost/cstdlib.hpp"
int main () {
// Create a 3D array that is 3 x 4 x 2
boost::array<int, 3> shape = {{ 3, 4, 2 }};
boost::multi_array<double, 3> A(shape);
typedef boost::multi_array<double, 3>::index index;
// Assign a value to an element in the array
boost::array<index, 3> idx = {{ 0, 0, 0 }};
A(idx) = 3.14;
assert(A(idx) == 3.14);
return boost::exit_success;
}

38
example/print_array.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include <iostream>
#include "boost/multi_array.hpp"
#include "boost/array.hpp"
#include "boost/cstdlib.hpp"
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 double& x)
{
os << x;
}
int main()
{
typedef boost::multi_array<double, 2> array;
double values[] = {
0, 1, 2,
3, 4, 5
};
const int values_size=6;
array A(boost::extents[2][3]);
A.assign(values,values+values_size);
print(std::cout, A);
return boost::exit_success;
}
// The output is:
// [[0,1,2],[3,4,5]]

41
example/subview.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "boost/multi_array.hpp"
#include "boost/cstdlib.hpp"
int
main()
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
int 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
};
const int data_size=24;
array myarray(boost::extents[2][3][4]);
myarray.assign(data,data+data_size);
//
// array_view dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
typedef array::index_range range;
array::array_view<ndims>::type myview =
myarray[boost::indices[range(0,2)][range(1,3)][range(0,4,2)]];
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 2; ++j)
for (array::index k = 0; k != 2; ++k)
assert(myview[i][j][k] == myarray[i][j+1][k*2]);
return boost::exit_success;
}

42
example/subview2.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include "boost/multi_array.hpp"
#include "boost/cstdlib.hpp"
int
main()
{
using boost::extents;
using boost::indices;
typedef boost::multi_array<int,3> array;
int 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
};
const int data_size=24;
array myarray(extents[2][3][4]);
myarray.assign(data,data+data_size);
//
// array_view dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
typedef boost::multi_array_types::index_range range;
array::array_view<3>::type myview =
myarray[indices[range(0,2)][range(1,3)][range(0,4,2)]];
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 2; ++j)
for (array::index k = 0; k != 2; ++k)
assert(myview[i][j][k] == myarray[i][j+1][k*2]);
return boost::exit_success;
}

View File

@@ -0,0 +1,190 @@
#ifndef BOOST_MULTI_ARRAY_RG071801_HPP
#define BOOST_MULTI_ARRAY_RG071801_HPP
//
// multi_array.hpp - contains the multi_array class template
// declaration and definition
//
#include "boost/multi_array/base.hpp"
#include "boost/multi_array/collection_concept.hpp"
#include "boost/multi_array/copy_array.hpp"
#include "boost/multi_array/iterator.hpp"
#include "boost/multi_array/subarray.hpp"
#include "boost/multi_array_ref.hpp"
#include "boost/multi_array/algorithm.hpp"
#include "boost/array.hpp"
#include "boost/type_traits.hpp"
#include <algorithm>
#include <cstddef>
#include <functional>
#include <numeric>
#include <vector>
namespace boost {
template<typename T, std::size_t NumDims,
typename Allocator>
class multi_array :
public multi_array_ref<T,NumDims>
{
typedef multi_array_ref<T,NumDims> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::reference reference;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::iterator iterator;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::iter_base iter_base;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::reverse_iterator reverse_iterator;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
// concept checks
// BOOST_CLASS_REQUIRES(T,DefaultConstructibleConcept);
// BOOST_CLASS_REQUIRES(T,AssignableConcept);
// BOOST_CLASS_REQUIRES(T,LessThanComparableConcept);
// BOOST_CLASS_REQUIRES(T,CopyConstructibleConcept);
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
template <class ExtentList>
explicit multi_array(ExtentList const& extents) :
super_type((T*)initial_base_,extents) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
allocate_space();
}
template <class ExtentList>
explicit multi_array(ExtentList const& extents,
const general_storage_order<NumDims>& so) :
super_type((T*)initial_base_,extents,so) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
allocate_space();
}
template <class ExtentList>
explicit multi_array(ExtentList const& extents,
const general_storage_order<NumDims>& so,
Allocator const& alloc) :
super_type((T*)initial_base_,extents,so), allocator_(alloc) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
allocate_space();
}
explicit multi_array(const detail::multi_array
::extent_gen<NumDims>& ranges) :
super_type((T*)initial_base_,ranges) {
allocate_space();
}
explicit multi_array(const detail::multi_array
::extent_gen<NumDims>& ranges,
const general_storage_order<NumDims>& so) :
super_type((T*)initial_base_,ranges,so) {
allocate_space();
}
explicit multi_array(const detail::multi_array
::extent_gen<NumDims>& ranges,
const general_storage_order<NumDims>& so,
Allocator const& alloc) :
super_type((T*)initial_base_,ranges,so), allocator_(alloc) {
allocate_space();
}
multi_array(const multi_array& rhs) :
super_type(rhs), allocator_(rhs.allocator_) {
allocate_space();
boost::copy_n(rhs.base_,rhs.num_elements(),base_);
}
template <typename OPtr>
multi_array(const detail::multi_array::
const_sub_array<T,NumDims,OPtr>& rhs) :
super_type(rhs) {
allocate_space();
std::copy(rhs.begin(),rhs.end(),begin());
}
// For some reason, gcc 2.95.2 doesn't pick the above template
// member function when passed a subarray, so i was forced to
// duplicate the functionality here...
multi_array(const detail::multi_array::
sub_array<T,NumDims>& rhs) :
super_type(rhs) {
allocate_space();
std::copy(rhs.begin(),rhs.end(),begin());
}
// Since assignment is a deep copy, multi_array_ref
// contains all the necessary code.
template <typename ConstMultiArray>
multi_array& operator=(const ConstMultiArray& other) {
super_type::operator=(other);
return *this;
}
multi_array& operator=(const multi_array& other) {
if (&other != this) {
super_type::operator=(other);
}
return *this;
}
~multi_array() {
deallocate_space();
}
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();
std::uninitialized_fill_n(base_,allocated_elements_,T());
}
void deallocate_space() {
if(base_) {
for(T* i = base_; i != base_+allocated_elements_; ++i)
allocator_.destroy(i);
allocator_.deallocate(base_,allocated_elements_);
}
}
typedef boost::array<size_type,NumDims> size_list;
typedef boost::array<index,NumDims> index_list;
Allocator allocator_;
T* base_;
size_type allocated_elements_;
enum {initial_base_ = 0};
};
} // namespace boost
#endif // BOOST_MULTI_ARRAY_RG071801_HPP

View File

@@ -0,0 +1,88 @@
#ifndef BOOST_ALGORITHM_RG071801_HPP
#define BOOST_ALGORITHM_RG071801_HPP
//
//
// Copyright (c) 1994
// Hewlett-Packard Company
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Hewlett-Packard Company makes no
// representations about the suitability of this software for any
// purpose. It is provided "as is" without express or implied warranty.
//
//
// Copyright (c) 1996-1998
// Silicon Graphics Computer Systems, Inc.
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Silicon Graphics makes no
// representations about the suitability of this software for any
// purpose. It is provided "as is" without express or implied warranty.
//
#include "boost/iterator.hpp"
namespace boost {
//--------------------------------------------------
// copy_n (not part of the C++ standard)
#if 1
template <class InputIter, class Size, class OutputIter>
OutputIter copy_n(InputIter first, Size count,
OutputIter result) {
for ( ; count > 0; --count) {
*result = *first;
++first;
++result;
}
return result;
}
#else // !1
template <class InputIter, class Size, class OutputIter>
OutputIter copy_n__(InputIter first, Size count,
OutputIter result,
std::input_iterator_tag) {
for ( ; count > 0; --count) {
*result = *first;
++first;
++result;
}
return result;
}
template <class RAIter, class Size, class OutputIter>
inline OutputIter
copy_n__(RAIter first, Size count,
OutputIter result,
std::random_access_iterator_tag) {
RAIter last = first + count;
return std::copy(first, last, result);
}
template <class InputIter, class Size, class OutputIter>
inline OutputIter
copy_n__(InputIter first, Size count, OutputIter result) {
typedef std::iterator_traits<InputIter>::iterator_category cat;
return copy_n__(first, count, result, cat());
}
template <class InputIter, class Size, class OutputIter>
inline OutputIter
copy_n(InputIter first, Size count, OutputIter result) {
return copy_n__(first, count, result);
}
#endif // 1
} // namespace boost
#endif // BOOST_ALGORITHM_RG071801_HPP

View File

@@ -0,0 +1,448 @@
#ifndef BASE_RG071801_HPP
#define BASE_RG071801_HPP
//
// base.hpp - some implementation base classes for from which
// functionality is acquired
//
#include "boost/multi_array/extent_range.hpp"
#include "boost/multi_array/extent_gen.hpp"
#include "boost/multi_array/index_range.hpp"
#include "boost/multi_array/index_gen.hpp"
#include "boost/multi_array/storage_order.hpp"
#include "boost/multi_array/types.hpp"
#include "boost/config.hpp"
#include "boost/multi_array/iterator_adaptors.hpp"
#include "boost/static_assert.hpp"
#include "boost/type.hpp"
#include <cassert>
#include <cstddef>
#include <memory>
namespace boost {
/////////////////////////////////////////////////////////////////////////
// class declarations
/////////////////////////////////////////////////////////////////////////
template<typename T, std::size_t NumDims,
typename Allocator = std::allocator<T> >
class multi_array;
// This is a public interface for use by end users!
namespace multi_array_types {
typedef boost::detail::multi_array::size_type size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::detail::multi_array::index index;
typedef detail::multi_array::index_range<index,size_type> index_range;
typedef detail::multi_array::extent_range<index,size_type> extent_range;
typedef detail::multi_array::index_gen<0,0> index_gen;
typedef detail::multi_array::extent_gen<0> extent_gen;
}
// boost::extents and boost::indices are now a part of the public
// interface. That way users don't necessarily have to create their
// own objects. On the other hand, one may not want the overhead of
// object creation in small-memory environments. Thus, the objects
// can be left undefined by defining BOOST_MULTI_ARRAY_NO_GENERATORS
// before loading multi_array.hpp or multi_array_ref.hpp
#if !BOOST_MULTI_ARRAY_NO_GENERATORS
namespace {
multi_array_types::extent_gen extents;
multi_array_types::index_gen indices;
}
#endif // BOOST_MULTI_ARRAY_NO_GENERATORS
namespace detail {
namespace multi_array {
template <typename T, std::size_t NumDims>
class sub_array;
template <typename T, std::size_t NumDims, typename TPtr = const T*>
class const_sub_array;
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct iterator_generator;
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct const_iterator_generator;
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct reverse_iterator_generator;
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct const_reverse_iterator_generator;
template <typename T,typename TPtr>
struct iterator_base;
template <typename T, std::size_t NumDims>
struct iterator_policies;
template <typename T, std::size_t NumDims, typename TPtr = const T*>
class const_multi_array_view;
template <typename T, std::size_t NumDims>
class multi_array_view;
/////////////////////////////////////////////////////////////////////////
// class interfaces
/////////////////////////////////////////////////////////////////////////
class multi_array_base {
public:
typedef multi_array_types::size_type size_type;
typedef multi_array_types::difference_type difference_type;
typedef multi_array_types::index index;
typedef multi_array_types::index_range index_range;
typedef multi_array_types::extent_range extent_range;
typedef multi_array_types::index_gen index_gen;
typedef multi_array_types::extent_gen extent_gen;
};
//
// value_accessor_n
// contains the routines for accessing elements from
// N-dimensional views.
//
template<typename T, std::size_t NumDims>
class value_accessor_n : public multi_array_base {
typedef multi_array_base super_type;
public:
typedef typename super_type::index index;
//
// public typedefs used by classes that inherit from this base
//
typedef T element;
typedef boost::multi_array<T,NumDims-1> value_type;
typedef sub_array<T,NumDims-1> reference;
typedef const_sub_array<T,NumDims-1> const_reference;
protected:
// used by array operator[] and iterators to get reference types.
template <typename Reference, typename TPtr>
Reference access(boost::type<Reference>,index idx,TPtr base,
const size_type* extents,
const index* strides,
const index* index_base) const {
// return a sub_array<T,NDims-1> proxy object
TPtr newbase = base + idx * strides[0];
return Reference(newbase,extents+1,strides+1,index_base+1);
}
value_accessor_n() { }
~value_accessor_n() { }
};
//
// value_accessor_one
// contains the routines for accessing reference elements from
// 1-dimensional views.
//
template<typename T>
class value_accessor_one : public multi_array_base {
typedef multi_array_base super_type;
public:
typedef typename super_type::index index;
//
// public typedefs for use by classes that inherit it.
//
typedef T element;
typedef T value_type;
typedef T& reference;
typedef T const& const_reference;
protected:
// used by array operator[] and iterators to get reference types.
template <typename Reference, typename TPtr>
Reference access(boost::type<Reference>,index idx,TPtr base,
const size_type*,
const index* strides,
const index*) const {
return *(base + idx * strides[0]);
}
value_accessor_one() { }
~value_accessor_one() { }
};
/////////////////////////////////////////////////////////////////////////
// choose value accessor begins
//
struct choose_value_accessor_n {
template <typename T, std::size_t NumDims>
struct bind {
typedef value_accessor_n<T,NumDims> type;
};
};
struct choose_value_accessor_one {
template <typename T, std::size_t NumDims>
struct bind {
typedef value_accessor_one<T> type;
};
};
template <std::size_t NumDims>
struct value_accessor_gen_helper {
typedef choose_value_accessor_n choice;
};
template <>
struct value_accessor_gen_helper<1> {
typedef choose_value_accessor_one choice;
};
template <typename T, std::size_t NumDims>
struct value_accessor_generator {
private:
typedef typename value_accessor_gen_helper<NumDims>::choice Choice;
public:
typedef typename Choice::template bind<T,NumDims>::type type;
};
//
// choose value accessor ends
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// multi_array/sub_array base stuffs
/////////////////////////////////////////////////////////////////////////
template <std::size_t NumDims>
struct iterator_tag_selector {
typedef std::input_iterator_tag type;
};
template <>
struct iterator_tag_selector<1> {
typedef std::random_access_iterator_tag type;
};
////////////////////////////////////////////////////////////////////////
// multi_array_base
////////////////////////////////////////////////////////////////////////
template <typename T, std::size_t NumDims>
class multi_array_impl_base :
public value_accessor_generator<T,NumDims>::type {
typedef typename value_accessor_generator<T,NumDims>::type super_type;
public:
typedef typename super_type::index index;
typedef typename super_type::size_type size_type;
typedef typename super_type::element element;
typedef typename super_type::index_range index_range;
typedef typename super_type::value_type value_type;
typedef typename super_type::reference reference;
typedef typename super_type::const_reference const_reference;
template <std::size_t NDims>
struct subarray {
typedef boost::detail::multi_array::sub_array<T,NDims> type;
};
template <std::size_t NDims>
struct const_subarray {
typedef boost::detail::multi_array::const_sub_array<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct const_array_view {
public:
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
//
// iterator support
//
typedef typename iterator_tag_selector<NumDims>::type iterator_tag;
typedef typename
iterator_generator<T,NumDims,value_type,
reference,iterator_tag,index>::type iterator;
typedef typename
const_iterator_generator<T,NumDims,value_type,
const_reference,iterator_tag,index>::type const_iterator;
typedef typename
reverse_iterator_generator<T,NumDims,value_type,
reference,iterator_tag,index>::type reverse_iterator;
typedef typename
const_reverse_iterator_generator<T,NumDims,value_type,
const_reference,iterator_tag,index>::type const_reverse_iterator;
protected:
typedef iterator_base<T,T*> iter_base;
typedef iterator_base<T,const T*> const_iter_base;
multi_array_impl_base() { }
~multi_array_impl_base() { }
// Used by operator() in our array classes
template <typename Reference, typename IndexList, typename TPtr>
Reference access_element(boost::type<Reference>, TPtr base,
const IndexList& indices,
const index* strides) const {
index offset = 0;
for (size_type n = 0; n != NumDims; ++n)
offset += indices[n] * strides[n];
return base[offset];
}
template <typename StrideList, typename ExtentList>
void compute_strides(StrideList& stride_list, ExtentList& extent_list,
const general_storage_order<NumDims>& storage)
{
// invariant: stride = the stride for dimension n
index stride = 1;
for (size_type n = 0; n != NumDims; ++n) {
index stride_sign = +1;
if (!storage.ascending(storage.ordering(n)))
stride_sign = -1;
// The stride for this dimension is the product of the
// lengths of the ranks minor to it.
stride_list[storage.ordering(n)] = stride * stride_sign;
stride *= extent_list[storage.ordering(n)];
}
}
// This calculates the offset to the array base pointer due to:
// 1. dimensions stored in descending order
// 2. non-zero dimension index bases
template <typename StrideList, typename ExtentList, typename BaseList>
index
calculate_origin_offset(const StrideList& stride_list,
const ExtentList& extent_list,
const general_storage_order<NumDims>& storage,
const BaseList& index_base_list)
{
return
calculate_descending_dimension_offset(stride_list,extent_list,
storage) +
calculate_indexing_offset(stride_list,index_base_list);
}
// This calculates the offset added to the base pointer that are
// caused by descending dimensions
template <typename StrideList, typename ExtentList>
index
calculate_descending_dimension_offset(const StrideList& stride_list,
const ExtentList& extent_list,
const general_storage_order<NumDims>& storage)
{
index offset = 0;
if (!storage.all_dims_ascending())
for (size_type n = 0; n != NumDims; ++n)
if (!storage.ascending(n))
offset -= (extent_list[n] - 1) * stride_list[n];
return offset;
}
// This is used to reindex array_views, which are no longer
// concerned about storage order (specifically, whether dimensions
// are ascending or descending) since the viewed array handled it.
template <typename StrideList, typename BaseList>
index
calculate_indexing_offset(const StrideList& stride_list,
const BaseList& index_base_list)
{
index offset = 0;
for (size_type n = 0; n != NumDims; ++n)
offset -= stride_list[n] * index_base_list[n];
return offset;
}
// Slicing using an index_gen.
// Note that populating an index_gen creates a type that encodes
// both the number of dimensions in the current Array (NumDims), and
// the Number of dimensions for the resulting view. This allows the
// compiler to fail if the dimensions aren't completely accounted
// for. For reasons unbeknownst to me, a BOOST_STATIC_ASSERT
// within the member function template does not work. I should add a
// note to the documentation specifying that you get a damn ugly
// error message if you screw up in your slicing code.
template <typename ArrayRef, int NDims, typename TPtr>
ArrayRef
generate_array_view(boost::type<ArrayRef>,
const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices,
const size_type* extents,
const index* strides,
const index* index_bases,
TPtr base) const {
boost::array<index,NDims> new_strides;
boost::array<index,NDims> new_extents;
index offset = 0;
size_type dim = 0;
for (size_type n = 0; n != NumDims; ++n) {
const index default_start = index_bases[n];
const index default_finish = default_start+extents[n];
const index_range& current_range = indices.ranges_[n];
index start = current_range.get_start(default_start);
index finish = current_range.get_finish(default_finish);
index index_factor = current_range.stride();
index len = (finish - start) / index_factor;
// the array data pointer is modified to account for non-zero
// bases during slicing (see [Garcia] for the math involved)
offset += start * strides[n];
if (!current_range.is_degenerate()) {
// The index_factor for each dimension is included into the
// strides for the array_view (see [Garcia] for the math involved).
new_strides[dim] = index_factor * strides[n];
// calculate new extents
new_extents[dim] = len;
++dim;
}
}
assert (dim == NDims);
return
ArrayRef(base+offset,
new_extents,
new_strides);
}
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BASE_RG071801_HPP

View File

@@ -0,0 +1,50 @@
#ifndef COLLECTION_CONCEPT_RG103101_HPP
#define COLLECTION_CONCEPT_RG103101_HPP
#include "boost/concept_check.hpp"
namespace boost {
namespace detail {
namespace multi_array {
//===========================================================================
// Collection Concept
template <class Collection>
struct CollectionConcept
{
typedef typename Collection::value_type value_type;
typedef typename Collection::iterator iterator;
typedef typename Collection::const_iterator const_iterator;
typedef typename Collection::reference reference;
typedef typename Collection::const_reference const_reference;
// typedef typename Collection::pointer pointer;
typedef typename Collection::difference_type difference_type;
typedef typename Collection::size_type size_type;
void constraints() {
boost::function_requires<boost::InputIteratorConcept<iterator> >();
boost::function_requires<boost::InputIteratorConcept<const_iterator> >();
boost::function_requires<boost::CopyConstructibleConcept<value_type> >();
const_constraints(c);
i = c.begin();
i = c.end();
c.swap(c);
}
void const_constraints(const Collection& c) {
ci = c.begin();
ci = c.end();
n = c.size();
b = c.empty();
}
Collection c;
bool b;
iterator i;
const_iterator ci;
size_type n;
};
}
}
}
#endif // COLLECTION_CONCEPT_RG103101_HPP

View File

@@ -0,0 +1,191 @@
#ifndef BOOST_MULTI_ARRAY_CONCEPT_CHECKS_RG110101_HPP
#define BOOST_MULTI_ARRAY_CONCEPT_CHECKS_RG110101_HPP
//
// concept-checks.hpp - Checks out Const MultiArray and MultiArray
// concepts
//
#include "boost/concept_check.hpp"
namespace boost {
namespace detail {
namespace multi_array {
//
// idgen_helper -
// This is a helper for generating index_gen instantiations with
// the right type in order to test the call to
// operator[](index_gen). Since one would normally write:
// A[ indices[range1][range2] ]; // or
// B[ indices[index1][index2][range1] ];
// idgen helper allows us to generate the "indices" type by
// creating it through recursive calls.
template <std::size_t N>
struct idgen_helper {
template <typename Array, typename IdxGen, typename Call_Type>
static void call(Array& a, const IdxGen& idgen, Call_Type c) {
typedef typename Array::index_range index_range;
typedef typename Array::index index;
idgen_helper<N-1>::call(a,idgen[c],c);
}
};
template <>
struct idgen_helper<0> {
template <typename Array, typename IdxGen, typename Call_Type>
static void call(Array& a, const IdxGen& idgen, Call_Type) {
typedef typename Array::index_range index_range;
typedef typename Array::index index;
a[ idgen ];
}
};
template <typename Array, std::size_t NumDims >
struct ConstMultiArrayConcept
{
void constraints() {
// function_requires< CopyConstructibleConcept<Array> >();
// RG - a( CollectionArchetype) when available...
a[ id ];
// Test slicing, keeping only the first dimension, losing the rest
idgen_helper<NumDims-1>::call(a,idgen[range],id);
// Test slicing, keeping all dimensions.
idgen_helper<NumDims-1>::call(a,idgen[range],range);
st = a.size();
st = a.num_dimensions();
st = a.num_elements();
stp = a.shape();
idp = a.strides();
idp = a.index_bases();
cit = a.begin();
cit = a.end();
crit = a.rbegin();
crit = a.rend();
eltp = a.origin();
}
typedef typename Array::value_type value_type;
typedef typename Array::reference reference;
typedef typename Array::const_reference const_reference;
typedef typename Array::size_type size_type;
typedef typename Array::difference_type difference_type;
typedef typename Array::iterator iterator;
typedef typename Array::const_iterator const_iterator;
typedef typename Array::reverse_iterator reverse_iterator;
typedef typename Array::const_reverse_iterator const_reverse_iterator;
typedef typename Array::element element;
typedef typename Array::index index;
typedef typename Array::index_gen index_gen;
typedef typename Array::index_range index_range;
typedef typename Array::extent_gen extent_gen;
typedef typename Array::extent_range extent_range;
Array a;
size_type st;
const size_type* stp;
index id;
const index* idp;
const_iterator cit;
const_reverse_iterator crit;
const element* eltp;
index_gen idgen;
index_range range;
};
template <typename Array, std::size_t NumDims >
struct MutableMultiArrayConcept
{
void constraints() {
// function_requires< CopyConstructibleConcept<Array> >();
// RG - a( CollectionArchetype) when available...
value_type vt = a[ id ];
// Test slicing, keeping only the first dimension, losing the rest
idgen_helper<NumDims-1>::call(a,idgen[range],id);
// Test slicing, keeping all dimensions.
idgen_helper<NumDims-1>::call(a,idgen[range],range);
st = a.size();
st = a.num_dimensions();
st = a.num_elements();
stp = a.shape();
idp = a.strides();
idp = a.index_bases();
it = a.begin();
it = a.end();
rit = a.rbegin();
rit = a.rend();
eltp = a.origin();
const_constraints(a);
}
void const_constraints(const Array& a) {
// value_type vt = a[ id ];
// Test slicing, keeping only the first dimension, losing the rest
idgen_helper<NumDims-1>::call(a,idgen[range],id);
// Test slicing, keeping all dimensions.
idgen_helper<NumDims-1>::call(a,idgen[range],range);
st = a.size();
st = a.num_dimensions();
st = a.num_elements();
stp = a.shape();
idp = a.strides();
idp = a.index_bases();
cit = a.begin();
cit = a.end();
crit = a.rbegin();
crit = a.rend();
eltp = a.origin();
}
typedef typename Array::value_type value_type;
typedef typename Array::reference reference;
typedef typename Array::const_reference const_reference;
typedef typename Array::size_type size_type;
typedef typename Array::difference_type difference_type;
typedef typename Array::iterator iterator;
typedef typename Array::const_iterator const_iterator;
typedef typename Array::reverse_iterator reverse_iterator;
typedef typename Array::const_reverse_iterator const_reverse_iterator;
typedef typename Array::element element;
typedef typename Array::index index;
typedef typename Array::index_gen index_gen;
typedef typename Array::index_range index_range;
typedef typename Array::extent_gen extent_gen;
typedef typename Array::extent_range extent_range;
Array a;
size_type st;
const size_type* stp;
index id;
const index* idp;
iterator it;
const_iterator cit;
reverse_iterator rit;
const_reverse_iterator crit;
const element* eltp;
index_gen idgen;
index_range range;
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_MULTI_ARRAY_CONCEPT_CHECKS_RG110101_HPP

View File

@@ -0,0 +1,56 @@
#ifndef COPY_ARRAY_RG092101_HPP
#define COPY_ARRAY_RG092101_HPP
//
// copy_array.hpp - generic code for copying the contents of one
// Basic_MultiArray to another. We assume that they are of the same
// shape
//
#include "boost/type.hpp"
#include <cassert>
namespace boost {
namespace detail {
namespace multi_array {
template <typename Element>
class copy_dispatch {
public:
template <typename SourceIterator, typename DestIterator>
static void copy_array (SourceIterator first, SourceIterator last,
DestIterator result) {
while (first != last) {
copy_array(*first++,*result++);
}
}
private:
// Array2 has to be passed by VALUE here because subarray
// pseudo-references are temporaries created by iterator::operator*()
template <typename Array1, typename Array2>
static void copy_array (const Array1& source, Array2 dest) {
copy_array(source.begin(),source.end(),dest.begin());
}
static void copy_array (const Element& source, Element& dest) {
dest = source;
}
};
template <typename Array1, typename Array2>
void copy_array (Array1& source, Array2& dest) {
assert(std::equal(source.shape(),source.shape()+source.num_dimensions(),
dest.shape()));
// Dispatch to the proper function
typedef typename Array1::element element_type;
copy_dispatch<element_type>::
copy_array(source.begin(),source.end(),dest.begin());
}
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // COPY_ARRAY_RG092101_HPP

View File

@@ -0,0 +1,63 @@
#ifndef BOOST_EXTENT_GEN_RG071801_HPP
#define BOOST_EXTENT_GEN_RG071801_HPP
#include "boost/multi_array/extent_range.hpp"
#include "boost/multi_array/range_list.hpp"
#include "boost/multi_array/types.hpp"
#include "boost/array.hpp"
#include <algorithm>
namespace boost {
namespace detail {
namespace multi_array {
template <std::size_t NumRanges>
class extent_gen {
public:
typedef boost::detail::multi_array::index index;
typedef boost::detail::multi_array::size_type size_type;
private:
typedef extent_range<index,size_type> range;
typedef typename range_list_generator<range,NumRanges>::type range_list;
public:
template <std::size_t Ranges>
struct gen_type {
typedef extent_gen<Ranges> type;
};
range_list ranges_;
extent_gen() { }
// Used by operator[] to expand extent_gens
extent_gen(const extent_gen<NumRanges-1>& rhs,
const range& a_range)
{
std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin());
*ranges_.rbegin() = a_range;
}
extent_gen<NumRanges+1>
operator[](const range& a_range)
{
return extent_gen<NumRanges+1>(*this,a_range);
}
extent_gen<NumRanges+1>
operator[](index idx)
{
return extent_gen<NumRanges+1>(*this,range(0,idx));
}
static extent_gen<0> extents() {
return extent_gen<0>();
}
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_EXTENT_GEN_RG071801_HPP

View File

@@ -0,0 +1,37 @@
#ifndef BOOST_EXTENT_RANGE_RG071801_HPP
#define BOOST_EXTENT_RANGE_RG071801_HPP
#include <utility>
namespace boost {
namespace detail {
namespace multi_array {
template <typename Extent, typename SizeType>
class extent_range : private std::pair<Extent,Extent> {
typedef std::pair<Extent,Extent> super_type;
public:
typedef Extent index;
typedef SizeType size_type;
extent_range(index start, index finish) :
super_type(start,finish) { }
extent_range(index finish) :
super_type(0,finish) { }
extent_range() : super_type(0,0) { }
index start() const { return super_type::first; }
index finish() const { return super_type::second; }
size_type size() const { return super_type::second - super_type::first; }
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_EXTENT_RANGE_RG071801_HPP

View File

@@ -0,0 +1,69 @@
#ifndef BOOST_INDEX_GEN_RG071801_HPP
#define BOOST_INDEX_GEN_RG071801_HPP
#include "boost/array.hpp"
#include "boost/multi_array/index_range.hpp"
#include "boost/multi_array/range_list.hpp"
#include "boost/multi_array/types.hpp"
#include <algorithm>
#include <cstddef>
namespace boost {
namespace detail {
namespace multi_array {
template <int NumRanges, int NumDims>
struct index_gen {
private:
typedef index Index;
typedef std::size_t SizeType;
typedef index_range<Index,SizeType> range;
public:
template <int Dims, int Ranges>
struct gen_type {
typedef index_gen<Ranges,Dims> type;
};
typedef typename range_list_generator<range,NumRanges>::type range_list;
range_list ranges_;
index_gen() { }
template <int ND>
explicit index_gen(const index_gen<NumRanges-1,ND>& rhs,
const index_range<Index,SizeType>& range)
{
std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin());
*ranges_.rbegin() = range;
}
index_gen<NumRanges+1,NumDims+1>
operator[](const index_range<Index,SizeType>& range) const
{
index_gen<NumRanges+1,NumDims+1> tmp;
std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin());
*tmp.ranges_.rbegin() = range;
return tmp;
}
index_gen<NumRanges+1,NumDims>
operator[](Index idx) const
{
index_gen<NumRanges+1,NumDims> tmp;
std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin());
*tmp.ranges_.rbegin() = index_range<Index,SizeType>(idx);
return tmp;
}
static index_gen<0,0> indices() {
return index_gen<0,0>();
}
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_INDEX_GEN_RG071801_HPP

View File

@@ -0,0 +1,189 @@
#ifndef BOOST_INDEX_RANGE_RG071801_HPP
#define BOOST_INDEX_RANGE_RG071801_HPP
#include <boost/config.hpp>
#include <utility>
#include <boost/limits.hpp>
// For representing intervals, also with stride.
// A degenerate range is a range with one element.
// Thanks to Doug Gregor for the really cool idea of using the
// comparison operators to express various interval types!
// Internally, we represent the interval as half-open.
namespace boost {
namespace detail {
namespace multi_array {
template <typename Index,typename SizeType>
class index_range {
public:
typedef Index index;
typedef SizeType size_type;
index_range()
{
start_ = from_start();
finish_ = to_end();
stride_ = 1;
degenerate_ = false;
}
explicit index_range(index pos)
{
start_ = pos;
finish_ = pos;
stride_ = 1;
degenerate_ = true;
}
explicit index_range(index start, index finish, index stride=1)
: start_(start), finish_(finish), stride_(stride),
degenerate_(start_ == finish_)
{ }
// These are for chaining assignments to an index_range
index_range& start(index s) {
start_ = s;
degenerate_ = (start_ == finish_);
return *this;
}
index_range& finish(index f) {
finish_ = f;
degenerate_ = (start_ == finish_);
return *this;
}
index_range& stride(index s) { stride_ = s; return *this; }
index start() const
{
return start_;
}
index get_start(index low_index_range = 0) const
{
if (start_ == from_start())
return low_index_range;
return start_;
}
index finish() const
{
return finish_;
}
index get_finish(index high_index_range = 0) const
{
if (finish_ == to_end())
return high_index_range;
return finish_;
}
size_type size(index recommended_length = 0) const
{
if ((start_ == from_start()) || (finish_ == to_end()))
return recommended_length;
else
return (finish_ - start_) / stride_;
}
index stride() const { return stride_; }
bool is_ascending_contiguous() const
{
return (start_ < finish_) && is_unit_stride();
}
void set_index_range(index start, index finish, index stride=1)
{
start_ = start;
finish_ = finish;
stride_ = stride;
}
static index_range all()
{ return index_range(from_start(), to_end(), 1); }
bool is_unit_stride() const
{ return stride_ == 1; }
bool is_degenerate() const { return degenerate_; }
index_range operator-(index shift) const
{
return index_range(start_ - shift, finish_ - shift, stride_);
}
index_range operator+(index shift) const
{
return index_range(start_ + shift, finish_ + shift, stride_);
}
index operator[](unsigned i) const
{
return start_ + i * stride_;
}
index operator()(unsigned i) const
{
return start_ + i * stride_;
}
// add conversion to std::slice?
private:
static index from_start()
{ return std::numeric_limits<index>::min(); }
static index to_end()
{ return std::numeric_limits<index>::max(); }
public:
index start_, finish_, stride_;
bool degenerate_;
};
// Express open and closed interval end-points using the comparison
// operators.
// left closed
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<=(Index s, const index_range<Index,SizeType>& r)
{
return index_range<Index,SizeType>(s, r.finish(), r.stride());
}
// left open
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<(Index s, const index_range<Index,SizeType>& r)
{
return index_range<Index,SizeType>(s + 1, r.finish(), r.stride());
}
// right open
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<(const index_range<Index,SizeType>& r, Index f)
{
return index_range<Index,SizeType>(r.start(), f, r.stride());
}
// right closed
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<=(const index_range<Index,SizeType>& r, Index f)
{
return index_range<Index,SizeType>(r.start(), f + 1, r.stride());
}
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_INDEX_RANGE_RG071801_HPP

View File

@@ -0,0 +1,159 @@
#ifndef ITERATOR_RG071801_HPP
#define ITERATOR_RG071801_HPP
//
// iterator.hpp - implementation of iterators for the
// multi-dimensional array class
//
#include "boost/multi_array/base.hpp"
#include "boost/multi_array/iterator_adaptors.hpp"
#include "boost/iterator_adaptors.hpp"
#include <cstddef>
#include <iterator>
namespace boost {
namespace detail {
namespace multi_array {
/////////////////////////////////////////////////////////////////////////
// iterator components
/////////////////////////////////////////////////////////////////////////
template <typename T, typename TPtr>
struct iterator_base : private multi_array_base {
typedef multi_array_base super_type;
typedef super_type::index index;
typedef super_type::size_type size_type;
index idx_;
TPtr base_;
const size_type* extents_;
const index* strides_;
const index* index_base_;
iterator_base(int idx, TPtr base, const size_type* extents,
const index* strides,
const index* index_base) :
idx_(idx), base_(base), extents_(extents),
strides_(strides), index_base_(index_base) {
}
template <typename OPtr>
iterator_base(const iterator_base<T,OPtr>& rhs) :
idx_(rhs.idx_), base_(rhs.base_), extents_(rhs.extents_),
strides_(rhs.strides_), index_base_(rhs.index_base_) {
}
// default constructor required
iterator_base() {}
};
template<typename T, std::size_t NumDims>
struct iterator_policies :
public boost::detail::multi_array::default_iterator_policies,
private value_accessor_generator<T,NumDims>::type {
private:
typedef typename value_accessor_generator<T,NumDims>::type super_type;
public:
template <class IteratorAdaptor>
typename IteratorAdaptor::reference
dereference(const IteratorAdaptor& iter) const {
typedef typename IteratorAdaptor::reference reference;
return super_type::access(boost::type<reference>(),
iter.base().idx_,
iter.base().base_,
iter.base().extents_,
iter.base().strides_,
iter.base().index_base_);
}
template <class IteratorAdaptor>
static void increment(IteratorAdaptor& x) { ++x.base().idx_; }
template <class IteratorAdaptor>
static void decrement(IteratorAdaptor& x) { --x.base().idx_; }
template <class IteratorAdaptor1, class IteratorAdaptor2>
bool equal(IteratorAdaptor1& lhs, IteratorAdaptor2& rhs) const {
return (lhs.base().idx_ == rhs.base().idx_) &&
(lhs.base().base_ == rhs.base().base_) &&
(lhs.base().extents_ == rhs.base().extents_) &&
(lhs.base().strides_ == rhs.base().strides_) &&
(lhs.base().index_base_ == rhs.base().index_base_);
}
template <class IteratorAdaptor, class DifferenceType>
static void advance(IteratorAdaptor& x, DifferenceType n) {
x.idx_ += n;
}
template <class IteratorAdaptor1, class IteratorAdaptor2>
typename IteratorAdaptor1::difference_type
distance(IteratorAdaptor1& lhs, IteratorAdaptor2& rhs) const {
return rhs.base().idx_ - lhs.base().idx_;
}
};
template <typename T, typename base_type,
std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct iterator_gen_helper {
private:
typedef iterator_policies<T,NumDims> policies;
typedef value_type* pointer_type;
typedef tag category;
public:
typedef boost::detail::multi_array::iterator_adaptor<base_type,policies,value_type,
reference_type,pointer_type,category,difference_type> type;
};
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct iterator_generator {
private:
typedef iterator_base<T,T*> base_type;
public:
typedef typename iterator_gen_helper<T,base_type,NumDims,value_type,
reference_type,tag,difference_type>::type type;
};
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct const_iterator_generator {
private:
typedef iterator_base<T,const T*> base_type;
public:
typedef typename iterator_gen_helper<T,base_type,NumDims,value_type,
reference_type,tag,difference_type>::type type;
};
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct reverse_iterator_generator {
private:
typedef iterator_base<T,T*> base_type;
typedef typename iterator_gen_helper<T,base_type,NumDims,value_type,
reference_type,tag,difference_type>::type it_type;
public:
typedef typename boost::reverse_iterator_generator<it_type>::type type;
};
template <typename T, std::size_t NumDims, typename value_type,
typename reference_type, typename tag, typename difference_type>
struct const_reverse_iterator_generator {
private:
typedef iterator_base<T,const T*> base_type;
typedef typename iterator_gen_helper<T,base_type,NumDims,value_type,
reference_type,tag,difference_type>::type it_type;
public:
typedef typename boost::reverse_iterator_generator<it_type>::type type;
};
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // ITERATOR_RG071801_HPP

View File

@@ -0,0 +1,966 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// Revision History:
// 27 Mar 2002 Ronald Garcia
// Forked from the main tree iterator adaptors. Necessary to
// allow iterator::operator->*() to work with multi_array iterators.
// 01 Feb 2002 Jeremy Siek
// Added more comments in default_iterator_policies.
// 08 Jan 2001 David Abrahams
// Moved concept checks into a separate class, which makes MSVC
// better at dealing with them.
// 07 Jan 2001 David Abrahams
// Choose proxy for operator->() only if the reference type is not a reference.
// Updated workarounds for __MWERKS__ == 0x2406
// 20 Dec 2001 David Abrahams
// Adjusted is_convertible workarounds for __MWERKS__ == 0x2406
// 03 Nov 2001 Jeremy Siek
// Changed the named template parameter interface and internal.
// 04 Oct 2001 Jeremy Siek
// Changed projection_iterator to not rely on the default reference,
// working around a limitation of detail::iterator_traits.
// 04 Oct 2001 David Abrahams
// Applied indirect_iterator patch from George A. Heintzelman <georgeh@aya.yale.edu>
// Changed name of "bind" to "select" to avoid problems with MSVC.
// 26 Sep 2001 David Abrahams
// Added borland bug fix
// 08 Mar 2001 Jeremy Siek
// Added support for optional named template parameters.
// 19 Feb 2001 David Abrahams
// Rolled back reverse_iterator_pair_generator again, as it doesn't
// save typing on a conforming compiler.
// 18 Feb 2001 David Abrahams
// Reinstated reverse_iterator_pair_generator
// 16 Feb 2001 David Abrahams
// Add an implicit conversion operator to operator_arrow_proxy
// as CW and BCC workarounds.
// 11 Feb 2001 David Abrahams
// Switch to use of BOOST_STATIC_CONSTANT where possible
// 11 Feb 2001 Jeremy Siek
// Removed workaround for older MIPSpro compiler. The workaround
// was preventing the proper functionality of the underlying
// iterator being carried forward into the iterator adaptor.
// Also added is_bidirectional enum to avoid EDG compiler error.
// 11 Feb 2001 David Abrahams
// Borland fixes up the wazoo. It finally works!
// 10 Feb 2001 David Abrahams
// Removed traits argument from iterator_adaptor<> and switched to
// explicit trait specification for maximum ease-of-use.
// Added comments to detail::iterator_defaults<>
// Began using detail::iterator_defaults<> unconditionally for code clarity
// Changed uses of `Iterator' to `Base' where non-iterators can be used.
//
// 10 Feb 2001 David Abrahams
// Rolled in supposed Borland fixes from John Maddock, but not seeing any
// improvement yet
// Changed argument order to indirect_ generator, for convenience in the
// case of input iterators (where Reference must be a value type).
// Removed derivation of filter_iterator_policies from
// default_iterator_policies, since the iterator category is likely to be
// reduced (we don't want to allow illegal operations like decrement).
// Support for a simpler filter iterator interface.
//
// 09 Feb 2001 David Abrahams
// Improved interface to indirect_ and reverse_ iterators
// Rolled back Jeremy's new constructor for now; it was causing
// problems with counting_iterator_test
// Attempted fix for Borland
//
// 09 Feb 2001 Jeremy Siek
// Added iterator constructor to allow const adaptor
// from non-const adaptee.
// Changed make_xxx to pass iterators by-value to
// get arrays converted to pointers.
// Removed InnerIterator template parameter from
// indirect_iterator_generator.
// Rearranged parameters for make_filter_iterator
//
// 07 Feb 2001 Jeremy Siek
// Removed some const iterator adaptor generators.
// Added make_xxx_iterator() helper functions for remaining
// iterator adaptors.
// Removed some traits template parameters where they
// where no longer needed thanks to detail::iterator_traits.
// Moved some of the compile-time logic into enums for
// EDG compatibility.
//
// 07 Feb 2001 David Abrahams
// Removed iterator_adaptor_pair_generator and
// reverse_iterator_pair_generator (more such culling to come)
// Improved comments
// Changed all uses of std::iterator_traits as default arguments
// to boost::detail::iterator_traits for improved utility in
// non-generic contexts
// Fixed naming convention of non-template parameter names
//
// 06 Feb 2001 David Abrahams
// Produce operator-> proxy objects for InputIterators
// Added static assertions to do some basic concept checks
// Renamed single-type generators -> xxx_generator
// Renamed const/nonconst iterator generators -> xxx_pair_generator
// Added make_transform_iterator(iter, function)
// The existence of boost::detail::iterator_traits allowed many
// template arguments to be defaulted. Some arguments had to be
// moved to accomplish it.
//
// 04 Feb 2001 MWERKS bug workaround, concept checking for proper
// reference types (David Abrahams)
#ifndef BOOST_ITERATOR_ADAPTOR_RG032702_HPP_
# define BOOST_ITERATOR_ADAPTOR_RG032702_HPP_
# include <boost/iterator.hpp>
# include <boost/utility.hpp>
# include <boost/compressed_pair.hpp>
# include <boost/concept_check.hpp>
# include <boost/type.hpp>
# include <boost/static_assert.hpp>
# include <boost/type_traits.hpp>
# include <boost/detail/iterator.hpp>
# include <boost/detail/select_type.hpp>
// I was having some problems with VC6. I couldn't tell whether our hack for
// stock GCC was causing problems so I needed an easy way to turn it on and
// off. Now we can test the hack with various compilers and still have an
// "out" if it doesn't work. -dwa 7/31/00
# if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 && !defined(__STL_USE_NAMESPACES)
# define BOOST_RELOPS_AMBIGUITY_BUG 1
# endif
namespace boost {
namespace detail {
namespace multi_array {
//============================================================================
// Default policies for iterator adaptors. You can use this as a base
// class if you want to customize particular policies.
struct default_iterator_policies
{
// Some of the member functions were defined static, but Borland
// got confused and thought they were non-const. Also, Sun C++
// does not like static function templates.
//
// The reason some members were defined static is because there is
// not state (data members) needed by those members of the
// default_iterator_policies class. If your policies class member
// functions need to access state stored in the policies object,
// then the member functions should not be static (they can't be).
template <class Base>
void initialize(Base&)
{ }
template <class IteratorAdaptor>
typename IteratorAdaptor::reference dereference(const IteratorAdaptor& x) const
{ return *x.base(); }
template <class IteratorAdaptor>
void increment(IteratorAdaptor& x)
{ ++x.base(); }
template <class IteratorAdaptor>
void decrement(IteratorAdaptor& x)
{ --x.base(); }
template <class IteratorAdaptor, class DifferenceType>
void advance(IteratorAdaptor& x, DifferenceType n)
{ x.base() += n; }
template <class IteratorAdaptor1, class IteratorAdaptor2>
typename IteratorAdaptor1::difference_type
distance(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
{ return y.base() - x.base(); }
template <class IteratorAdaptor1, class IteratorAdaptor2>
bool equal(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
{ return x.base() == y.base(); }
};
// putting the comparisons in a base class avoids the g++
// ambiguous overload bug due to the relops operators
#ifdef BOOST_RELOPS_AMBIGUITY_BUG
template <class Derived, class Base>
struct iterator_comparisons : Base { };
template <class D1, class D2, class Base1, class Base2>
inline bool operator==(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return x.policies().equal(x, y);
}
template <class D1, class D2, class Base1, class Base2>
inline bool operator!=(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return !x.policies().equal(x, y);
}
template <class D1, class D2, class Base1, class Base2>
inline bool operator<(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return x.policies().distance(y, x) < 0;
}
template <class D1, class D2, class Base1, class Base2>
inline bool operator>(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return x.policies().distance(y, x) > 0;
}
template <class D1, class D2, class Base1, class Base2>
inline bool operator>=(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return x.policies().distance(y, x) >= 0;
}
template <class D1, class D2, class Base1, class Base2>
inline bool operator<=(const iterator_comparisons<D1,Base1>& xb,
const iterator_comparisons<D2,Base2>& yb)
{
const D1& x = static_cast<const D1&>(xb);
const D2& y = static_cast<const D2&>(yb);
return x.policies().distance(y, x) <= 0;
}
#endif
namespace detail {
// operator->() needs special support for input iterators to strictly meet the
// standard's requirements. If *i is not a reference type, we must still
// produce a (constant) lvalue to which a pointer can be formed. We do that by
// returning an instantiation of this special proxy class template.
template <class T>
struct operator_arrow_proxy
{
operator_arrow_proxy(const T& x) : m_value(x) {}
// RG removed const below
T* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// RG - removed const below
operator T*() const { return &m_value; }
mutable T m_value;
};
template <class Iter>
inline operator_arrow_proxy<typename Iter::reference>
operator_arrow(const Iter& i, std::input_iterator_tag) {
// RG - THIS is the change I needed to make!
// My input iterators need to return proxy references rather than values
typedef typename Iter::reference value_t; // VC++ needs this typedef
return operator_arrow_proxy<value_t>(*i);
}
template <class Iter>
inline typename Iter::pointer
operator_arrow(const Iter& i, std::forward_iterator_tag) {
return &(*i);
}
template <class Value, class Reference, class Pointer>
struct operator_arrow_result_generator
{
//RG - another important change!
typedef operator_arrow_proxy<Reference> proxy;
// Borland chokes unless it's an actual enum (!)
enum { use_proxy = !boost::is_reference<Reference>::value };
typedef typename boost::detail::if_true<(use_proxy)>::template
then<
proxy,
// else
Pointer
>::type type;
};
# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Select default pointer and reference types for adapted non-pointer
// iterators based on the iterator and the value_type. Poor man's partial
// specialization is in use here.
template <bool is_pointer>
struct iterator_defaults_select
{
template <class Iterator,class Value>
struct traits
{
// The assumption is that iterator_traits can deduce these types
// properly as long as the iterator is not a pointer.
typedef typename boost::detail::iterator_traits<Iterator>::pointer pointer;
typedef typename boost::detail::iterator_traits<Iterator>::reference reference;
};
};
// Select default pointer and reference types for adapted pointer iterators
// given a (possibly-const) value_type.
template <>
struct iterator_defaults_select<true>
{
template <class Iterator,class Value>
struct traits
{
typedef Value* pointer;
typedef Value& reference;
};
};
// Consolidate selection of the default pointer and reference type
template <class Iterator,class Value>
struct iterator_defaults
{
BOOST_STATIC_CONSTANT(bool, is_ptr = boost::is_pointer<Iterator>::value);
typedef typename iterator_defaults_select<is_ptr>::template traits<Iterator,Value> traits;
typedef typename traits::pointer pointer;
typedef typename traits::reference reference;
};
# else
template <class Iterator,class Value>
struct iterator_defaults : iterator_traits<Iterator>
{
// Trying to factor the common is_same expression into an enum or a
// static bool constant confused Borland.
typedef typename if_true<(
::boost::is_same<Value,typename iterator_traits<Iterator>::value_type>::value
)>::template then<
typename iterator_traits<Iterator>::pointer,
Value*
>::type pointer;
typedef typename if_true<(
::boost::is_same<Value,typename iterator_traits<Iterator>::value_type>::value
)>::template then<
typename iterator_traits<Iterator>::reference,
Value&
>::type reference;
};
# endif
//===========================================================================
// Specify the defaults for iterator_adaptor's template parameters
struct default_argument { };
// This class template is a workaround for MSVC.
struct dummy_default_gen {
template <class Base, class Traits>
struct select { typedef default_argument type; };
};
// This class template is a workaround for MSVC.
template <class Gen> struct default_generator {
typedef dummy_default_gen type;
};
struct default_value_type {
template <class Base, class Traits>
struct select {
typedef typename boost::detail::iterator_traits<Base>::value_type type;
};
};
template <> struct default_generator<default_value_type>
{ typedef default_value_type type; }; // VC++ workaround
struct default_difference_type {
template <class Base, class Traits>
struct select {
typedef typename boost::detail::iterator_traits<Base>::difference_type type;
};
};
template <> struct default_generator<default_difference_type>
{ typedef default_difference_type type; }; // VC++ workaround
struct default_iterator_category {
template <class Base, class Traits>
struct select {
typedef typename boost::detail::iterator_traits<Base>::iterator_category type;
};
};
template <> struct default_generator<default_iterator_category>
{ typedef default_iterator_category type; }; // VC++ workaround
struct default_pointer {
template <class Base, class Traits>
struct select {
typedef typename Traits::value_type Value;
typedef typename boost::detail::multi_array::detail::iterator_defaults<Base,Value>::pointer
type;
};
};
template <> struct default_generator<default_pointer>
{ typedef default_pointer type; }; // VC++ workaround
struct default_reference {
template <class Base, class Traits>
struct select {
typedef typename Traits::value_type Value;
typedef typename boost::detail::multi_array::detail::iterator_defaults<Base,Value>::reference
type;
};
};
template <> struct default_generator<default_reference>
{ typedef default_reference type; }; // VC++ workaround
} // namespace detail
//===========================================================================
// Support for named template parameters
struct named_template_param_base { };
namespace detail {
struct value_type_tag { };
struct reference_tag { };
struct pointer_tag { };
struct difference_type_tag { };
struct iterator_category_tag { };
// avoid using std::pair because A or B might be a reference type, and g++
// complains about forming references to references inside std::pair
template <class A, class B>
struct cons_type {
typedef A first_type;
typedef B second_type;
};
} // namespace detail
template <class Value> struct value_type_is : public named_template_param_base
{
typedef detail::cons_type<detail::value_type_tag, Value> type;
};
template <class Reference> struct reference_is : public named_template_param_base
{
typedef detail::cons_type<detail::reference_tag, Reference> type;
};
template <class Pointer> struct pointer_is : public named_template_param_base
{
typedef detail::cons_type<detail::pointer_tag, Pointer> type;
};
template <class Difference> struct difference_type_is
: public named_template_param_base
{
typedef detail::cons_type<detail::difference_type_tag, Difference> type;
};
template <class IteratorCategory> struct iterator_category_is
: public named_template_param_base
{
typedef detail::cons_type<detail::iterator_category_tag, IteratorCategory> type;
};
namespace detail {
struct end_of_list { };
// Given an associative list, find the value with the matching key.
// An associative list is a list of key-value pairs. The list is
// built out of cons_type's and is terminated by end_of_list.
# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || defined(__BORLANDC__)
template <class AssocList, class Key>
struct find_param;
struct find_param_continue {
template <class AssocList, class Key2> struct select {
typedef typename AssocList::first_type Head;
typedef typename Head::first_type Key1;
typedef typename Head::second_type Value;
typedef typename if_true<(is_same<Key1, Key2>::value)>::template
then<Value,
typename find_param<typename AssocList::second_type, Key2>::type
>::type type;
};
};
struct find_param_end {
template <class AssocList, class Key>
struct select { typedef detail::default_argument type; };
};
template <class AssocList> struct find_param_helper1
{ typedef find_param_continue type; };
template <> struct find_param_helper1<end_of_list>
{ typedef find_param_end type; };
template <class AssocList, class Key>
struct find_param {
typedef typename find_param_helper1<AssocList>::type select1;
typedef typename select1::template select<AssocList, Key>::type type;
};
# else
template <class AssocList, class Key> struct find_param;
template <class Key>
struct find_param<end_of_list, Key> { typedef default_argument type; };
// Found a matching Key, return the associated Value
template <class Key, class Value, class Rest>
struct find_param<detail::cons_type< detail::cons_type<Key, Value>, Rest>, Key> {
typedef Value type;
};
// Non-matching keys, continue the search
template <class Key1, class Value, class Rest, class Key2>
struct find_param<detail::cons_type< detail::cons_type<Key1, Value>, Rest>, Key2> {
typedef typename find_param<Rest, Key2>::type type;
};
# endif
struct make_named_arg {
template <class Key, class Value>
struct select { typedef typename Value::type type; };
};
struct make_key_value {
template <class Key, class Value>
struct select { typedef detail::cons_type<Key, Value> type; };
};
template <class Value>
struct is_named_parameter
{
enum { value = is_convertible<Value, named_template_param_base>::value };
};
# if defined(__MWERKS__) && __MWERKS__ <= 0x2406 // workaround for broken is_convertible implementation
template <class T> struct is_named_parameter<value_type_is<T> > { enum { value = true }; };
template <class T> struct is_named_parameter<reference_is<T> > { enum { value = true }; };
template <class T> struct is_named_parameter<pointer_is<T> > { enum { value = true }; };
template <class T> struct is_named_parameter<difference_type_is<T> > { enum { value = true }; };
template <class T> struct is_named_parameter<iterator_category_is<T> > { enum { value = true }; };
# endif
template <class Key, class Value>
struct make_arg {
# ifdef __BORLANDC__
// Borland C++ doesn't like the extra indirection of is_named_parameter
typedef typename
if_true<(is_convertible<Value,named_template_param_base>::value)>::
template then<make_named_arg, make_key_value>::type Make;
# else
enum { is_named = is_named_parameter<Value>::value };
typedef typename if_true<(is_named)>::template
then<make_named_arg, make_key_value>::type Make;
# endif
typedef typename Make::template select<Key, Value>::type type;
};
// Mechanism for resolving the default argument for a template parameter.
template <class T> struct is_default { typedef type_traits::no_type type; };
template <> struct is_default<default_argument>
{ typedef type_traits::yes_type type; };
struct choose_default {
template <class Arg, class DefaultGen, class Base, class Traits>
struct select {
typedef typename default_generator<DefaultGen>::type Gen;
typedef typename Gen::template select<Base,Traits>::type type;
};
};
struct choose_arg {
template <class Arg, class DefaultGen, class Base, class Traits>
struct select {
typedef Arg type;
};
};
template <class UseDefault>
struct choose_arg_or_default { typedef choose_arg type; };
template <> struct choose_arg_or_default<type_traits::yes_type> {
typedef choose_default type;
};
template <class Arg, class DefaultGen, class Base, class Traits>
class resolve_default {
typedef typename choose_arg_or_default<typename is_default<Arg>::type>::type
Selector;
public:
typedef typename Selector
::template select<Arg, DefaultGen, Base, Traits>::type type;
};
template <class Base, class Value, class Reference, class Pointer,
class Category, class Distance>
class iterator_adaptor_traits_gen
{
// Form an associative list out of the template parameters
// If the argument is a normal parameter (not named) then make_arg
// creates a key-value pair. If the argument is a named parameter,
// then make_arg extracts the key-value pair defined inside the
// named parameter.
typedef detail::cons_type< typename make_arg<value_type_tag, Value>::type,
detail::cons_type<typename make_arg<reference_tag, Reference>::type,
detail::cons_type<typename make_arg<pointer_tag, Pointer>::type,
detail::cons_type<typename make_arg<iterator_category_tag, Category>::type,
detail::cons_type<typename make_arg<difference_type_tag, Distance>::type,
end_of_list> > > > > ArgList;
// Search the list for particular parameters
typedef typename find_param<ArgList, value_type_tag>::type Val;
typedef typename find_param<ArgList, difference_type_tag>::type Diff;
typedef typename find_param<ArgList, iterator_category_tag>::type Cat;
typedef typename find_param<ArgList, pointer_tag>::type Ptr;
typedef typename find_param<ArgList, reference_tag>::type Ref;
typedef boost::iterator<Category, Value, Distance, Pointer, Reference>
Traits0;
// Compute the defaults if necessary
typedef typename resolve_default<Val, default_value_type, Base, Traits0>::type
value_type;
// if getting default value type from iterator_traits, then it won't be const
typedef typename resolve_default<Diff, default_difference_type, Base,
Traits0>::type difference_type;
typedef typename resolve_default<Cat, default_iterator_category, Base,
Traits0>::type iterator_category;
typedef boost::iterator<iterator_category, value_type, difference_type,
Pointer, Reference> Traits1;
// Compute the defaults for pointer and reference. This is done as a
// separate step because the defaults for pointer and reference depend
// on value_type.
typedef typename resolve_default<Ptr, default_pointer, Base, Traits1>::type
pointer;
typedef typename resolve_default<Ref, default_reference, Base, Traits1>::type
reference;
public:
typedef boost::iterator<iterator_category,
typename remove_const<value_type>::type,
difference_type, pointer, reference> type;
};
// This is really a partial concept check for iterators. Should it
// be moved or done differently?
template <class Category, class Value, class Difference, class Pointer, class Reference>
struct validator
{
BOOST_STATIC_CONSTANT(
bool, is_input_or_output_iter
= (boost::is_convertible<Category*,std::input_iterator_tag*>::value
| boost::is_convertible<Category*,std::output_iterator_tag*>::value));
// Iterators should satisfy one of the known categories
BOOST_STATIC_ASSERT(is_input_or_output_iter);
// Iterators >= ForwardIterator must produce real references
// as required by the C++ standard requirements in Table 74.
BOOST_STATIC_CONSTANT(
bool, forward_iter_with_real_reference
= ((!boost::is_convertible<Category*,std::forward_iterator_tag*>::value)
| boost::is_same<Reference,Value&>::value
| boost::is_same<Reference,typename add_const<Value>::type&>::value));
BOOST_STATIC_ASSERT(forward_iter_with_real_reference);
};
} // namespace detail
// This macro definition is only temporary in this file
# if !defined(BOOST_MSVC)
# define BOOST_ARG_DEPENDENT_TYPENAME typename
# else
# define BOOST_ARG_DEPENDENT_TYPENAME
# endif
//============================================================================
//iterator_adaptor - Adapts a generic piece of data as an iterator. Adaptation
// is especially easy if the data being adapted is itself an iterator
//
// Base - the base (usually iterator) type being wrapped.
//
// Policies - a set of policies determining how the resulting iterator
// works.
//
// Value - if supplied, the value_type of the resulting iterator, unless
// const. If const, a conforming compiler strips constness for the
// value_type. If not supplied, iterator_traits<Base>::value_type is used
//
// Reference - the reference type of the resulting iterator, and in
// particular, the result type of operator*(). If not supplied but
// Value is supplied, Value& is used. Otherwise
// iterator_traits<Base>::reference is used.
//
// Pointer - the pointer type of the resulting iterator, and in
// particular, the result type of operator->(). If not
// supplied but Value is supplied, Value* is used. Otherwise
// iterator_traits<Base>::pointer is used.
//
// Category - the iterator_category of the resulting iterator. If not
// supplied, iterator_traits<Base>::iterator_category is used.
//
// Distance - the difference_type of the resulting iterator. If not
// supplied, iterator_traits<Base>::difference_type is used.
template <class Base, class Policies,
class Value = ::boost::detail::multi_array::detail::default_argument,
class Reference = ::boost::detail::multi_array::detail::default_argument,
class Pointer = ::boost::detail::multi_array::detail::default_argument,
class Category = ::boost::detail::multi_array::detail::default_argument,
class Distance = ::boost::detail::multi_array::detail::default_argument
>
struct iterator_adaptor :
#ifdef BOOST_RELOPS_AMBIGUITY_BUG
iterator_comparisons<
iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance>,
typename detail::iterator_adaptor_traits_gen<Base,Value,Reference,Pointer,Category, Distance>::type
>
#else
detail::iterator_adaptor_traits_gen<Base,Value,Reference,Pointer,Category,Distance>::type
#endif
{
typedef iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance> self;
public:
typedef detail::iterator_adaptor_traits_gen<Base,Value,Reference,Pointer,Category,Distance> TraitsGen;
typedef typename TraitsGen::type Traits;
typedef typename Traits::difference_type difference_type;
typedef typename Traits::value_type value_type;
typedef typename Traits::pointer pointer;
typedef typename Traits::reference reference;
typedef typename Traits::iterator_category iterator_category;
typedef Base base_type;
typedef Policies policies_type;
private:
typedef detail::validator<
iterator_category,value_type,difference_type,pointer,reference
> concept_check;
public:
iterator_adaptor()
{
}
explicit
iterator_adaptor(const Base& it, const Policies& p = Policies())
: m_iter_p(it, p) {
policies().initialize(base());
}
template <class Iter2, class Value2, class Pointer2, class Reference2>
iterator_adaptor (
const iterator_adaptor<Iter2,Policies,Value2,Reference2,Pointer2,Category,Distance>& src)
: m_iter_p(src.base(), src.policies())
{
policies().initialize(base());
}
#if defined(BOOST_MSVC) || defined(__BORLANDC__)
// This is required to prevent a bug in how VC++ generates
// the assignment operator for compressed_pairv
iterator_adaptor& operator= (const iterator_adaptor& x) {
m_iter_p = x.m_iter_p;
return *this;
}
#endif
reference operator*() const {
return policies().dereference(*this);
}
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning( disable : 4284 )
#endif
typename boost::detail::multi_array::detail::operator_arrow_result_generator<value_type,reference,pointer>::type
operator->() const
{ return detail::operator_arrow(*this, iterator_category()); }
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
value_type operator[](difference_type n) const
{ return *(*this + n); }
self& operator++() {
#if !defined(__MWERKS__) || __MWERKS__ >= 0x2405
policies().increment(*this);
#else
// Odd bug, MWERKS couldn't deduce the type for the member template
// Workaround by explicitly specifying the type.
policies().increment<self>(*this);
#endif
return *this;
}
self operator++(int) { self tmp(*this); ++*this; return tmp; }
self& operator--() {
#if !defined(__MWERKS__) || __MWERKS__ >= 0x2405
policies().decrement(*this);
#else
policies().decrement<self>(*this);
#endif
return *this;
}
self operator--(int) { self tmp(*this); --*this; return tmp; }
self& operator+=(difference_type n) {
policies().advance(*this, n);
return *this;
}
self& operator-=(difference_type n) {
policies().advance(*this, -n);
return *this;
}
base_type const& base() const { return m_iter_p.first(); }
// Moved from global scope to avoid ambiguity with the operator-() which
// subtracts iterators from one another.
self operator-(difference_type x) const
{ self result(*this); return result -= x; }
private:
compressed_pair<Base,Policies> m_iter_p;
public: // implementation details (too many compilers have trouble when these are private).
base_type& base() { return m_iter_p.first(); }
Policies& policies() { return m_iter_p.second(); }
const Policies& policies() const { return m_iter_p.second(); }
};
template <class Base, class Policies, class Value, class Reference, class Pointer,
class Category, class Distance1, class Distance2>
iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance1>
operator+(
iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance1> p,
Distance2 x)
{
return p += x;
}
template <class Base, class Policies, class Value, class Reference, class Pointer,
class Category, class Distance1, class Distance2>
iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance1>
operator+(
Distance2 x,
iterator_adaptor<Base,Policies,Value,Reference,Pointer,Category,Distance1> p)
{
return p += x;
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2, class Category,
class Distance>
typename iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>::difference_type
operator-(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
typedef typename iterator_adaptor<Iterator1,Policies,Value1,Reference1,
Pointer1,Category,Distance>::difference_type difference_type;
return x.policies().distance(y, x);
}
#ifndef BOOST_RELOPS_AMBIGUITY_BUG
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator==(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return x.policies().equal(x, y);
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator<(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return x.policies().distance(y, x) < 0;
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator>(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return x.policies().distance(y, x) > 0;
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator>=(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return x.policies().distance(y, x) >= 0;
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator<=(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return x.policies().distance(y, x) <= 0;
}
template <class Iterator1, class Iterator2, class Policies, class Value1, class Value2,
class Reference1, class Reference2, class Pointer1, class Pointer2,
class Category, class Distance>
inline bool
operator!=(
const iterator_adaptor<Iterator1,Policies,Value1,Reference1,Pointer1,Category,Distance>& x,
const iterator_adaptor<Iterator2,Policies,Value2,Reference2,Pointer2,Category,Distance>& y)
{
return !x.policies().equal(x, y);
}
#endif
} // namespace multi_array
} // namespace detail
} // namespace boost
# undef BOOST_ARG_DEPENDENT_TYPENAME
#endif

View File

@@ -0,0 +1,58 @@
#ifndef RANGE_LIST_RG072501_HPP
#define RANGE_LIST_RG072501_HPP
//
// range_list.hpp - helper to build boost::arrays for *_set types
//
#include "boost/array.hpp"
namespace boost {
namespace detail {
namespace multi_array {
/////////////////////////////////////////////////////////////////////////
// choose range list begins
//
struct choose_range_list_n {
template <typename T, std::size_t NumRanges>
struct bind {
typedef boost::array<T,NumRanges> type;
};
};
struct choose_range_list_zero {
template <typename T, std::size_t NumRanges>
struct bind {
typedef boost::array<T,1> type;
};
};
template <std::size_t NumRanges>
struct range_list_gen_helper {
typedef choose_range_list_n choice;
};
template <>
struct range_list_gen_helper<0> {
typedef choose_range_list_zero choice;
};
template <typename T, std::size_t NumRanges>
struct range_list_generator {
private:
typedef typename range_list_gen_helper<NumRanges>::choice Choice;
public:
typedef typename Choice::template bind<T,NumRanges>::type type;
};
//
// choose range list ends
/////////////////////////////////////////////////////////////////////////
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // RANGE_LIST_RG072501_HPP

View File

@@ -0,0 +1,112 @@
#ifndef BOOST_STORAGE_ORDER_RG071801_HPP
#define BOOST_STORAGE_ORDER_RG071801_HPP
#include "boost/multi_array/types.hpp"
#include "boost/array.hpp"
#include "boost/multi_array/algorithm.hpp"
#include <algorithm>
#include <cstddef>
#include <functional>
#include <vector>
namespace boost {
// RG - This is to make things work with VC++. So sad, so sad.
class c_storage_order;
class fortran_storage_order;
template <std::size_t NumDims>
class general_storage_order
{
public:
typedef detail::multi_array::size_type size_type;
template <typename OrderingIter, typename AscendingIter>
general_storage_order(OrderingIter ordering,
AscendingIter ascending) {
boost::copy_n(ordering,NumDims,ordering_.begin());
boost::copy_n(ascending,NumDims,ascending_.begin());
}
// RG - ideally these would not be necessary, but some compilers
// don't like template conversion operators. I suspect that not
// too many folk will feel the need to use customized
// storage_order objects, I sacrifice that feature for compiler support.
general_storage_order(const c_storage_order&) {
for (size_type i=0; i != NumDims; ++i) {
ordering_[i] = NumDims - 1 - i;
}
ascending_.assign(true);
}
general_storage_order(const fortran_storage_order&) {
for (size_type i=0; i != NumDims; ++i) {
ordering_[i] = i;
}
ascending_.assign(true);
}
size_type ordering(size_type dim) const { return ordering_[dim]; }
bool ascending(size_type dim) const { return ascending_[dim]; }
bool all_dims_ascending() const {
return std::accumulate(ascending_.begin(),ascending_.end(),true,
std::logical_and<bool>());
}
bool operator==(general_storage_order const& rhs) const {
return (ordering_ == rhs.ordering_) &&
(ascending_ == rhs.ascending_);
}
protected:
boost::array<size_type,NumDims> ordering_;
boost::array<bool,NumDims> ascending_;
};
class c_storage_order
{
typedef detail::multi_array::size_type size_type;
public:
// This is the idiom for creating your own custom storage orders.
// Not supported by all compilers though!
#ifndef __MWERKS__ // Metrowerks screams "ambiguity!"
template <std::size_t NumDims>
operator general_storage_order<NumDims>() const {
boost::array<size_type,NumDims> ordering;
boost::array<bool,NumDims> ascending;
for (size_type i=0; i != NumDims; ++i) {
ordering[i] = NumDims - 1 - i;
ascending[i] = true;
}
return general_storage_order<NumDims>(ordering.begin(),
ascending.begin());
}
#endif
};
class fortran_storage_order
{
typedef detail::multi_array::size_type size_type;
public:
// This is the idiom for creating your own custom storage orders.
// Not supported by all compilers though!
#ifndef __MWERKS__ // Metrowerks screams "ambiguity!"
template <std::size_t NumDims>
operator general_storage_order<NumDims>() const {
boost::array<size_type,NumDims> ordering;
boost::array<bool,NumDims> ascending;
for (size_type i=0; i != NumDims; ++i) {
ordering[i] = i;
ascending[i] = true;
}
return general_storage_order<NumDims>(ordering.begin(),
ascending.begin());
}
#endif
};
} // namespace boost
#endif // BOOST_ARRAY_STORAGE_RG071801_HPP

View File

@@ -0,0 +1,380 @@
#ifndef SUBARRAY_RG071801_HPP
#define SUBARRAY_RG071801_HPP
//
// subarray.hpp - used to implement standard operator[] on
// multi_arrays
//
#include "boost/multi_array/base.hpp"
#include "boost/multi_array/concept_checks.hpp"
#include "boost/limits.hpp"
#include "boost/type.hpp"
#include <algorithm>
#include <cstddef>
#include <functional>
namespace boost {
namespace detail {
namespace multi_array {
//
// const_sub_array
// multi_array's proxy class to allow multiple overloads of
// operator[] in order to provide a clean multi-dimensional array
// interface.
template <typename T, std::size_t NumDims, typename TPtr>
class const_sub_array :
public boost::detail::multi_array::multi_array_impl_base<T,NumDims>
{
typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
// template typedefs
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
// Allow default copy constructor as well.
template <typename OPtr>
const_sub_array (const const_sub_array<T,NumDims,OPtr>& rhs) :
base_(rhs.base_), extents_(rhs.extents_), strides_(rhs.strides_),
index_base_(rhs.index_base_) {
}
// const_sub_array always returns const types, regardless of its own
// constness.
const_reference operator[](index idx) const {
return super_type::access(boost::type<const_reference>(),
idx,base_,shape(),strides(),index_bases());
}
template <typename IndexList>
const element& operator()(const IndexList& indices) const {
return super_type::access_element(boost::type<const element&>(),
origin(),
indices,strides());
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
typedef const_array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
base_);
}
template <typename OPtr>
bool operator<(const const_sub_array<T,NumDims,OPtr>& rhs) const {
return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
}
template <typename OPtr>
bool operator==(const const_sub_array<T,NumDims,OPtr>& rhs) const {
if(std::equal(shape(),shape()+num_dimensions(),rhs.shape()))
return std::equal(begin(),end(),rhs.begin());
else return false;
}
template <typename OPtr>
bool operator!=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
return !(*this == rhs);
}
template <typename OPtr>
bool operator>(const const_sub_array<T,NumDims,OPtr>& rhs) const {
return rhs < *this;
}
template <typename OPtr>
bool operator<=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
return !(*this > rhs);
}
template <typename OPtr>
bool operator>=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
return !(*this < rhs);
}
const_iterator begin() const {
return const_iterator(const_iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
}
const_iterator end() const {
return const_iterator(const_iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
TPtr origin() const { return base_; }
size_type size() const { return extents_[0]; }
size_type max_size() const { return num_elements(); }
bool empty() const { return size() == 0; }
size_type num_dimensions() const { return NumDims; }
const size_type* shape() const { return extents_; }
const index* strides() const { return strides_; }
const index* index_bases() const { return index_base_; }
size_type num_elements() const {
return std::accumulate(shape(),shape() + num_dimensions(),
size_type(1), std::multiplies<size_type>());
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
protected:
template <typename,std::size_t> friend class value_accessor_n;
template <typename,std::size_t,typename> friend class const_sub_array;
#else
public: // Should be protected
#endif
const_sub_array (TPtr base,
const size_type* extents,
const index* strides,
const index* index_base) :
base_(base), extents_(extents), strides_(strides),
index_base_(index_base) {
}
TPtr base_;
const size_type* extents_;
const index* strides_;
const index* index_base_;
private:
// const_sub_array cannot be assigned to (no deep copies!)
const_sub_array& operator=(const const_sub_array&);
};
//
// sub_array
// multi_array's proxy class to allow multiple overloads of
// operator[] in order to provide a clean multi-dimensional array
// interface.
template <typename T, std::size_t NumDims>
class sub_array : public const_sub_array<T,NumDims,T*>
{
typedef const_sub_array<T,NumDims,T*> super_type;
public:
typedef typename super_type::element element;
typedef typename super_type::reference reference;
typedef typename super_type::index index;
typedef typename super_type::size_type size_type;
typedef typename super_type::iterator iterator;
typedef typename super_type::reverse_iterator reverse_iterator;
typedef typename super_type::iter_base iter_base;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::const_iter_base const_iter_base;
// template typedefs
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
// Assignment from other ConstMultiArray types.
template <typename ConstMultiArray>
sub_array& operator=(const ConstMultiArray& other) {
function_requires< boost::detail::multi_array::ConstMultiArrayConcept<
ConstMultiArray, NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
return *this;
}
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()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
}
return *this;
}
T* origin() { return base_; }
const T* origin() const { return base_; }
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,base_,shape(),strides(),index_bases());
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices) {
typedef array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
origin());
}
template <class IndexList>
element& operator()(const IndexList& indices) {
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
// RG - rbegin() and rend() written naively to thwart MSVC ICE.
reverse_iterator rbegin() {
reverse_iterator ri(end());
return ri;
}
reverse_iterator rend() {
reverse_iterator ri(begin());
return ri;
}
//
// proxies
//
template <class IndexList>
const element& operator()(const IndexList& indices) const {
return super_type::operator()(indices);
}
const_reference operator[](index idx) const {
return super_type::operator[](idx);
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
return super_type::operator[](indices);
}
const_iterator begin() const {
return super_type::begin();
}
const_iterator end() const {
return super_type::end();
}
const_reverse_iterator rbegin() const {
return super_type::rbegin();
}
const_reverse_iterator rend() const {
return super_type::rend();
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
template <typename,std::size_t> friend class value_accessor_n;
#else
public: // should be private
#endif
sub_array (T* base,
const size_type* extents,
const index* strides,
const index* index_base) :
super_type(base,extents,strides,index_base) {
}
};
} // namespace multi_array
} // namespace detail
//
// traits classes to get sub_array types
//
template <typename Array, int N>
class subarray_gen {
typedef typename Array::element element;
public:
typedef boost::detail::multi_array::sub_array<element,N> type;
};
template <typename Array, int N>
class const_subarray_gen {
typedef typename Array::element element;
public:
typedef boost::detail::multi_array::const_sub_array<element,N> type;
};
} // namespace boost
#endif // SUBARRAY_RG071801_HPP

View File

@@ -0,0 +1,25 @@
#ifndef BOOST_MULTI_ARRAY_TYPES_RG071801_HPP
#define BOOST_MULTI_ARRAY_TYPES_RG071801_HPP
//
// types.hpp - supply types that are needed by several headers
//
#include "boost/config.hpp"
#include <cstddef>
namespace boost {
namespace detail {
namespace multi_array{
// needed typedefs
typedef std::size_t size_type;
typedef int index;
} // namespace multi_array
} // namespace detail
} // namespace boost
#endif // BOOST_MULTI_ARRAY_TYPES_RG071801_HPP

View File

@@ -0,0 +1,442 @@
#ifndef BOOST_MULTI_ARRAY_VIEW_RG071301_HPP
#define BOOST_MULTI_ARRAY_VIEW_RG071301_HPP
//
// view.hpp - code for creating "views" of array data.
//
#include "boost/multi_array/base.hpp"
#include "boost/multi_array/concept_checks.hpp"
#include "boost/multi_array/iterator.hpp"
#include "boost/multi_array/storage_order.hpp"
#include "boost/multi_array/subarray.hpp"
#include "boost/multi_array/algorithm.hpp"
#include "boost/array.hpp"
#include "boost/limits.hpp"
#include <algorithm>
#include <cstddef>
#include <functional>
#include <numeric>
namespace boost {
namespace detail {
namespace multi_array {
// TPtr = const T* defaulted in base.hpp
template <typename T, std::size_t NumDims, typename TPtr>
class const_multi_array_view :
public boost::detail::multi_array::multi_array_impl_base<T,NumDims>
{
typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
// template typedefs
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
template <typename OPtr>
const_multi_array_view(const
const_multi_array_view<T,NumDims,OPtr>& other) :
base_(other.base_), origin_offset_(other.origin_offset_),
num_elements_(other.num_elements_), extent_list_(other.extent_list_),
stride_list_(other.stride_list_), index_base_list_(other.index_base_list_)
{ }
template <class BaseList>
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_);
}
void reindex(index value) {
index_base_list_.assign(value);
origin_offset_ =
calculate_indexing_offset(stride_list_,index_base_list_);
}
size_type num_dimensions() const { return NumDims; }
size_type size() const { return extent_list_.front(); }
size_type max_size() const { return num_elements(); }
bool empty() const { return size() == 0; }
const size_type* shape() const {
return extent_list_.data();
}
const index* strides() const {
return stride_list_.data();
}
const T* origin() const { return base_+origin_offset_; }
size_type num_elements() const { return num_elements_; }
const index* index_bases() const {
return index_base_list_.data();
}
template <typename IndexList>
const element& operator()(IndexList indices) const {
return super_type::access_element(boost::type<const element&>(),
origin(),
indices,strides());
}
// Only allow const element access
const_reference operator[](index idx) const {
return super_type::access(boost::type<const_reference>(),
idx,origin(),
shape(),strides(),
index_bases());
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
typedef const_array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
origin());
}
const_iterator begin() const {
return const_iterator(const_iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
}
const_iterator end() const {
return const_iterator(const_iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
template <typename OPtr>
bool operator==(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
if(std::equal(extent_list_.begin(),
extent_list_.end(),
rhs.extent_list_.begin()))
return std::equal(begin(),end(),rhs.begin());
else return false;
}
template <typename OPtr>
bool operator<(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
}
template <typename OPtr>
bool operator!=(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
return !(*this == rhs);
}
template <typename OPtr>
bool operator>(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
return rhs < *this;
}
template <typename OPtr>
bool operator<=(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
return !(*this > rhs);
}
template <typename OPtr>
bool operator>=(const
const_multi_array_view<T,NumDims,OPtr>& rhs)
const {
return !(*this < rhs);
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
protected:
template <typename,std::size_t> friend class multi_array_impl_base;
template <typename,std::size_t,typename> friend class const_multi_array_view;
#else
public: // should be protected
#endif
// This constructor is used by multi_array_impl_base::generate_array_view
// to create strides
template <typename ExtentList, typename Index>
explicit const_multi_array_view(TPtr base,
const ExtentList& extents,
const boost::array<Index,NumDims>& strides):
base_(base), origin_offset_(0) {
index_base_list_.assign(0);
// Get the extents and strides
boost::copy_n(extents.begin(),NumDims,extent_list_.begin());
boost::copy_n(strides.begin(),NumDims,stride_list_.begin());
// Calculate the array size
num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
size_type(1),std::multiplies<size_type>());
assert(num_elements_ != 0);
}
typedef boost::array<size_type,NumDims> size_list;
typedef boost::array<index,NumDims> index_list;
TPtr base_;
index origin_offset_;
size_type num_elements_;
size_list extent_list_;
index_list stride_list_;
index_list index_base_list_;
private:
// const_multi_array_view cannot be assigned to (no deep copies!)
const_multi_array_view& operator=(const const_multi_array_view& other);
};
template <typename T, std::size_t NumDims>
class multi_array_view :
public const_multi_array_view<T,NumDims,T*>
{
typedef const_multi_array_view<T,NumDims,T*> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::reference reference;
typedef typename super_type::iterator iterator;
typedef typename super_type::iter_base iter_base;
typedef typename super_type::reverse_iterator reverse_iterator;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
// template typedefs
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
// Assignment from other ConstMultiArray types.
template <typename ConstMultiArray>
multi_array_view& operator=(const ConstMultiArray& other) {
function_requires<
boost::detail::multi_array::
ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
return *this;
}
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()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
}
return *this;
}
element* origin() { return base_+origin_offset_; }
template <class IndexList>
element& operator()(const IndexList& indices) {
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
}
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,origin(),
shape(),strides(),
index_bases());
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices) {
typedef array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
origin());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
reverse_iterator rbegin() {
return reverse_iterator(end());
}
reverse_iterator rend() {
return reverse_iterator(begin());
}
// Using declarations don't seem to work for g++
// These are the proxies to work around this.
const element* origin() const { return super_type::origin(); }
template <class IndexList>
const element& operator()(const IndexList& indices) const {
return super_type::operator()(indices);
}
const_reference operator[](index idx) const {
return super_type::operator[](idx);
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const boost::detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
return super_type::operator[](indices);
}
const_iterator begin() const {
return super_type::begin();
}
const_iterator end() const {
return super_type::end();
}
const_reverse_iterator rbegin() const {
return super_type::rbegin();
}
const_reverse_iterator rend() const {
return super_type::rend();
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
template <typename,std::size_t> friend class multi_array_impl_base;
#else
public: // should be private
#endif
// constructor used by multi_array_impl_base::generate_array_view to
// generate array views
template <typename ExtentList, typename Index>
explicit multi_array_view(T* base,
const ExtentList& extents,
const boost::array<Index,NumDims>& strides) :
super_type(base,extents,strides) { }
};
} // namespace multi_array
} // namespace detail
//
// traits classes to get array_view types
//
template <typename Array, int N>
class array_view_gen {
typedef typename Array::element element;
public:
typedef boost::detail::multi_array::multi_array_view<element,N> type;
};
template <typename Array, int N>
class const_array_view_gen {
typedef typename Array::element element;
public:
typedef boost::detail::multi_array::const_multi_array_view<element,N> type;
};
} // namespace boost
#endif // BOOST_MULTI_ARRAY_VIEW_RG071301_HPP

View File

@@ -0,0 +1,581 @@
#ifndef BOOST_MULTI_ARRAY_REF_RG071801_HPP
#define BOOST_MULTI_ARRAY_REF_RG071801_HPP
//
// multi_array_ref.hpp - code for creating "views" of array data.
//
#include "boost/multi_array/base.hpp"
#include "boost/multi_array/collection_concept.hpp"
#include "boost/multi_array/concept_checks.hpp"
#include "boost/multi_array/iterator.hpp"
#include "boost/multi_array/storage_order.hpp"
#include "boost/multi_array/subarray.hpp"
#include "boost/multi_array/view.hpp"
#include "boost/multi_array/algorithm.hpp"
#include "boost/array.hpp"
#include "boost/concept_check.hpp"
#include "boost/functional.hpp"
#include "boost/limits.hpp"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <functional>
#include <numeric>
namespace boost {
template <typename T, std::size_t NumDims,
typename TPtr = const T*
>
class const_multi_array_ref :
public detail::multi_array::multi_array_impl_base<T,NumDims>
{
typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
// template typedefs
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
// make const_multi_array_ref a friend of itself
template <typename,std::size_t,typename>
friend class const_multi_array_ref;
#endif
template <typename OPtr>
const_multi_array_ref(const const_multi_array_ref<T,NumDims,
OPtr>& other)
: base_(other.base_), storage_(other.storage_),
extent_list_(other.extent_list_),
stride_list_(other.stride_list_),
index_base_list_(other.index_base_list_),
origin_offset_(other.origin_offset_),
directional_offset_(other.directional_offset_),
num_elements_(other.num_elements_) { }
template <typename ExtentList>
explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
base_(base), storage_(c_storage_order()) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
index_base_list_.assign(0);
init_multi_array_ref(extents.begin());
}
template <typename ExtentList>
explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
const general_storage_order<NumDims>& so) :
base_(base), storage_(so) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
index_base_list_.assign(0);
init_multi_array_ref(extents.begin());
}
explicit const_multi_array_ref(TPtr base,
const detail::multi_array::
extent_gen<NumDims>& ranges) :
base_(base), storage_(c_storage_order()) {
init_from_extent_gen(ranges);
}
explicit const_multi_array_ref(TPtr base,
const detail::multi_array::
extent_gen<NumDims>& ranges,
const general_storage_order<NumDims>& so) :
base_(base), storage_(so) {
init_from_extent_gen(ranges);
}
template <class InputIterator>
void assign(InputIterator begin, InputIterator end) {
boost::function_requires<InputIteratorConcept<InputIterator> >();
InputIterator in_iter = begin;
T* out_iter = base_;
std::size_t copy_count=0;
while (in_iter != end && copy_count < num_elements_) {
*out_iter++ = *in_iter++;
copy_count++;
}
}
template <class BaseList>
void reindex(const BaseList& values) {
boost::function_requires<
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_,
storage_,index_base_list_);
}
void reindex(index value) {
index_base_list_.assign(value);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
}
template <typename SizeList>
void reshape(const SizeList& extents) {
boost::function_requires<
detail::multi_array::CollectionConcept<SizeList> >();
assert(num_elements_ ==
std::accumulate(extents.begin(),extents.end(),
size_type(1),std::multiplies<size_type>()));
std::copy(extents.begin(),extents.end(),extent_list_.begin());
compute_strides(stride_list_,extent_list_,storage_);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
}
size_type num_dimensions() const { return NumDims; }
size_type size() const { return extent_list_.front(); }
// given reshaping functionality, this is the max possible size.
size_type max_size() const { return num_elements(); }
bool empty() const { return size() == 0; }
const size_type* shape() const {
return extent_list_.data();
}
const index* strides() const {
return stride_list_.data();
}
const element* origin() const { return base_+origin_offset_; }
const element* data() const { return base_; }
size_type num_elements() const { return num_elements_; }
const index* index_bases() const {
return index_base_list_.data();
}
template <typename IndexList>
const element& operator()(IndexList indices) const {
boost::function_requires<
detail::multi_array::CollectionConcept<IndexList> >();
return super_type::access_element(boost::type<const element&>(),
origin(),
indices,strides());
}
// Only allow const element access
const_reference operator[](index idx) const {
return super_type::access(boost::type<const_reference>(),
idx,origin(),
shape(),strides(),index_bases());
}
// see generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
typedef const_array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
origin());
}
const_iterator begin() const {
return const_iterator(const_iter_base(*index_bases(),origin(),
shape(),strides(),index_bases()));
}
const_iterator end() const {
return const_iterator(const_iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
template <typename OPtr>
bool operator==(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
if(std::equal(extent_list_.begin(),
extent_list_.end(),
rhs.extent_list_.begin()))
return std::equal(begin(),end(),rhs.begin());
else return false;
}
template <typename OPtr>
bool operator<(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
}
template <typename OPtr>
bool operator!=(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
return !(*this == rhs);
}
template <typename OPtr>
bool operator>(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
return rhs < *this;
}
template <typename OPtr>
bool operator<=(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
return !(*this > rhs);
}
template <typename OPtr>
bool operator>=(const
const_multi_array_ref<T,NumDims,OPtr>& rhs)
const {
return !(*this < rhs);
}
// This ensures that const_multi_array_ref types with different TPtr
// types can convert to each other
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
protected:
#else
public:
#endif
// This is used by multi_array, which is a subclass of this
void set_base_ptr(TPtr new_base) { base_ = new_base; }
template <typename OPtr>
const_multi_array_ref(const detail::multi_array::
const_sub_array<T,NumDims,OPtr>& rhs)
: base_(rhs.origin()),
storage_(c_storage_order()),
origin_offset_(0), directional_offset_(0),
num_elements_(rhs.num_elements())
{
using boost::copy_n;
copy_n(rhs.shape(),rhs.num_dimensions(),extent_list_.begin());
copy_n(rhs.strides(),rhs.num_dimensions(),stride_list_.begin());
copy_n(rhs.index_bases(),rhs.num_dimensions(),index_base_list_.begin());
}
typedef boost::array<size_type,NumDims> size_list;
typedef boost::array<index,NumDims> index_list;
TPtr base_;
general_storage_order<NumDims> storage_;
size_list extent_list_;
index_list stride_list_;
index_list index_base_list_;
index origin_offset_;
index directional_offset_;
size_type num_elements_;
private:
// const_multi_array_ref cannot be assigned to (no deep copies!)
const_multi_array_ref& operator=(const const_multi_array_ref& other);
void init_from_extent_gen(const
detail::multi_array::
extent_gen<NumDims>& ranges) {
typedef boost::array<index,NumDims> extent_list;
// get the index_base values
std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
index_base_list_.begin(),
boost::mem_fun_ref(&extent_range::start));
// calculate the extents
extent_list extents;
std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
extents.begin(),
boost::mem_fun_ref(&extent_range::size));
init_multi_array_ref(extents.begin());
}
template <class InputIterator>
void init_multi_array_ref(InputIterator extents_iter) {
boost::function_requires<InputIteratorConcept<InputIterator> >();
boost::copy_n(extents_iter,num_dimensions(),extent_list_.begin());
// Calculate the array size
num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
1,std::multiplies<index>());
assert(num_elements_ != 0);
compute_strides(stride_list_,extent_list_,storage_);
origin_offset_ =
calculate_origin_offset(stride_list_,extent_list_,
storage_,index_base_list_);
directional_offset_ =
calculate_descending_dimension_offset(stride_list_,extent_list_,
storage_);
}
};
template <typename T, std::size_t NumDims>
class multi_array_ref :
public const_multi_array_ref<T,NumDims,T*>
{
typedef const_multi_array_ref<T,NumDims,T*> super_type;
public:
typedef typename super_type::value_type value_type;
typedef typename super_type::reference reference;
typedef typename super_type::iterator iterator;
typedef typename super_type::iter_base iter_base;
typedef typename super_type::reverse_iterator reverse_iterator;
typedef typename super_type::const_reference const_reference;
typedef typename super_type::const_iterator const_iterator;
typedef typename super_type::const_iter_base const_iter_base;
typedef typename super_type::const_reverse_iterator const_reverse_iterator;
typedef typename super_type::element element;
typedef typename super_type::size_type size_type;
typedef typename super_type::difference_type difference_type;
typedef typename super_type::index index;
typedef typename super_type::extent_range extent_range;
template <std::size_t NDims>
struct const_array_view {
typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
};
template <std::size_t NDims>
struct array_view {
typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
};
template <class ExtentList>
explicit multi_array_ref(T* base, const ExtentList& extents) :
super_type(base,extents) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
}
template <class ExtentList>
explicit multi_array_ref(T* base, const ExtentList& extents,
const general_storage_order<NumDims>& so) :
super_type(base,extents,so) {
boost::function_requires<
detail::multi_array::CollectionConcept<ExtentList> >();
}
explicit multi_array_ref(T* base,
const detail::multi_array::
extent_gen<NumDims>& ranges) :
super_type(base,ranges) { }
explicit multi_array_ref(T* base,
const detail::multi_array::
extent_gen<NumDims>&
ranges,
const general_storage_order<NumDims>& so) :
super_type(base,ranges,so) { }
template <typename OPtr>
multi_array_ref(const detail::multi_array::
const_sub_array<T,NumDims,OPtr>& rhs)
: super_type(rhs) {}
// Assignment from other ConstMultiArray types.
template <typename ConstMultiArray>
multi_array_ref& operator=(const ConstMultiArray& other) {
function_requires<
detail::multi_array::
ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
// make sure the dimensions agree
assert(other.num_dimensions() == num_dimensions());
assert(std::equal(other.shape(),other.shape()+num_dimensions(),
shape()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
return *this;
}
multi_array_ref& operator=(const multi_array_ref& 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()));
// iterator-based copy
std::copy(other.begin(),other.end(),begin());
}
return *this;
}
element* origin() { return base_+origin_offset_; }
element* data() { return base_; }
template <class IndexList>
element& operator()(const IndexList& indices) {
boost::function_requires<
detail::multi_array::CollectionConcept<IndexList> >();
return super_type::access_element(boost::type<element&>(),
origin(),
indices,strides());
}
reference operator[](index idx) {
return super_type::access(boost::type<reference>(),
idx,origin(),
shape(),strides(),
index_bases());
}
// See note attached to generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename array_view<NDims>::type
operator[](const detail::multi_array::
index_gen<NumDims,NDims>& indices) {
typedef array_view<NDims>::type return_type;
return
super_type::generate_array_view(boost::type<return_type>(),
indices,
shape(),
strides(),
index_bases(),
origin());
}
iterator begin() {
return iterator(iter_base(*index_bases(),origin(),shape(),
strides(),index_bases()));
}
iterator end() {
return iterator(iter_base(*index_bases()+*shape(),origin(),
shape(),strides(),index_bases()));
}
// RG - rbegin() and rend() written naively to thwart MSVC ICE.
reverse_iterator rbegin() {
reverse_iterator ri(end());
return ri;
}
reverse_iterator rend() {
reverse_iterator ri(begin());
return ri;
}
// Using declarations don't seem to work for g++
// These are the proxies to work around this.
const element* origin() const { return super_type::origin(); }
const element* data() const { return super_type::data(); }
template <class IndexList>
const element& operator()(const IndexList& indices) const {
boost::function_requires<
detail::multi_array::CollectionConcept<IndexList> >();
return super_type::operator()(indices);
}
const_reference operator[](index idx) const {
return super_type::access(boost::type<const_reference>(),
idx,origin(),
shape(),strides(),index_bases());
}
// See note attached to generate_array_view in base.hpp
#ifndef BOOST_MSVC
template <int NDims>
#else
template <int NumDims, int NDims> // else ICE
#endif // BOOST_MSVC
typename const_array_view<NDims>::type
operator[](const detail::multi_array::
index_gen<NumDims,NDims>& indices)
const {
return super_type::operator[](indices);
}
const_iterator begin() const {
return super_type::begin();
}
const_iterator end() const {
return super_type::end();
}
const_reverse_iterator rbegin() const {
return super_type::rbegin();
}
const_reverse_iterator rend() const {
return super_type::rend();
}
};
} // namespace boost
#endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP

50
test/access.cpp Normal file
View File

@@ -0,0 +1,50 @@
//
// access.cpp - operator[] and operator() tests with various arrays
// The tests assume that they are working on an Array of shape 2x3x4
//
#include "generative_tests.hpp"
template <typename Array>
void access(Array& A, const mutable_array_tag&) {
assign(A);
access(A,const_array_tag());
const Array& CA = A;
access(CA,const_array_tag());
}
template <typename Array>
void access(Array& A, const const_array_tag&) {
const int ndims = 3;
typedef typename Array::index index;
const index idx0 = A.index_bases()[0];
const index idx1 = A.index_bases()[1];
const index idx2 = A.index_bases()[2];
// operator[]
int cnum = 0;
const Array& CA = A;
for (index i = idx0; i != idx0+2; ++i)
for (index j = idx1; j != idx1+3; ++j)
for (index k = idx2; k != idx2+4; ++k) {
BOOST_TEST(A[i][j][k] == cnum++);
BOOST_TEST(CA[i][j][k] == A[i][j][k]);
}
// operator()
for (index i2 = 0; i2 != 2; ++i2)
for (index j2 = 0; j2 != 3; ++j2)
for (index k2 = 0; k2 != 4; ++k2) {
boost::array<index,ndims> indices;
indices[0] = i2; indices[1] = j2; indices[2] = k2;
BOOST_TEST(A(indices) == A[i2][j2][k2]);
BOOST_TEST(CA(indices) == A(indices));
}
++tests_run;
}
int test_main(int,char**) {
return run_generative_tests();
}

61
test/assign.cpp Normal file
View File

@@ -0,0 +1,61 @@
//
// assign.cpp - Test out operator=() on the different types
//
//
#include "generative_tests.hpp"
#include "boost/array.hpp"
#include "boost/multi_array.hpp"
#include "boost/cstdlib.hpp"
#include <algorithm>
#include <iostream>
template <typename ArrayA, typename ArrayB>
bool equal(const ArrayA& A, const ArrayB& B)
{
typename ArrayA::const_iterator ia;
typename ArrayB::const_iterator ib = B.begin();
for (ia = A.begin(); ia != A.end(); ++ia, ++ib)
if (!equal(*ia, *ib))
return false;
return true;
}
bool equal(const int& a, const int& b)
{
return a == b;
}
template <typename Array>
void access(Array& A, const mutable_array_tag&) {
assign(A);
typedef boost::multi_array<int,3> array3;
int insert[] = {
99,98,97,96,
95,94,93,92,
91,90,89,88,
87,86,85,84,
83,82,81,80,
79,78,77,76
};
const int insert_size = 2*3*4;
array3 filler(boost::extents[2][3][4]);
filler.assign(insert,insert+insert_size);
A = filler;
BOOST_TEST(equal(A,filler));
++tests_run;
}
template <typename Array>
void access(Array&, const const_array_tag&) {
}
int test_main(int,char**) {
return run_generative_tests();
}

131
test/compare.cpp Normal file
View File

@@ -0,0 +1,131 @@
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include <algorithm>
#include <list>
int
test_main(int, char*[])
{
typedef boost::multi_array<double, 3> array;
typedef array::size_type size_type;
boost::array<size_type,3> sizes = { { 3, 3, 3 } };
const size_type num_elements = 27;
// Copy Constructor
{
array A(sizes);
std::vector<double> vals(num_elements, 4.5);
A.assign(vals.begin(),vals.end());
array B(A);
BOOST_TEST(A == B);
BOOST_TEST(B == A);
BOOST_TEST(A[0] == B[0]);
}
// Assignment Operator
{
array A(sizes), B(sizes);
std::vector<double> vals(num_elements, 4.5);
A.assign(vals.begin(),vals.end());
B = A;
BOOST_TEST(A == B);
BOOST_TEST(B == A);
BOOST_TEST(B[0] == A[0]);
typedef array::index_range range;
array::index_gen indices;
array::array_view<2>::type C = A[indices[2][range()][range()]];
array::array_view<2>::type D = B[indices[2][range()][range()]];
BOOST_TEST(C == D);
}
// Different Arrays
{
array A(sizes), B(sizes);
std::vector<double> valsA(num_elements, 4.5);
std::vector<double> valsB(num_elements, 2.5);
A.assign(valsA.begin(),valsA.end());
B.assign(valsB.begin(),valsB.end());
BOOST_TEST(A != B);
BOOST_TEST(B != A);
BOOST_TEST(A[0] != B[0]);
typedef array::index_range range;
array::index_gen indices;
array::array_view<2>::type C = A[indices[2][range()][range()]];
array::array_view<2>::type D = B[indices[2][range()][range()]];
BOOST_TEST(C != D);
}
// Comparisons galore!
{
array A(sizes), B(sizes);
double valsA[] = {
0, 0, 0,
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 1, 1,
1, 1, 1,
2, 2, 2,
2, 2, 2,
2, 2, 2
};
double valsB[] = {
0, 0, 0,
0, 0, 0,
0, 0, 0,
1, 1, 1,
1, 1, 1,
1, 1, 1,
2, 2, 2,
2, 2, 2,
2, 2, 1
};
A.assign(valsA,valsA+num_elements);
B.assign(valsB,valsB+num_elements);
BOOST_TEST(B < A);
BOOST_TEST(A > B);
BOOST_TEST(B <= A);
BOOST_TEST(A >= B);
BOOST_TEST(B[0] == A[0]);
BOOST_TEST(B[2] < A[2]);
array C = A;
BOOST_TEST(C <= A);
BOOST_TEST(C >= A);
BOOST_TEST(!(C < A));
BOOST_TEST(!(C > A));
typedef array::index_range range;
array::index_gen indices;
array::array_view<2>::type D = A[indices[2][range()][range()]];
array::array_view<2>::type E = B[indices[2][range()][range()]];
BOOST_TEST(E < D);
BOOST_TEST(E <= D);
}
return boost::exit_success;
}

52
test/concept_checks.cpp Normal file
View File

@@ -0,0 +1,52 @@
//
// concept_checks.cpp -
// make sure the types meet concept requirements
//
#include "boost/concept_check.hpp"
#include "boost/multi_array/concept_checks.hpp"
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
typedef boost::multi_array_ref<int,ndims> array_ref;
typedef boost::const_multi_array_ref<int,ndims> const_array_ref;
typedef array::array_view<ndims>::type array_view;
typedef array::const_array_view<ndims>::type const_array_view;
typedef array::subarray<ndims>::type subarray;
typedef array::const_subarray<ndims>::type const_subarray;
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<array,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<array_ref,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<const_array_ref,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<array_view,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<const_array_view,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<subarray,ndims> >();
boost::function_requires<
boost::detail::multi_array::ConstMultiArrayConcept<const_subarray,ndims> >();
boost::function_requires<
boost::detail::multi_array::MutableMultiArrayConcept<array,ndims> >();
boost::function_requires<
boost::detail::multi_array::MutableMultiArrayConcept<array_ref,ndims> >();
boost::function_requires<
boost::detail::multi_array::MutableMultiArrayConcept<array_view,ndims> >();
boost::function_requires<
boost::detail::multi_array::MutableMultiArrayConcept<subarray,ndims> >();
return boost::exit_success;
}

201
test/constructors.cpp Normal file
View File

@@ -0,0 +1,201 @@
//
// constructors.cpp - Testing out the various constructor options
//
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/multi_array.hpp"
#include "boost/multi_array_ref.hpp"
#include <algorithm>
#include <list>
template <class Array>
void check_shape(const Array& A,
unsigned int* sizes,
int* strides,
unsigned int num_elements)
{
BOOST_TEST(A.num_elements() == num_elements);
BOOST_TEST(A.size() == *sizes);
BOOST_TEST(std::equal(sizes, sizes + A.num_dimensions(), A.shape()));
BOOST_TEST(std::equal(strides, strides + A.num_dimensions(), A.strides()));
check_shape(A[0], ++sizes, ++strides, num_elements / A.size());
}
void check_shape(const double&, unsigned int*, int*, unsigned int)
{}
template <typename ArrayA, typename ArrayB>
bool equal(const ArrayA& A, const ArrayB& B)
{
typename ArrayA::const_iterator ia;
typename ArrayB::const_iterator ib = B.begin();
for (ia = A.begin(); ia != A.end(); ++ia, ++ib)
if (!equal(*ia, *ib))
return false;
return true;
}
bool equal(const double& a, const double& b)
{
return a == b;
}
int
test_main(int, char*[])
{
typedef boost::multi_array<double, 3>::size_type size_type;
boost::array<size_type,3> sizes = { { 3, 3, 3 } };
int strides[] = { 9, 3, 1 };
size_type num_elements = 27;
// Constructor 1, default storage order and allocator
{
boost::multi_array<double, 3> A(sizes);
check_shape(A, &sizes[0], strides, num_elements);
double* ptr = 0;
boost::multi_array_ref<double,3> B(ptr,sizes);
check_shape(B, &sizes[0], strides, num_elements);
const double* cptr = ptr;
boost::const_multi_array_ref<double,3> C(cptr,sizes);
check_shape(C, &sizes[0], strides, num_elements);
}
// Constructor 1, fortran storage order and user-supplied allocator
{
typedef boost::multi_array<double, 3,
std::allocator<double> >::size_type size_type;
size_type num_elements = 27;
int col_strides[] = { 1, 3, 9 };
boost::multi_array<double, 3,
std::allocator<double> > A(sizes,boost::fortran_storage_order());
check_shape(A, &sizes[0], col_strides, num_elements);
double *ptr=0;
boost::multi_array_ref<double, 3>
B(ptr,sizes,boost::fortran_storage_order());
check_shape(B, &sizes[0], col_strides, num_elements);
const double *cptr=ptr;
boost::const_multi_array_ref<double, 3>
C(cptr,sizes,boost::fortran_storage_order());
check_shape(C, &sizes[0], col_strides, num_elements);
}
// Constructor 2, default storage order and allocator
{
typedef boost::multi_array<double, 3>::size_type size_type;
size_type num_elements = 27;
boost::multi_array<double, 3>::extent_gen extents;
boost::multi_array<double, 3> A(extents[3][3][3]);
check_shape(A, &sizes[0], strides, num_elements);
double *ptr=0;
boost::multi_array_ref<double, 3> B(ptr,extents[3][3][3]);
check_shape(B, &sizes[0], strides, num_elements);
const double *cptr=ptr;
boost::const_multi_array_ref<double, 3> C(cptr,extents[3][3][3]);
check_shape(C, &sizes[0], strides, num_elements);
}
// Copy Constructors
{
typedef boost::multi_array<double, 3>::size_type size_type;
size_type num_elements = 27;
std::vector<double> vals(27, 4.5);
boost::multi_array<double, 3> A(sizes);
A.assign(vals.begin(),vals.end());
boost::multi_array<double, 3> B(A);
check_shape(B, &sizes[0], strides, num_elements);
BOOST_TEST(equal(A, B));
double ptr[27];
boost::multi_array_ref<double, 3> C(ptr,sizes);
A.assign(vals.begin(),vals.end());
boost::multi_array_ref<double, 3> D(C);
check_shape(D, &sizes[0], strides, num_elements);
BOOST_TEST(C.data() == D.data());
const double* cptr = ptr;
boost::const_multi_array_ref<double, 3> E(cptr,sizes);
boost::const_multi_array_ref<double, 3> F(E);
check_shape(F, &sizes[0], strides, num_elements);
BOOST_TEST(E.data() == F.data());
}
// Conversion construction
{
typedef boost::multi_array<double, 3>::size_type size_type;
size_type num_elements = 27;
std::vector<double> vals(27, 4.5);
boost::multi_array<double, 3> A(sizes);
A.assign(vals.begin(),vals.end());
boost::multi_array_ref<double, 3> B(A);
boost::const_multi_array_ref<double, 3> C(A);
check_shape(B, &sizes[0], strides, num_elements);
check_shape(C, &sizes[0], strides, num_elements);
BOOST_TEST(B.data() == A.data());
BOOST_TEST(C.data() == A.data());
double ptr[27];
boost::multi_array_ref<double, 3> D(ptr,sizes);
D.assign(vals.begin(),vals.end());
boost::const_multi_array_ref<double, 3> E(D);
check_shape(E, &sizes[0], strides, num_elements);
BOOST_TEST(E.data() == D.data());
}
// Assignment Operator
{
typedef boost::multi_array<double, 3>::size_type size_type;
size_type num_elements = 27;
std::vector<double> vals(27, 4.5);
boost::multi_array<double, 3> A(sizes), B(sizes);
A.assign(vals.begin(),vals.end());
B = A;
check_shape(B, &sizes[0], strides, num_elements);
BOOST_TEST(equal(A, B));
double ptr1[27];
double ptr2[27];
boost::multi_array_ref<double, 3> C(ptr1,sizes), D(ptr2,sizes);
C.assign(vals.begin(),vals.end());
D = C;
check_shape(D, &sizes[0], strides, num_elements);
BOOST_TEST(equal(C,D));
}
// subarray value_type is multi_array
{
typedef boost::multi_array<double,3> array;
typedef array::size_type size_type;
size_type num_elements = 27;
std::vector<double> vals(num_elements, 4.5);
boost::multi_array<double, 3> A(sizes);
A.assign(vals.begin(),vals.end());
typedef array::subarray<2>::type subarray;
subarray B = A[1];
subarray::value_type C = B[0];
// should comparisons between the types work?
BOOST_TEST(equal(A[1][0],C));
BOOST_TEST(equal(B[0],C));
}
return boost::exit_success;
}

300
test/dimtest.cpp Normal file
View File

@@ -0,0 +1,300 @@
//
// Trying to diagnose problems under visual
#include "boost/config.hpp"
#include "boost/array.hpp"
#include "boost/limits.hpp"
#include <algorithm>
#include <utility>
typedef int index;
typedef std::size_t size_type;
template <typename Index,typename SizeType>
class index_range {
public:
index_range()
{
start_ = from_start();
finish_ = to_end();
stride_ = 1;
degenerate_ = false;
}
explicit index_range(Index pos)
{
start_ = pos;
finish_ = pos;
stride_ = 1;
degenerate_ = true;
}
explicit index_range(Index start, Index finish, Index stride=1)
: start_(start), finish_(finish), stride_(stride),
degenerate_(start_ == finish_)
{ }
// These are for chaining assignments to an index_range
index_range& start(Index s) {
start_ = s;
degenerate_ = (start_ == finish_);
return *this;
}
index_range& finish(Index f) {
finish_ = f;
degenerate_ = (start_ == finish_);
return *this;
}
index_range& stride(Index s) { stride_ = s; return *this; }
Index start() const
{
return start_;
}
Index get_start(Index low_index_range = 0) const
{
if (start_ == from_start())
return low_index_range;
return start_;
}
Index finish() const
{
return finish_;
}
Index get_finish(Index high_index_range = 0) const
{
if (finish_ == to_end())
return high_index_range;
return finish_;
}
unsigned int size(Index recommended_length = 0) const
{
if ((start_ == from_start()) || (finish_ == to_end()))
return recommended_length;
else
return (finish_ - start_) / stride_;
}
Index stride() const { return stride_; }
bool is_ascending_contiguous() const
{
return (start_ < finish_) && is_unit_stride();
}
void set_index_range(Index start, Index finish, Index stride=1)
{
start_ = start;
finish_ = finish;
stride_ = stride;
}
static index_range all()
{ return index_range(from_start(), to_end(), 1); }
bool is_unit_stride() const
{ return stride_ == 1; }
bool is_degenerate() const { return degenerate_; }
index_range operator-(Index shift) const
{
return index_range(start_ - shift, finish_ - shift, stride_);
}
index_range operator+(Index shift) const
{
return index_range(start_ + shift, finish_ + shift, stride_);
}
Index operator[](unsigned i) const
{
return start_ + i * stride_;
}
Index operator()(unsigned i) const
{
return start_ + i * stride_;
}
// add conversion to std::slice?
private:
static Index from_start()
{ return std::numeric_limits<Index>::min(); }
static Index to_end()
{ return std::numeric_limits<Index>::max(); }
public:
Index start_, finish_, stride_;
bool degenerate_;
};
// Express open and closed interval end-points using the comparison
// operators.
// left closed
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<=(Index s, const index_range<Index,SizeType>& r)
{
return index_range<Index,SizeType>(s, r.finish(), r.stride());
}
// left open
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<(Index s, const index_range<Index,SizeType>& r)
{
return index_range<Index,SizeType>(s + 1, r.finish(), r.stride());
}
// right open
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<(const index_range<Index,SizeType>& r, Index f)
{
return index_range<Index,SizeType>(r.start(), f, r.stride());
}
// right closed
template <typename Index, typename SizeType>
inline index_range<Index,SizeType>
operator<=(const index_range<Index,SizeType>& r, Index f)
{
return index_range<Index,SizeType>(r.start(), f + 1, r.stride());
}
//
// range_list.hpp - helper to build boost::arrays for *_set types
//
/////////////////////////////////////////////////////////////////////////
// choose range list begins
//
struct choose_range_list_n {
template <typename T, std::size_t NumRanges>
struct bind {
typedef boost::array<T,NumRanges> type;
};
};
struct choose_range_list_zero {
template <typename T, std::size_t NumRanges>
struct bind {
typedef boost::array<T,1> type;
};
};
template <std::size_t NumRanges>
struct range_list_gen_helper {
typedef choose_range_list_n choice;
};
template <>
struct range_list_gen_helper<0> {
typedef choose_range_list_zero choice;
};
template <typename T, std::size_t NumRanges>
struct range_list_generator {
private:
typedef typename range_list_gen_helper<NumRanges>::choice Choice;
public:
typedef typename Choice::template bind<T,NumRanges>::type type;
};
//
// choose range list ends
/////////////////////////////////////////////////////////////////////////
//
// Index_gen.hpp stuff
//
template <int NumRanges, int NumDims>
struct index_gen {
private:
typedef index Index;
typedef size_type SizeType;
typedef index_range<Index,SizeType> range;
public:
typedef typename range_list_generator<range,NumRanges>::type range_list;
range_list ranges_;
index_gen() { }
template <int ND>
explicit index_gen(const index_gen<NumRanges-1,ND>& rhs,
const index_range<Index,SizeType>& range)
{
std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin());
*ranges_.rbegin() = range;
}
index_gen<NumRanges+1,NumDims+1>
operator[](const index_range<Index,SizeType>& range) const
{
index_gen<NumRanges+1,NumDims+1> tmp;
std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin());
*tmp.ranges_.rbegin() = range;
return tmp;
}
index_gen<NumRanges+1,NumDims>
operator[](Index idx) const
{
index_gen<NumRanges+1,NumDims> tmp;
std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin());
*tmp.ranges_.rbegin() = index_range<Index,SizeType>(idx);
return tmp;
}
};
template <int NDims, int NRanges>
void accept_gen(index_gen<NRanges,NDims>& indices) {
// do nothing
}
template <typename X, typename Y, int A, int B>
class foo { };
class boo {
template <int NDims, int NRanges>
void operator[](index_gen<NRanges,NDims>& indices) {
}
};
template <typename X, typename Y, int A1, int A2>
void take_foo(foo<X,Y,A1,A2>& f) { }
int main() {
index_gen<0,0> indices;
typedef index_range<index,size_type> range;
take_foo(foo<int,std::size_t,1,2>());
indices[range()][range()][range()];
accept_gen(indices);
accept_gen(index_gen<0,0>());
accept_gen(indices[range()][range()][range()]);
boo b;
b[indices[range()][range()][range()]];
return 0;
}

29
test/fail_cbracket.cpp Normal file
View File

@@ -0,0 +1,29 @@
//
// fail_cbracket.cpp -
// checking constness of const operator[].
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
array sma(sma_dims);
const array& csma = sma;
// FAIL! cannot assign to csma.
csma[0][0][0] = 5;
return boost::exit_success;
}

31
test/fail_cdata.cpp Normal file
View File

@@ -0,0 +1,31 @@
//
// fail_cdata.cpp
// Testing data() member function constness.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
const int data_size = 24;
array sma(sma_dims);
sma.assign(data,data+data_size);
const array& csma = sma;
// FAIL! data() returns a const int*
int* cdptr = csma.data();
(void)cdptr; // suppress compiler warnings;
return boost::exit_success;
}

22
test/fail_citerator.cpp Normal file
View File

@@ -0,0 +1,22 @@
//
// fail_citerator.cpp -
// const_iterator/iterator conversion test
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
int test_main(int,char**) {
typedef boost::multi_array<int,3> array;
typedef array::iterator iterator1;
typedef array::const_iterator citerator1;
// ILLEGAL conversion from const_iterator to iterator
iterator1 in = citerator1();
return boost::exit_success;
}

33
test/fail_cparen.cpp Normal file
View File

@@ -0,0 +1,33 @@
//
// fail_cparen.cpp -
// Testing const operator() constness.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
const int data_size = 24;
array sma(sma_dims);
sma.assign(data,data+data_size);
const array& csma = sma;
boost::array<array::index,ndims> indices = {{0,0,0}};
// FAIL! Cannot assign to csma
csma(indices) = 5;
return boost::exit_success;
}

22
test/fail_criterator.cpp Normal file
View File

@@ -0,0 +1,22 @@
//
// fail_criterator.cpp
// const_reverse_iterator/reverse_iterator conversion test
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
int test_main(int,char**) {
typedef boost::multi_array<int,3> array;
typedef array::reverse_iterator riterator1;
typedef array::const_reverse_iterator criterator1;
// ILLEGAL conversion from const_reverse_iterator to reverse_iterator
riterator1 in = criterator1();
return boost::exit_success;
}

35
test/fail_csubarray.cpp Normal file
View File

@@ -0,0 +1,35 @@
//
// fail_csubarray.cpp -
// Testing subarray and const_subarray assignment
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
array sma(sma_dims);
int num = 0;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
array::const_subarray<ndims-1>::type csba = sma[0];
// FAIL! Preserve constness (no const_subarray -> subarray conversion).
array::subarray<ndims-1>::type sba = csba;
return boost::exit_success;
}

34
test/fail_csubarray2.cpp Normal file
View File

@@ -0,0 +1,34 @@
//
// fail_csubarray2.cpp
// Testing constness of subarray operations.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
array sma(sma_dims);
int num = 0;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
const array& sma_const = sma;
// FAIL! preserve constness.
array::subarray<ndims-1>::type sba = sma_const[0];
return boost::exit_success;
}

38
test/fail_csubarray3.cpp Normal file
View File

@@ -0,0 +1,38 @@
//
// fail_csubarray3.cpp
// Testing constness of subarray operations.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
array sma(sma_dims);
int num = 0;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
const array& sma_const = sma;
array::const_subarray<ndims-1>::type sba = sma_const[0];
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
// FAIL! sba cannot be assigned to.
sba[j][k] = num++;
return boost::exit_success;
}

54
test/fail_cview.cpp Normal file
View File

@@ -0,0 +1,54 @@
//
// fail_cview.cpp -
// ensure const_array_view doesn't allow element assignment.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
const int data_size = 24;
array sma(sma_dims);
sma.assign(data,data+data_size);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array& csma = sma;
typedef array::index_range range;
array::index_gen indices;
array::const_array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
boost::array<array::index,3> elmt = {{0,0,0}};
// FAIL! const_array_view cannot be assigned to.
csma2(elmt) = 5;
return boost::exit_success;
}

50
test/fail_cview2.cpp Normal file
View File

@@ -0,0 +1,50 @@
//
// fail_cview2.cpp
// ensure const_array_view cannot be converted to array_view
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
const int data_size = 24;
array sma(sma_dims);
sma.assign(data,data+data_size);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array& csma = sma;
typedef array::index_range range;
array::index_gen indices;
// FAIL! preserve constness (no const_array_view -> array_view).
array::array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
return boost::exit_success;
}

55
test/fail_cview3.cpp Normal file
View File

@@ -0,0 +1,55 @@
//
// fail_cview3.cpp
// ensure const_array_ref doesn't allow assignment.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
boost::array<array::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
const int data_size = 24;
array sma(sma_dims);
sma.assign(data,data+data_size);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array& csma = sma;
typedef array::index_range range;
array::index_gen indices;
array::const_array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 2; ++j)
for (array::index k = 0; k != 2; ++k)
// FAIL! csma2 cannot be assigned to.
csma2[i][j][k] = 0;
return boost::exit_success;
}

View File

@@ -0,0 +1,33 @@
//
// fail_ref_cbracket.cpp
// checking constness of const operator[].
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int data[] = {77,77,77,77,77,77,77,77,77,77,77,77,
77,77,77,77,77,77,77,77,77,77,77,77};
array_ref sma(data,sma_dims);
const array_ref& csma = sma;
// FAIL! can't assign to const multi_array_ref.
csma[0][0][0] = 5;
return boost::exit_success;
}

30
test/fail_ref_cdata.cpp Normal file
View File

@@ -0,0 +1,30 @@
//
// fail_ref_cdata.cpp -
// Testing data() member function constness.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
array_ref sma(data,sma_dims);
const array_ref& csma = sma;
// FAIL! data() returns const int*.
int* cdptr = csma.data();
(void)cdptr; // suppress compiler warnings
return boost::exit_success;
}

View File

@@ -0,0 +1,22 @@
//
// fail_ref_citerator.cpp
// const_iterator/iterator conversion test
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
int test_main(int,char**) {
typedef boost::multi_array_ref<int,3> array_ref;
typedef array_ref::iterator iterator1;
typedef array_ref::const_iterator citerator1;
// FAIL! ILLEGAL conversion from const_iterator to iterator
iterator1 in = citerator1();
return boost::exit_success;
}

33
test/fail_ref_cparen.cpp Normal file
View File

@@ -0,0 +1,33 @@
//
// fail_ref_cparen.cpp
// Testing const operator() constness.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
array_ref sma(data,sma_dims);
const array_ref& csma = sma;
boost::array<array_ref::index,ndims> indices = {{0,0,0}};
// FAIL! cannot assign to a const multi_array_ref
csma(indices) = 5;
return boost::exit_success;
}

View File

@@ -0,0 +1,22 @@
//
// fail_ref_criterator.cpp
// const_reverse_iterator/reverse_iterator conversion test
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
int test_main(int,char**) {
typedef boost::multi_array_ref<int,3> array_ref;
typedef array_ref::reverse_iterator riterator1;
typedef array_ref::const_reverse_iterator criterator1;
// Fail! ILLEGAL conversion from const_reverse_iterator to reverse_iterator
riterator1 in = criterator1();
return boost::exit_success;
}

View File

@@ -0,0 +1,37 @@
//
// fail_ref_csubarray.cpp -
// Testing subarray and const_subarray assignment
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int data[] = {77,77,77,77,77,77,77,77,77,77,77,77,
77,77,77,77,77,77,77,77,77,77,77,77};
array_ref sma(data,sma_dims);
int num = 0;
for (array_ref::index i = 0; i != 2; ++i)
for (array_ref::index j = 0; j != 3; ++j)
for (array_ref::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
array_ref::const_subarray<ndims-1>::type csba = sma[0];
array_ref::subarray<ndims-1>::type sba = csba; // FAIL! preserve constness.
return boost::exit_success;
}

View File

@@ -0,0 +1,38 @@
//
// fail_ref_csubarray2.cpp -
// Testing constness of subarray operations.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int data[] = {77,77,77,77,77,77,77,77,77,77,77,77,
77,77,77,77,77,77,77,77,77,77,77,77};
array_ref sma(data,sma_dims);
int num = 0;
for (array_ref::index i = 0; i != 2; ++i)
for (array_ref::index j = 0; j != 3; ++j)
for (array_ref::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
const array_ref& sma_const = sma;
array_ref::subarray<ndims-1>::type sba = sma_const[0]; // FAIL!
// preserve constness
return boost::exit_success;
}

View File

@@ -0,0 +1,41 @@
//
// fail_ref_csubarray3.cpp -
// Testing constness of subarray operations.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int data[] = {77,77,77,77,77,77,77,77,77,77,77,77,
77,77,77,77,77,77,77,77,77,77,77,77};
array_ref sma(data,sma_dims);
int num = 0;
for (array_ref::index i = 0; i != 2; ++i)
for (array_ref::index j = 0; j != 3; ++j)
for (array_ref::index k = 0; k != 4; ++k)
sma[i][j][k] = num++;
const array_ref& sma_const = sma;
array_ref::const_subarray<ndims-1>::type sba = sma_const[0];
for (array_ref::index j = 0; j != 3; ++j)
for (array_ref::index k = 0; k != 4; ++k)
sba[j][k] = num++; // FAIL! can't assign to const_subarray.
return boost::exit_success;
}

51
test/fail_ref_cview.cpp Normal file
View File

@@ -0,0 +1,51 @@
//
// fail_ref_cview.cpp
// ensure const_array_view doesn't allow element assignment.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
array_ref sma(data,sma_dims);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array_ref& csma = sma;
typedef array_ref::index_range range;
array_ref::index_gen indices;
array_ref::const_array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
boost::array<array_ref::index,3> elmt = {{0,0,0}};
csma2(elmt) = 5; // FAIL! csma is read only
return boost::exit_success;
}

52
test/fail_ref_cview2.cpp Normal file
View File

@@ -0,0 +1,52 @@
//
// fail_ref_cview2.cpp
// ensure const_array_view cannot be converted to array_view
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
array_ref sma(data,sma_dims);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array_ref& csma = sma;
typedef array_ref::index_range range;
array_ref::index_gen indices;
array_ref::array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
for (array_ref::index i = 0; i != 2; ++i)
for (array_ref::index j = 0; j != 2; ++j)
for (array_ref::index k = 0; k != 2; ++k)
csma2[i][j][k] = 0; // FAIL! csma2 is read only
return boost::exit_success;
}

53
test/fail_ref_cview3.cpp Normal file
View File

@@ -0,0 +1,53 @@
//
// fail_ref_cview3.cpp -
// ensure const_array_view doesn't allow assignment.
//
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array_ref<int,ndims> array_ref;
boost::array<array_ref::size_type,ndims> sma_dims = {{2,3,4}};
int 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};
array_ref sma(data,sma_dims);
//
// subarray dims:
// [base,stride,bound)
// [0,1,2), [1,1,3), [0,2,4)
//
const array_ref& csma = sma;
typedef array_ref::index_range range;
array_ref::index_gen indices;
array_ref::const_array_view<ndims>::type csma2 =
csma[indices[range(0,2)][range(1,3)][range(0,4,2)]];
for (array_ref::index i = 0; i != 2; ++i)
for (array_ref::index j = 0; j != 2; ++j)
for (array_ref::index k = 0; k != 2; ++k)
csma2[i][j][k] = 0; // FAIL! csma2 is read only.
return boost::exit_success;
}

267
test/generative_tests.hpp Normal file
View File

@@ -0,0 +1,267 @@
#ifndef GENERATIVE_TESTS_RG072001_HPP
#define GENERATIVE_TESTS_RG072001_HPP
//
// generative-tests.hpp - Framework for running tests on all the types
// of multi_array
//
// In order to create a set of tests, you must define the following two
// function signatures:
// template <typename Array>
// void access(Array& A, const mutable_array_tag&);
//
// template <typename Array>
// void access(Array& A, const const_array_tag&);
//
// The framework will always pass 2x3x4 arrays into these functions.
// The const_array_tag version of access must NOT attempt to modify
// the array. Assume that the passed array has constness in this case.
//
// The mutable_array_tag version of access should pass the array to the
// assign() function in order to set its values before running tests.
//
// If you wish to write your own code to assign data to the array
// (ie. test the iterators by assigning data with them), you must
// #define MULTIARRAY_TEST_ASSIGN before including this file.
// assign() will call this function.
//
// If you wish to know how many tests were run, you must increment
// the global variable 'tests_run' somewhere in your test code.
//
// Since generative-tests uses the Boost.Test framework, you must
// define at least the following:
//
// int test_main(int,char**) { return run_generative_tests(); }
//
#include "boost/multi_array.hpp"
#include "boost/multi_array_ref.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include <algorithm>
#include <iostream>
#include <vector>
namespace {
unsigned int tests_run = 0;
} // empty namespace
struct mutable_array_tag { };
struct const_array_tag { };
template <typename Array>
void assign_if_not_const(Array&, const const_array_tag&) {
// do nothing
}
template <typename Array>
void assign_if_not_const(Array& A, const mutable_array_tag&);
#ifndef MULTIARRAY_TEST_ASSIGN
template <typename Array>
void assign_if_not_const(Array& A, const mutable_array_tag&) {
typedef typename Array::index index;
const index idx0 = A.index_bases()[0];
const index idx1 = A.index_bases()[1];
const index idx2 = A.index_bases()[2];
int num = 0;
for (index i = idx0; i != idx0 + 2; ++i)
for (index j = idx1; j != idx1 + 3; ++j)
for (index k = idx2; k != idx2 + 4; ++k)
A[i][j][k] = num++;
}
#endif // MULTIARRAY_TEST_ASSIGN
template <typename Array>
void assign(Array& A) {
assign_if_not_const(A,mutable_array_tag());
}
template <typename Array>
void access(Array& A, const mutable_array_tag&);
template <typename Array>
void access(Array& A, const const_array_tag&);
template <typename StorageOrder3,typename StorageOrder4,typename Modifier>
int run_configuration(const StorageOrder3& so3,
const StorageOrder4& so4,
const Modifier& modifier) {
// multi_array
{
typedef boost::multi_array<int,3> array;
typename array::extent_gen extents;
{
array A(extents[2][3][4],so3);
modifier.modify(A);
access(A,mutable_array_tag());
}
}
// multi_array_ref
{
typedef boost::multi_array_ref<int,3> array_ref;
typename array_ref::extent_gen extents;
{
int local[24];
array_ref A(local,extents[2][3][4],so3);
modifier.modify(A);
access(A,mutable_array_tag());
}
}
// const_multi_array_ref
{
typedef boost::multi_array_ref<int,3> array_ref;
typedef boost::const_multi_array_ref<int,3> const_array_ref;
typename array_ref::extent_gen extents;
{
int local[24];
array_ref A(local,extents[2][3][4],so3);
modifier.modify(A);
assign(A);
const_array_ref B = A;
access(B,const_array_tag());
}
}
// sub_array
{
typedef boost::multi_array<int,4> array;
typename array::extent_gen extents;
{
array A(extents[2][2][3][4],so4);
modifier.modify(A);
typename array::template subarray<3>::type B = A[1];
access(B,mutable_array_tag());
}
}
// const_sub_array
{
typedef boost::multi_array<int,4> array;
typename array::extent_gen extents;
{
array A(extents[2][2][3][4],so4);
modifier.modify(A);
typename array::template subarray<3>::type B = A[1];
assign(B);
typename array::template const_subarray<3>::type C = B;
access(C,const_array_tag());
}
}
// array_view
{
typedef boost::multi_array<int,3> array;
typedef typename array::index_range range;
typename array::index_gen indices;
typename array::extent_gen extents;
{
typedef typename array::index index;
array A(extents[4][5][6],so3);
modifier.modify(A);
const index idx0 = A.index_bases()[0];
const index idx1 = A.index_bases()[1];
const index idx2 = A.index_bases()[2];
typename array::template array_view<3>::type B =A[
indices[range(idx0+1,idx0+3)]
[range(idx1+1,idx1+4)]
[range(idx2+1,idx2+5)]
];
access(B,mutable_array_tag());
}
}
// const_array_view
{
typedef boost::multi_array<int,3> array;
typedef typename array::index_range range;
typename array::index_gen indices;
typename array::extent_gen extents;
{
typedef typename array::index index;
array A(extents[4][5][6],so3);
modifier.modify(A);
const index idx0 = A.index_bases()[0];
const index idx1 = A.index_bases()[1];
const index idx2 = A.index_bases()[2];
typename array::template array_view<3>::type B =A[
indices[range(idx0+1,idx0+3)]
[range(idx1+1,idx1+4)]
[range(idx2+1,idx2+5)]
];
assign(B);
typename array::template const_array_view<3>::type C = B;
access(C,const_array_tag());
}
}
return boost::exit_success;
}
template <typename ArrayModifier>
int run_storage_tests(const ArrayModifier& modifier) {
run_configuration(boost::c_storage_order(),
boost::c_storage_order(),modifier);
run_configuration(boost::fortran_storage_order(),
boost::fortran_storage_order(),modifier);
std::size_t ordering[] = {2,0,1,3};
bool ascending[] = {false,true,true,true};
run_configuration(boost::general_storage_order<3>(ordering,ascending),
boost::general_storage_order<4>(ordering,ascending),
modifier);
return boost::exit_success;
}
struct null_modifier {
template <typename Array>
void modify(Array&) const { }
};
struct set_index_base_modifier {
template <typename Array>
void modify(Array& A) const { A.reindex(1); }
};
struct reindex_modifier {
template <typename Array>
void modify(Array& A) const {
boost::array<int,4> bases = {{1,2,3,4}};
A.reindex(bases);
}
};
struct reshape_modifier {
template <typename Array>
void modify(Array& A) const {
typedef typename Array::size_type size_type;
std::vector<size_type> old_shape(A.num_dimensions());
std::vector<size_type> new_shape(A.num_dimensions());
std::copy(A.shape(),A.shape()+A.num_dimensions(),old_shape.begin());
std::copy(old_shape.rbegin(),old_shape.rend(),new_shape.begin());
A.reshape(new_shape);
A.reshape(old_shape);
}
};
int run_generative_tests() {
run_storage_tests(null_modifier());
run_storage_tests(set_index_base_modifier());
run_storage_tests(reindex_modifier());
run_storage_tests(reshape_modifier());
std::cout << "Total Tests Run: " << tests_run << '\n';
return boost::exit_success;
}
#endif // GENERATIVE_TESTS_RG072001_HPP

72
test/idxgen1.cpp Normal file
View File

@@ -0,0 +1,72 @@
//
// idxset1.cpp - testing the code for index_gen
//
#include "boost/multi_array/index_gen.hpp"
#include "boost/multi_array/index_range.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include <cstddef>
template <int NumRanges, int NumDims>
void check(const boost::detail::multi_array::
index_gen<NumRanges,NumDims>&) { }
bool operator==(const boost::detail::multi_array::
index_range<int,std::size_t>& lhs,
const boost::detail::multi_array::
index_range<int,std::size_t>& rhs) {
return lhs.start_ == rhs.start_ &&
lhs.finish_ == rhs.finish_ &&
lhs.stride_ == rhs.stride_ &&
lhs.degenerate_ == rhs.degenerate_;
}
int
test_main(int,char**)
{
typedef boost::detail::multi_array::index_range<int,std::size_t> range;
boost::detail::multi_array::index_gen<0,0> indices;
check<1,1>(indices[range()]);
check<2,2>(indices[range()][range()]);
check<3,3>(indices[range()][range()][range()]);
check<1,0>(indices[0]);
check<2,0>(indices[0][0]);
check<2,1>(indices[range()][0]);
check<2,1>(indices[0][range()]);
check<3,0>(indices[0][0][0]);
check<3,1>(indices[range()][0][0]);
check<3,1>(indices[0][range()][0]);
check<3,1>(indices[0][0][range()]);
check<3,2>(indices[range()][range()][0]);
check<3,2>(indices[range()][0][range()]);
check<3,2>(indices[0][range()][range()]);
{
boost::detail::multi_array::index_gen<3,3> is1 =
indices[range(0,1,2)][range(1,2,3)][range(2,3,4)];
BOOST_TEST(is1.ranges_[0] == range(0,1,2));
BOOST_TEST(is1.ranges_[1] == range(1,2,3));
BOOST_TEST(is1.ranges_[2] == range(2,3,4));
}
{
boost::detail::multi_array::index_gen<3,2> is2 =
indices[range(0,1,2)][2][range(2,3,4)];
BOOST_TEST(is2.ranges_[0] == range(0,1,2));
BOOST_TEST(is2.ranges_[1] == range(2));
BOOST_TEST(is2.ranges_[1].is_degenerate());
BOOST_TEST(is2.ranges_[2] == range(2,3,4));
}
return boost::exit_success;
}

134
test/index_bases.cpp Normal file
View File

@@ -0,0 +1,134 @@
//
// index_bases - test of the index_base modifying facilities.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include <vector>
#include <iostream>
int
test_main(int,char**)
{
typedef boost::multi_array<double, 3> array;
typedef boost::multi_array_ref<double, 3> array_ref;
typedef boost::const_multi_array_ref<double, 3> const_array_ref;
typedef array::array_view<3>::type array_view;
typedef array::size_type size_type;
typedef array::extent_range range;
typedef array::index_range irange;
array::extent_gen extents;
array::index_gen indices;
// Construct with nonzero bases
{
array A(extents[range(1,4)][range(2,5)][range(3,6)]);
array B(extents[3][3][3]);
double ptr[27];
array_ref
C(ptr,extents[range(1,4)][range(2,5)][range(3,6)]);
const_array_ref
D(ptr,extents[range(1,4)][range(2,5)][range(3,6)]);
array_view E = A[indices[irange()][irange()][irange()]];
std::vector<double> vals;
for (int i = 0; i < 27; ++i)
vals.push_back(i);
A.assign(vals.begin(),vals.end());
B.assign(vals.begin(),vals.end());
C.assign(vals.begin(),vals.end());
boost::array<int,3> bases = { { 1, 2, 3 } };
for (size_type a = 0; a < A.shape()[0]; ++a)
for (size_type b = 0; b < A.shape()[1]; ++b)
for (size_type c = 0; c < A[b].size(); ++c) {
BOOST_TEST(A[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
BOOST_TEST(C[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
BOOST_TEST(D[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
// Test that E does not inherit A's index_base
BOOST_TEST(E[a][b][c] == B[a][b][c]);
}
}
// Reindex
{
typedef array::size_type size_type;
array A(extents[3][3][3]), B(extents[3][3][3]);
double ptr[27];
array_ref C(ptr,extents[3][3][3]);
const_array_ref D(ptr,extents[3][3][3]);
array_view E = B[indices[irange()][irange()][irange()]];
std::vector<double> vals;
for (int i = 0; i < 27; ++i)
vals.push_back(i);
A.assign(vals.begin(),vals.end());
B.assign(vals.begin(),vals.end());
C.assign(vals.begin(),vals.end());
boost::array<int,3> bases = { { 1, 2, 3 } };
A.reindex(bases);
C.reindex(bases);
D.reindex(bases);
E.reindex(bases);
for (size_type a = 0; a < A.shape()[0]; ++a)
for (size_type b = 0; b < A.shape()[1]; ++b)
for (size_type c = 0; c < A.shape()[2]; ++c) {
BOOST_TEST(A[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
BOOST_TEST(C[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
BOOST_TEST(D[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
BOOST_TEST(E[a+bases[0]][b+bases[1]][c+bases[2]] == B[a][b][c]);
}
}
// Set Index Base
{
typedef array::size_type size_type;
array A(extents[3][3][3]), B(extents[3][3][3]);
double ptr[27];
array_ref C(ptr,extents[3][3][3]);
const_array_ref D(ptr,extents[3][3][3]);
array_view E = B[indices[irange()][irange()][irange()]];
std::vector<double> vals;
for (int i = 0; i < 27; ++i)
vals.push_back(i);
A.assign(vals.begin(),vals.end());
B.assign(vals.begin(),vals.end());
C.assign(vals.begin(),vals.end());
A.reindex(1);
C.reindex(1);
D.reindex(1);
E.reindex(1);
for (size_type a = 0; a < A.shape()[0]; ++a)
for (size_type b = 0; b < A.shape()[1]; ++b)
for (size_type c = 0; c < A.shape()[2]; ++c) {
BOOST_TEST(A[a+1][b+1][c+1] == B[a][b][c]);
BOOST_TEST(C[a+1][b+1][c+1] == B[a][b][c]);
BOOST_TEST(D[a+1][b+1][c+1] == B[a][b][c]);
BOOST_TEST(E[a+1][b+1][c+1] == B[a][b][c]);
}
}
return boost::exit_success;
}

204
test/iterators.cpp Normal file
View File

@@ -0,0 +1,204 @@
//
// iterators.cpp - checking out iterator stuffs.
// The tests assume that the array has shape 2x3x4
//
#define MULTIARRAY_TEST_ASSIGN
#include "generative_tests.hpp"
// iterator-test-specific code
template <typename Array>
void assign_if_not_const(Array& A, const mutable_array_tag&) {
typedef typename Array::iterator iterator3;
typedef typename Array::template subarray<2>::type::iterator iterator2;
typedef typename Array::template subarray<1>::type::iterator iterator1;
int num = 0;
for (iterator3 i = A.begin(); i != A.end(); ++i)
for(iterator2 ii = (*i).begin(); ii != (*i).end(); ++ii)
for(iterator1 iii = (*ii).begin(); iii != (*ii).end(); ++iii)
*iii = num++;
}
template <typename Array>
struct ittraits_const {
typedef typename Array::const_iterator iterator3;
typedef typename boost::subarray_gen<Array,2>::type::const_iterator
iterator2;
typedef typename boost::subarray_gen<Array,1>::type::const_iterator
iterator1;
typedef typename Array::const_reverse_iterator riterator3;
typedef typename boost::subarray_gen<Array,2>::type::const_reverse_iterator
riterator2;
typedef typename boost::subarray_gen<Array,1>::type::const_reverse_iterator
riterator1;
};
template <typename Array>
struct ittraits_mutable {
typedef typename Array::iterator iterator3;
typedef typename boost::subarray_gen<Array,2>::type::iterator iterator2;
typedef typename boost::subarray_gen<Array,1>::type::iterator iterator1;
typedef typename Array::reverse_iterator riterator3;
typedef typename boost::subarray_gen<Array,2>::type::reverse_iterator
riterator2;
typedef typename boost::subarray_gen<Array,1>::type::reverse_iterator
riterator1;
};
/////////////////////////////////////////////////////////////////////////
// choose ittraits begins
//
struct choose_ittraits_const {
template <typename Array>
struct bind {
typedef ittraits_const<Array> type;
};
};
struct choose_ittraits_mutable {
template <typename Array>
struct bind {
typedef ittraits_mutable<Array> type;
};
};
template <typename ConstnessTag>
struct ittraits_gen_helper {
typedef choose_ittraits_mutable choice;
};
template <>
struct ittraits_gen_helper<const_array_tag> {
typedef choose_ittraits_const choice;
};
template <typename Array, typename ConstTag>
struct ittraits_generator {
private:
typedef typename ittraits_gen_helper<ConstTag>::choice Choice;
public:
typedef typename Choice::template bind<Array>::type type;
};
//
// choose ittraits ends
/////////////////////////////////////////////////////////////////////////
template <typename Array>
void construct_iterators(Array&) {
// Default constructed iterators and
// const iterators constructed from iterators.
{
typename Array::iterator i1;
typename Array::const_iterator ci1;
typename Array::reverse_iterator r1;
typename Array::const_reverse_iterator cr1;
#if 0 // RG - MSVC fails to compile these
typename Array::const_iterator ci2 =
typename Array::iterator();
typename Array::const_reverse_iterator cr2 =
typename Array::reverse_iterator();
#endif
typename Array::const_iterator ci2 = i1;
typename Array::const_reverse_iterator cr2 = cr1;
}
}
template <typename Array, typename IterTraits>
void test_iterators(Array& A, const IterTraits&) {
// Iterator comparison and arithmetic
{
typedef typename IterTraits::iterator3 iterator;
iterator i1 = A.begin();
iterator i2 = A.end();
BOOST_TEST(i1 < i2);
BOOST_TEST((i2 - i1) == typename iterator::difference_type(2));
}
// Standard Array Iteration
{
typedef typename IterTraits::iterator3 iterator3;
typedef typename IterTraits::iterator2 iterator2;
typedef typename IterTraits::iterator1 iterator1;
int vals = 0;
for (iterator3 i = A.begin(); i != A.end(); ++i)
for(iterator2 ii = (*i).begin(); ii != (*i).end(); ++ii)
for(iterator1 iii = (*ii).begin(); iii != (*ii).end(); ++iii)
BOOST_TEST(*iii == vals++);
}
// Using operator->() on iterators
{
typedef typename IterTraits::iterator3 iterator3;
typedef typename IterTraits::iterator2 iterator2;
typedef typename IterTraits::iterator1 iterator1;
int vals = 0;
for (iterator3 i = A.begin(); i != A.end(); ++i)
for(iterator2 ii = i->begin(); ii != i->end(); ++ii)
for(iterator1 iii = ii->begin(); iii != ii->end(); ++iii)
BOOST_TEST(*iii == vals++);
}
// Reverse Iterator Hierarchy Test
{
typedef typename IterTraits::riterator3 riterator3;
typedef typename IterTraits::riterator2 riterator2;
typedef typename IterTraits::riterator1 riterator1;
int check_iter_val = A.num_elements()-1;
for (riterator3 i = A.rbegin(); i != (riterator3)A.rend(); ++i)
for(riterator2 ii = (*i).rbegin(); ii != (riterator2)(*i).rend(); ++ii)
for(riterator1 iii = (*ii).rbegin(); iii != (riterator1)(*ii).rend();
++iii)
BOOST_TEST(*iii == check_iter_val--);
}
++tests_run;
}
template <typename Array>
void access(Array& A, const mutable_array_tag&) {
assign(A);
construct_iterators(A);
typedef typename ittraits_generator<Array,mutable_array_tag>::type
m_iter_traits;
typedef typename ittraits_generator<Array,const_array_tag>::type
c_iter_traits;
test_iterators(A,m_iter_traits());
test_iterators(A,c_iter_traits());
const Array& CA = A;
test_iterators(CA,c_iter_traits());
}
template <typename Array>
void access(Array& A, const const_array_tag&) {
construct_iterators(A);
typedef typename ittraits_generator<Array,const_array_tag>::type
c_iter_traits;
test_iterators(A,c_iter_traits());
}
int
test_main(int, char**)
{
return run_generative_tests();
}

94
test/range1.cpp Normal file
View File

@@ -0,0 +1,94 @@
//
// range1.cpp - test of index_range
//
#include "boost/multi_array/index_range.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include <cstddef>
int
test_main(int,char**)
{
typedef boost::detail::multi_array::index_range<int,std::size_t> range;
{
// typical range creation and extraction
range r1(-3,5);
BOOST_TEST(r1.start() == -3);
BOOST_TEST(r1.finish() == 5);
BOOST_TEST(r1.stride() == 1);
BOOST_TEST(!r1.is_degenerate());
BOOST_TEST(r1.get_start(0) == -3);
BOOST_TEST(r1.get_finish(100) == 5);
}
{
range r2(-3,5,2);
BOOST_TEST(r2.start() == -3);
BOOST_TEST(r2.finish() == 5);
BOOST_TEST(r2.stride() == 2);
BOOST_TEST(!r2.is_degenerate());
}
{
// degenerate creation
range r3(5);
BOOST_TEST(r3.start() == 5);
BOOST_TEST(r3.finish() == 5);
BOOST_TEST(r3.stride() == 1);
BOOST_TEST(r3.is_degenerate());
}
{
// default range creation
range r4;
BOOST_TEST(r4.get_start(0) == 0);
BOOST_TEST(r4.get_finish(100) == 100);
BOOST_TEST(r4.stride() == 1);
}
{
// create a range using the setter methods
range r5 = range().stride(2).start(-3).finish(7);
BOOST_TEST(r5.start() == -3);
BOOST_TEST(r5.stride() == 2);
BOOST_TEST(r5.finish() == 7);
}
// try out all the comparison operators
{
range r6 = -3 <= range().stride(2) < 7;
BOOST_TEST(r6.start() == -3);
BOOST_TEST(r6.stride() == 2);
BOOST_TEST(r6.finish() == 7);
}
{
range r7 = -3 < range() <= 7;
BOOST_TEST(r7.start() == -2);
BOOST_TEST(r7.stride() == 1);
BOOST_TEST(r7.finish() == 8);
}
// arithmetic operators
{
range r8 = range(0,5) + 2;
BOOST_TEST(r8.start() == 2);
BOOST_TEST(r8.stride() == 1);
BOOST_TEST(r8.finish() == 7);
}
{
range r9 = range(0,5) - 2;
BOOST_TEST(r9.start() == -2);
BOOST_TEST(r9.stride() == 1);
BOOST_TEST(r9.finish() == 3);
}
return boost::exit_success;
}

38
test/regression.cfg Normal file
View File

@@ -0,0 +1,38 @@
// Regression suite file for boost::multi_array
run libs/multi_array/test/constructors.cpp
run libs/multi_array/test/access.cpp
run libs/multi_array/test/compare.cpp
run libs/multi_array/test/iterators.cpp
run libs/multi_array/test/slice.cpp
run libs/multi_array/test/assign.cpp
run libs/multi_array/test/index_bases.cpp
run libs/multi_array/test/storage_order.cpp
run libs/multi_array/test/reshape.cpp
run libs/multi_array/test/range1.cpp
run libs/multi_array/test/idxgen1.cpp
run libs/multi_array/test/stl_interaction.cpp
compile libs/multi_array/test/concept_checks.cpp
compile-fail libs/multi_array/test/fail_cbracket.cpp
compile-fail libs/multi_array/test/fail_cdata.cpp
compile-fail libs/multi_array/test/fail_citerator.cpp
compile-fail libs/multi_array/test/fail_cparen.cpp
compile-fail libs/multi_array/test/fail_criterator.cpp
compile-fail libs/multi_array/test/fail_csubarray.cpp
compile-fail libs/multi_array/test/fail_csubarray2.cpp
compile-fail libs/multi_array/test/fail_csubarray3.cpp
compile-fail libs/multi_array/test/fail_cview.cpp
compile-fail libs/multi_array/test/fail_cview2.cpp
compile-fail libs/multi_array/test/fail_cview3.cpp
compile-fail libs/multi_array/test/fail_ref_cbracket.cpp
compile-fail libs/multi_array/test/fail_ref_cdata.cpp
compile-fail libs/multi_array/test/fail_ref_citerator.cpp
compile-fail libs/multi_array/test/fail_ref_cparen.cpp
compile-fail libs/multi_array/test/fail_ref_criterator.cpp
compile-fail libs/multi_array/test/fail_ref_csubarray.cpp
compile-fail libs/multi_array/test/fail_ref_csubarray2.cpp
compile-fail libs/multi_array/test/fail_ref_csubarray3.cpp
compile-fail libs/multi_array/test/fail_ref_cview.cpp
compile-fail libs/multi_array/test/fail_ref_cview2.cpp
compile-fail libs/multi_array/test/fail_ref_cview3.cpp

86
test/reshape.cpp Normal file
View File

@@ -0,0 +1,86 @@
//
// reshape.cpp - testing reshaping functionality
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include "boost/type.hpp"
int
test_main(int,char**)
{
const int ndims=3;
typedef boost::multi_array<int,ndims> array;
typedef boost::multi_array_ref<int,ndims> array_ref;
typedef boost::const_multi_array_ref<int,ndims> const_array_ref;
boost::array<array::size_type,ndims> dims = {{2,3,4}};
boost::array<array::size_type,ndims> new_dims = {{4,3,2}};
int 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};
const int data_size=24;
// Basic reshape test
{
array A(dims);
A.assign(data,data+data_size);
array_ref B(data,dims);
const_array_ref C(data,dims);
A.reshape(new_dims);
B.reshape(new_dims);
C.reshape(new_dims);
int* ptr = data;
for (array::index i = 0; i != 4; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 2; ++k) {
BOOST_TEST(A[i][j][k] == *ptr);
BOOST_TEST(B[i][j][k] == *ptr);
BOOST_TEST(C[i][j][k] == *ptr++);
}
}
// Ensure that index bases are preserved over reshape
{
boost::array<array::index,ndims> bases = {{0, 1, -1}};
array A(dims);
A.assign(data,data+data_size);
array_ref B(data,dims);
const_array_ref C(data,dims);
A.reindex(bases);
B.reindex(bases);
C.reindex(bases);
A.reshape(new_dims);
B.reshape(new_dims);
C.reshape(new_dims);
int* ptr = data;
for (array::index i = 0; i != 4; ++i)
for (array::index j = 1; j != 4; ++j)
for (array::index k = -1; k != 1; ++k) {
BOOST_TEST(A[i][j][k] == *ptr);
BOOST_TEST(B[i][j][k] == *ptr);
BOOST_TEST(C[i][j][k] == *ptr++);
}
}
return boost::exit_success;
}

142
test/slice.cpp Normal file
View File

@@ -0,0 +1,142 @@
//
// slice.cpp - testing out slicing on a matrices
//
#include "generative_tests.hpp"
#include "boost/array.hpp"
template <typename Array>
struct view_traits_mutable {
public:
#if 0 // RG - MSVC can't handle templates nested in templates. Use traits
typedef typename Array::template array_view<3>::type array_view3;
typedef typename Array::template array_view<2>::type array_view2;
#endif
typedef typename boost::array_view_gen<Array,3>::type array_view3;
typedef typename boost::array_view_gen<Array,2>::type array_view2;
};
template <typename Array>
struct view_traits_const {
#if 0 // RG - MSVC can't handle templates nested in templates. Use traits
typedef typename Array::template const_array_view<3>::type array_view3;
typedef typename Array::template const_array_view<2>::type array_view2;
#endif
typedef typename boost::const_array_view_gen<Array,3>::type array_view3;
typedef typename boost::const_array_view_gen<Array,2>::type array_view2;
};
/////////////////////////////////////////////////////////////////////////
// choose view_traits begins
//
struct choose_view_traits_const {
template <typename Array>
struct bind {
typedef view_traits_const<Array> type;
};
};
struct choose_view_traits_mutable {
template <typename Array>
struct bind {
typedef view_traits_mutable<Array> type;
};
};
template <typename ConstnessTag>
struct view_traits_gen_helper {
typedef choose_view_traits_mutable choice;
};
template <>
struct view_traits_gen_helper<const_array_tag> {
typedef choose_view_traits_const choice;
};
template <typename Array, typename ConstTag>
struct view_traits_generator {
private:
typedef typename view_traits_gen_helper<ConstTag>::choice Choice;
public:
typedef typename Choice::template bind<Array>::type type;
};
//
// choose view_traits ends
/////////////////////////////////////////////////////////////////////////
template <typename Array, typename ViewTraits>
void test_views(Array& A, const ViewTraits&) {
typedef typename Array::index index;
typedef typename Array::index_range range;
typename Array::index_gen indices;
const index idx0 = A.index_bases()[0];
const index idx1 = A.index_bases()[1];
const index idx2 = A.index_bases()[2];
// Standard View
{
typename ViewTraits::array_view3 B = A[
indices[range(idx0+0,idx0+2)]
[range(idx1+1,idx1+3)]
[range(idx2+0,idx2+4,2)]
];
for (index i = 0; i != 2; ++i)
for (index j = 0; j != 2; ++j)
for (index k = 0; k != 2; ++k) {
BOOST_TEST(B[i][j][k] == A[idx0+i][idx1+j+1][idx2+k*2]);
boost::array<index,3> elmts;
elmts[0]=i; elmts[1]=j; elmts[2]=k;
BOOST_TEST(B(elmts) == A[idx0+i][idx1+j+1][idx2+k*2]);
}
}
// Degenerate dimensions
{
typename ViewTraits::array_view2 B =
A[indices[range(idx0+0,idx0+2)][idx1+1][range(idx2+0,idx2+4,2)]];
for (index i = 0; i != 2; ++i)
for (index j = 0; j != 2; ++j) {
BOOST_TEST(B[i][j] == A[idx0+i][idx1+1][idx2+j*2]);
boost::array<index,2> elmts;
elmts[0]=i; elmts[1]=j;
BOOST_TEST(B(elmts) == A[idx0+i][idx1+1][idx2+j*2]);
}
}
++tests_run;
}
template <typename Array>
void access(Array& A, const mutable_array_tag&) {
assign(A);
typedef typename view_traits_generator<Array,mutable_array_tag>::type
m_view_traits;
typedef typename view_traits_generator<Array,const_array_tag>::type
c_view_traits;
test_views(A,m_view_traits());
test_views(A,c_view_traits());
const Array& CA = A;
test_views(CA,c_view_traits());
}
template <typename Array>
void access(Array& A, const const_array_tag&) {
typedef typename view_traits_generator<Array,const_array_tag>::type
c_view_traits;
test_views(A,c_view_traits());
}
int test_main(int,char**) {
return run_generative_tests();
}

61
test/stl_interaction.cpp Normal file
View File

@@ -0,0 +1,61 @@
//
// stl_interaction.cpp - Make sure multi_arrays work with STL containers.
//
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/multi_array.hpp"
#include <algorithm>
#include <vector>
int
test_main(int, char**)
{
using boost::extents;
using boost::indices;
typedef boost::multi_array_types::index_range range;
typedef boost::multi_array<int,3> array3;
typedef boost::multi_array<int,2> array2;
typedef std::vector<array3> array3vec;
int 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
};
const int data_size = 24;
int insert[] = {
99,98,
97,96,
};
const int insert_size = 4;
array3 myarray(extents[2][3][4]);
myarray.assign(data,data+data_size);
array3vec myvec(5,myarray);
BOOST_TEST(myarray == myvec[1]);
array3::array_view<2>::type myview =
myarray[indices[1][range(0,2)][range(1,3)]];
array2 filler(extents[2][2]);
filler.assign(insert,insert+insert_size);
// Modify a portion of myarray through a view (myview)
myview = filler;
myvec.push_back(myarray);
BOOST_TEST(myarray != myvec[1]);
BOOST_TEST(myarray == myvec[5]);
return boost::exit_success;
}

148
test/storage_order.cpp Normal file
View File

@@ -0,0 +1,148 @@
//
// storage_order.cpp - testing storage_order-isms.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
int
test_main(int,char**)
{
const int ndims=3;
int data_row[] = {
0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13,14,15,
16,17,18,19,
20,21,22,23
};
int data_col[] = {
0,12,
4,16,
8,20,
1,13,
5,17,
9,21,
2,14,
6,18,
10,22,
3,15,
7,19,
11,23
};
const int num_elements = 24;
// fortran storage order
{
typedef boost::multi_array<int,ndims> array;
array::extent_gen extents;
array A(extents[2][3][4],boost::fortran_storage_order());
A.assign(data_col,data_col+num_elements);
int* num = data_row;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
BOOST_TEST(A[i][j][k] == *num++);
}
// Mimic fortran_storage_order using
// general_storage_order data placement
{
typedef boost::general_storage_order<ndims> storage;
typedef boost::multi_array<int,ndims> array;
array::size_type ordering[] = {0,1,2};
bool ascending[] = {true,true,true};
array::extent_gen extents;
array A(extents[2][3][4], storage(ordering,ascending));
A.assign(data_col,data_col+num_elements);
int* num = data_row;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
BOOST_TEST(A[i][j][k] == *num++);
}
// general_storage_order with arbitrary storage order
{
typedef boost::general_storage_order<ndims> storage;
typedef boost::multi_array<int,ndims> array;
array::size_type ordering[] = {2,0,1};
bool ascending[] = {true,true,true};
array::extent_gen extents;
array A(extents[2][3][4], storage(ordering,ascending));
int data_arb[] = {
0,1,2,3,
12,13,14,15,
4,5,6,7,
16,17,18,19,
8,9,10,11,
20,21,22,23
};
A.assign(data_arb,data_arb+num_elements);
int* num = data_row;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
BOOST_TEST(A[i][j][k] == *num++);
}
// general_storage_order with descending dimensions.
{
const int ndims=3;
typedef boost::general_storage_order<ndims> storage;
typedef boost::multi_array<int,ndims> array;
array::size_type ordering[] = {2,0,1};
bool ascending[] = {false,true,true};
array::extent_gen extents;
array A(extents[2][3][4], storage(ordering,ascending));
int data_arb[] = {
12,13,14,15,
0,1,2,3,
16,17,18,19,
4,5,6,7,
20,21,22,23,
8,9,10,11
};
A.assign(data_arb,data_arb+num_elements);
int* num = data_row;
for (array::index i = 0; i != 2; ++i)
for (array::index j = 0; j != 3; ++j)
for (array::index k = 0; k != 4; ++k)
BOOST_TEST(A[i][j][k] == *num++);
}
return boost::exit_success;
}

View File

@@ -0,0 +1,28 @@
//
// test out my new storage_order stuff
//
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/multi_array/storage_order.hpp"
int
test_main(int,char**) {
using namespace boost;
array<std::size_t,5> c_ordering = {{4,3,2,1,0}};;
array<std::size_t,5> fortran_ordering = {{0,1,2,3,4}};
array<bool,5> ascending = {{true,true,true,true,true}};
general_storage_order<5> c_storage(c_ordering.begin(),
ascending.begin());
general_storage_order<5> fortran_storage(fortran_ordering.begin(),
ascending.begin());
BOOST_TEST(c_storage == (general_storage_order<5>) c_storage_order());
BOOST_TEST(fortran_storage ==
(general_storage_order<5>) fortran_storage_order());
return boost::exit_success;
}

33
test/vc_death.cpp Normal file
View File

@@ -0,0 +1,33 @@
//
// index_bases - test of the index_base modifying facilities.
//
#include "boost/multi_array.hpp"
#define BOOST_INCLUDE_MAIN
#include "boost/test/test_tools.hpp"
#include "boost/array.hpp"
#include <vector>
#include <iostream>
int
test_main(int,char**)
{
typedef boost::multi_array<double, 3> array;
typedef array::array_view<3>::type array_view;
typedef array::extent_range erange;
typedef array::index_range irange;
array::extent_gen extents;
array::index_gen indices;
// Construct with nonzero bases
{
array A(extents[erange(1,4)][erange(2,5)][erange(3,6)]);
array_view E = A[indices[irange(1,2)][irange(1,2)][irange(1,2)]];
}
return boost::exit_success;
}