commit 685b7e4c373ad32053b36035484b777ee5f55684 Author: Ronald Garcia Date: Wed May 15 16:08:54 2002 +0000 Initial submission to Boost. [SVN r13915] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/doc/Collection.html b/doc/Collection.html new file mode 100644 index 0000000..6f937c6 --- /dev/null +++ b/doc/Collection.html @@ -0,0 +1,648 @@ + + + +Collection + + + +

+ boost logo +
Collection +

+ +

Description

+ +A Collection is a concept similar to the STL Container +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: + + + + +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. + +

+ +

Associated types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Value type + +X::value_type + +The type of the object stored in a Collection. +If the Collection is mutable then +the value type must be Assignable. +Otherwise the value type must be CopyConstructible. +
+Iterator type + +X::iterator + +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 InputIterator. +
+Const iterator type + +X::const_iterator + +A type of iterator that may be used to examine, but not to modify, + a Collection's elements. +
+Reference type + +X::reference + +A type that behaves like a reference to the Collection's value type. +[1] +
+Const reference type + +X::const_reference + +A type that behaves like a const reference to the Collection's value type. +
+Pointer type + +X::pointer + +A type that behaves as a pointer to the Collection's value type. +
+Distance type + +X::difference_type + +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. +
+Size type + +X::size_type + +An unsigned integral type that can represent any nonnegative value + of the Collection's distance type. +
+

Notation

+ + + + + + + + + + + + + +
+X + +A type that is a model of Collection. +
+a, b + +Object of type X. +
+T + +The value type of X. +
+ +

Valid expressions

+ +The following expressions must be valid. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Name + +Expression + +Return type +
+Beginning of range + +a.begin() + +iterator if a is mutable, const_iterator otherwise +
+End of range + +a.end() + +iterator if a is mutable, const_iterator otherwise +
+Size + +a.size() + +size_type +
+Empty Collection + +a.empty() + +Convertible to bool +
+Swap + +a.swap(b) + +void +
+

Expression semantics

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Name + +Expression + +Semantics + +Postcondition +
+
+Beginning of range + +a.begin() + +Returns an iterator pointing to the first element in the Collection. + +a.begin() is either dereferenceable or past-the-end. It is + past-the-end if and only if a.size() == 0. +
+End of range + +a.end() + +Returns an iterator pointing one past the last element in the + Collection. + +a.end() is past-the-end. +
+Size + +a.size() + +Returns the size of the Collection, that is, its number of elements. + +a.size() >= 0 +
+Empty Collection + +a.empty() + +Equivalent to a.size() == 0. (But possibly faster.) + +  +
+Swap + +a.swap(b) + +Equivalent to swap(a,b) + +  +
+

Complexity guarantees

+ +begin() and end() are amortized constant time. +

+size() is at most linear in the Collection's +size. empty() is amortized constant time. +

+swap() is at most linear in the size of the two collections. +

Invariants

+ + + + + + + + + + + + + +
+Valid range + +For any Collection a, [a.begin(), a.end()) is a valid + range. +
+Range size + +a.size() is equal to the distance from a.begin() to a.end(). +
+Completeness + +An algorithm that iterates through the range [a.begin(), a.end()) + will pass through every element of a. +
+ + +

Models

+ + + +

Collection Refinements

+ +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. + +

ForwardCollection

+The elements are arranged in some order that +does not change spontaneously from one iteration to the next. As +a result, a ForwardCollection is +EqualityComparable +and +LessThanComparable. +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 it1 == it2 and it1 is +dereferenceable then ++it1 == ++it2. The ForwardCollection +also has a front() method. + +

+ + + + + + + + + + + + + + + +
+Name + +Expression + +Return type + +Semantics +
+Font + +a.front() + +reference if a is mutable,
const_reference +otherwise. +
+Equivalent to *(a.first()). +
+ + +

ReversibleCollection

+ +The container provides access to iterators that traverse in both +directions (forward and reverse). The iterator type must meet all of +the requirements of +BidirectionalIterator +except that the reference type does not have to be a real C++ +reference. The ReversibleCollection adds the following requirements +to those of ForwardCollection. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Name + +Expression + +Return type + +Semantics +
+Beginning of range + +a.rbegin() + +reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + +Equivalent to X::reverse_iterator(a.end()). +
+End of range + +a.rend() + +reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + +Equivalent to X::reverse_iterator(a.begin()). +
+Back + +a.back() + +reference if a is mutable,
const_reference +otherwise. +
+Equivalent to *(--a.end()). +
+ +

SequentialCollection

+ +The elements are arranged in a strict linear order. No extra methods +are required. + +

RandomAccessCollection

+ +The iterators of a RandomAccessCollection satisfy all of the +requirements of RandomAccessIterator +except that the reference type does not have to be a real C++ +reference. In addition, a RandomAccessCollection provides +an element access operator. + +

+ + + + + + + + + + + + + + + +
+Name + +Expression + +Return type + +Semantics +
+Element Access + +a[n] + +reference if a is mutable, +const_reference otherwise. + +Returns the nth element of the Collection. +n must be convertible to size_type. +Precondition: 0 <= n < a.size(). +
+ +

Notes

+ +

[1] + +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). + +

See also

+Container + + +
+
+ + +
Copyright © 2000 +Jeremy Siek, Univ.of Notre Dame and C++ Library & Compiler Group/SGI (jsiek@engr.sgi.com) +
+ + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..bfc8e47 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,44 @@ + +MultiDimensional Array Libary + + + + + + + + + + + + +
+ boost logoHomeLibrariesPeopleFAQMore
+

Boost.MultiArray

+

Boost.MultiArray provides a generic N-dimensional array concept +definition and common implementations of that interface. +

+ + +
+
+ + +
Copyright © 2000-2001 +Ronald Garcia, + Indiana University (garcia@osl.iu.edu)
+Jeremy Siek, +Indiana University (jsiek@osl.iu.edu)
+Andrew Lumsdaine, +Indiana University (lums@osl.iu.edu) +
+ diff --git a/doc/matrix.gif b/doc/matrix.gif new file mode 100644 index 0000000..e0e6ac9 Binary files /dev/null and b/doc/matrix.gif differ diff --git a/doc/notes.html b/doc/notes.html new file mode 100644 index 0000000..1d6a469 --- /dev/null +++ b/doc/notes.html @@ -0,0 +1,74 @@ + + + + + + Boost.MultiArray: Extra Notes + + + + +

+ boost logo +
Boost.MultiArray: Extra Notes +
+

+ + + +

Compiler Support

+ +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: +
    +
  1. Gnu C++ Compiler v2.95.2 (compile with -ftemplate-depth-50) +
  2. Gnu C++ Compiler v3.0.2 +
  3. Kuck and Associates C++ Compiler v4.0f +
  4. Microsoft Visual C++ v6.0 sp5 +
  5. Comeau C++ Compiler v4.2.45 beta 2 (libcomo beta 14) +
  6. Intel C++ Compiler v5.0 (with MS lib v6.0 sp5) +
  7. Metrowerks CodeWarrior C++ Compiler v7.1 +
+ +Boost.MultiArray is known to NOT work with Borland C++ v5.5.1. +Support for this compiler is forthcoming. + + +

Future Work

+ +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: +
    +
  1. Pursue and document performance issues related to compilers and + implementation. +
  2. More comprehensive examples of using the library components. +
+ +
+ +
+Ronald Garcia +
+ + +Last modified: Mon May 6 16:28:15 EST 2002 + + + + diff --git a/doc/reference.html b/doc/reference.html new file mode 100644 index 0000000..a9f3c39 --- /dev/null +++ b/doc/reference.html @@ -0,0 +1,1265 @@ +Boost.MultiArray Reference Manual

Boost.MultiArray Reference Manual

Ronald Garcia

Indiana University
Open Systems Lab

Boost.MultiArray is composed of several components. +The MultiArray concept defines a generic interface to multidimensional +containers. +multi_array is a general purpose container class +that models MultiArray. multi_array_ref +and const_multi_array_ref are adapter +classes. Using them, +you can manipulate any block of contiguous data as though it were a +multi_array. +const_multi_array_ref differs from +multi_array_ref 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.

Library Synopsis

To use Boost.MultiArray, you must include the header +boost/multi_array.hpp in your source. This file +brings the following declarations into scope:

+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;
+
+}
+

MultiArray Concept

The MultiArray +concept defines an interface to hierarchically nested +containers. It specifies operations for accessing elements, +traversing containers, and creating views +of array data. +MultiArray defines +a flexible memory model that accomodates +a variety of data layouts. +

+At each level (or dimension) of a MultiArray's +container hierarchy lie a set of ordered containers, each of which +contains the same number and type of values. The depth of this +container hierarchy is the MultiArray's dimensionality. +MultiArray is recursively defined; the +containers at each level of the container hierarchy model +MultiArray as well. While each dimension of a MultiArray +has its own size, the list of sizes for all dimensions +defines the shape of the entire MultiArray. +At the base of this hierarchy lie 1-dimensional +MultiArrays. Their values are the contained +objects of interest and not part of the container hierarchy. These are +the MultiArray's elements. +

+Like other container concepts, MultiArray exports +iterators to traverse its values. In addition, values can be +addressed directly using the familiar bracket notation. +

+MultiArray also specifies +routines for creating +specialized views. A view lets you treat a +subset of the underlying +elements in a MultiArray as though it were a separate +MultiArray. Since a view refers to the same underlying elements, +changes made to a view's elements will be reflected in the original +MultiArray. For +example, given a 3-dimensional "cube" of elements, a 2-dimensional +slice can be viewed as if it were an independent +MultiArray. + +Views are created using index_gen and +index_range objects. +index_ranges denote elements from a certain +dimension that are to be included in a +view. index_gen aggregates range data and performs +bookkeeping to determine the view type to be returned. + +MultiArray's operator[] + must be passed the result +of N chained calls to +index_gen::operator[], i.e. + +

indices[a0][a1]...[aN];
+
+ +where N is the +MultiArray's dimensionality and +indices an object of type index_gen. + +The view type is dependent upon the number of degenerate dimensions +specified to index_gen. A degenerate dimension +occurs when a single-index is specified to +index_gen for a certain dimension. For example, if +indices is an object of type +index_gen, then the following example: + +
indices[index_range(0,5)][2][index_range(0,4)];
+
+ +has a degenerate second dimension. The view generated from the above +specification will have 2 dimensions with shape 5 x 2. +If the "2" above were replaced with +another index_range object, for example: + +
indices[index_range(0,5)][index_range(0,2)][index_range(0,4)];
+
+ +then the view would have 3 dimensions.

+MultiArray exports +information regarding the memory +layout of its contained elements. Its memory model for elements is +completely defined by 4 properties: the origin, shape, index bases, +and strides. The origin is the address in memory of the element +accessed as a[0][0]...[0], where +a is a MultiArray. The shape is a list of numbers +specifying the size of containers at each dimension. For example, the +first extent is the size of the outermost container, the second extent +is the size of its subcontainers, and so on. The index bases are a +list of signed values specifying the index of the first value in a +container. All containers at the same dimension share the same index +base. Note that since positive index bases are +possible, the origin need not exist in order to determine the location +in memory of the MultiArray's elements. + The strides determine how index values are mapped to memory offsets. +They accomodate a +number of possible element layouts. For example, the elements of a 2 +dimensional array can be stored by row (i.e., the elements of each row +are stored contiguously) or by column (i.e., the elements of each +column are stored contiguously). +

Notation

What follows are the descriptions of symbols that will be used +to describe the MultiArray interface.

Table 1. Notation

AA type that is a model of MultiArray +
aAn object of type A
NumDimsThe numeric dimension parameter associated with +A.
DimsSome numeric dimension parameter such that +0<Dims<NumDims. +
indicesAn object created by some number of chained calls +to index_gen::operator[](index_range).
index_listAn object whose type models +Collection
idxA signed integral value.
tmpAn object of type + boost::array<index,NumDims>

Associated Types

+

Table 2. Associated Types

TypeDescription
value_typeThis is the value type of the container. + If NumDims == 1, then this is +element. Otherwise, this is the value type of the +immediately nested containers. +
reference +This is the reference type of the contained value. +If NumDims == 1, then this is +element&. Otherwise, this is the same type as +template subarray<NumDims-1>::type. +
const_reference +This is the const reference type of the contained value. +If NumDims == 1, then this is +const element&. Otherwise, this is the same +type as +template const_subarray<NumDims-1>::type. +
size_type +This is an unsigned integral type. It is primarily used to specify array shape. +
difference_type +This is a signed integral type used to represent the distance between two +iterators. It is the same type as +std::iterator_traits<iterator>::difference_type. +
iterator +This is an iterator over the values of A. +If NumDims == 1, then it models + +Random Access Iterator. +Otherwise it models + +Random Access Traversal Iterator, + +Readable Iterator, and + +Writable Iterator. +
const_iterator +This is the const iterator over the values of A. +
reverse_iterator +This is the reversed iterator, used to iterate backwards over the values of +A. +
const_reverse_iterator +This is the reversed const iterator. +A. +
element +This is the type of objects stored at the base of the +hierarchy of MultiArrays. It is the same as +template subarray<1>::value_type
index +This is a signed integral type used for indexing into A. It +is also used to represent strides and index bases. +
index_gen +This type is used to create a tuple of index_ranges +passed to operator[] to create +an array_view<Dims>::type object. +
index_range +This type specifies a range of indices over some dimension of a +MultiArray. This range will be visible through an +array_view<Dims>::type object. +
template subarray<Dims>::type +This is subarray type with Dims dimensions. +It is the reference type of the (NumDims - Dims) +dimension of A and also models +MultiArray. +
template const_subarray<Dims>::type +This is the const subarray type. +
template array_view<Dims>::type +This is the view type with Dims dimensions. It is +returned by calling operator[](indices). +It models MultiArray. +
template +const_array_view<Dims>::type +This is the const view type with Dims dimensions. +

Valid expressions

Table 3. Valid Expressions

ExpressionReturn typeSemantics
a.shape()const size_type* +This returns a list of NumDims elements specifying the +extent of each array dimension. +
a.strides()const index* +This returns a list of NumDims elements specifying the +stride associated with each array dimension. When accessing values, +strides is used to calculate an element's location in memory. +
a.index_bases()const index* +This returns a list of NumDims elements specifying the +numeric index of the first element for each array dimension. +
a.origin()element* if a is mutable, +const element* otherwise. + +This returns the address of the element accessed by the expression +a[0][0]...[0].. If the index bases are positive, +this element won't exist, but the address can still be used to locate +a valid element given its indices. +
a.num_dimensions()size_typeThis returns the number of dimensions of the array +(note that a.num_dimensions() == NumDims).
a.num_elements()size_typeThis returns the number of elements contained +in the array. It is equivalent to the following code: +
+std::accumulate(a.shape(),a.shape+a.num_dimensions(),
+    size_type(1),std::multiplies<size_type>());
+
a.size()size_type +This returns the number of values contained in +a. It is equivalent to a.shape()[0];
a(index_list)element&; if a is mutable, +const element& otherwise. + +This expression accesses a specific element of +a.index_list is the unique set +of indices that address the element returned. It is +equivalent to the following code (disregarding intermediate temporaries): +
+    // multiply indices by strides
+    std::transform(index_list.begin(), index_list.end(),
+      a.strides(), tmp.begin(), std::multiplies<index>()),
+
+    // add the sum of the products to the origin
+    *std::accumulate(tmp.begin(), tmp.end(), a.origin());
+
a.begin()iterator if a is mutable, +const_iterator otherwise. + This returns an iterator pointing to the beginning of +a.
a.end()iterator if a is mutable, +const_iterator otherwise. + This returns an iterator pointing to the end of +a.
a.rbegin()reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + This returns a reverse iterator pointing to the +beginning of a reversed. +
a.rend()reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + +This returns a reverse iterator pointing to the end of a +reversed. +
a[idx]reference if a is mutable, +const_reference otherwise. + +This returns a reference type that is bound to the index +idx value of a. Note that if +i is the index base for this dimension, the above +expression returns the (idx-i)th element (counting +from zero). The expression is equivalent to +*(a.begin()+idx-a.index_bases()[0]);. +
a[indices]array_view<Dims>::type if +a is mutable, +const_array_view<Dims>::type otherwise. + +This expression generates a view of the array determined by the +index_range and index values + used to construct indices. +
a == bboolThis performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable for this +expression to be valid.
a < bboolThis performs a lexicographical comparison of the +values of a and b. The element +type must model LessThanComparable for this +expression to be valid.
a <= bboolThis performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable and +LessThanComparable for this +expression to be valid.
a > bboolThis performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable and +LessThanComparable for this +expression to be valid.
a >= bboolThis performs a lexicographical comparison of the +values of a and b. The element +type must model LessThanComparable for this +expression to be valid.

Complexity guarantees

begin() and end() execute in amortized +constant time. +size() executes in at most linear time in the +MultiArray's size. +

Invariants

Table 4. Invariants

Valid range[a.begin(),a.end()) is a valid range. +
Range sizea.size() == std::distance(a.begin(),a.end());. +
Completeness +Iteration through the range +[a.begin(),a.end()) will traverse across every +value_type of a. +
Accessor Equivalence +Calling a[a1][a2]...[aN] where N==NumDims +yields the same result as calling +a(index_list), where index_list +is a Collection containing the values a1...aN. +

Associated Types for Views

The following MultiArray associated +types define the interface for creating views of existing +MultiArrays. Their interfaces and roles in the +concept are described below.

index_range

index_range objects represent half-open +strided intervals. They are aggregated (using an +index_gen object) and passed to +a MultiArray's operator[] +to create an array view. When creating a view, +each index_range denotes a range of +valid indices along one dimension of a MultiArray. +Elements that are accessed through the set of ranges specified will be +included in the constructed view. In some cases, an +index_range is created without specifying start +or finish values. In those cases, the object is interpreted to +start at the beginning of a MultiArray dimension +and end at its end.

+index_range objects can be constructed and modified +several ways in order to allow convenient and clear expression of a +range of indices. To specify ranges, index_range +supports a set of constructors, mutating member functions, and a novel +specification involving inequality operators. Using inequality +operators, a half open range [5,10) can be specified as follows: +

5 <= range() < 10;
or +
4 < range() <= 9;
and so on. + +The following describes the +index_range interface. +

Table 5. Notation

iAn object of type index_range.
idx,idx1,idx2,idx3Objects of type index.

Table 6. Associated Types

TypeDescription
indexThis is a signed integral type. It is used to +specify the start, finish, and stride values.
size_typeThis is an unsigned integral type. It is used to +report the size of the range an index_range +represents.

Table 7. Valid Expressions

ExpressionReturn typeSemantics
index_range(idx1,idx2,idx3)index_rangeThis constructs an index_range + representing the interval [idx1,idx2) + with stride idx3.
index_range(idx1,idx2)index_rangeThis constructs an index_range + representing the interval [idx1,idx2) + with unit stride. It is equivalent to + index_range(idx1,idx2,1).
index_range()index_rangeThis construct an index_range +with unspecified start and finish values.
i.start(idx1)index&This sets the start index of i to + idx.
i.finish(idx)index&This sets the finish index of i to + idx.
i.stride(idx)index&This sets the stride length of i to + idx.
i.start()indexThis returns the start index of i.
i.finish()indexThis returns the finish index of i.
i.stride()indexThis returns the stride length of i.
i.get_start(idx)indexIf i specifies a start +value, this is equivalent to i.start(). Otherwise it +returns idx.
i.get_finish(idx)indexIf i specifies a finish +value, this is equivalent to i.finish(). Otherwise it +returns idx.
i.size(idx)size_typeIf i specifies a both finish and +start values, this is equivalent to +(i.finish()-i.start())/i.stride(). Otherwise it +returns idx.
i < idxindexThis is another syntax for specifying the finish +value. This notation does not include +idx in the range of valid indices. It is equivalent to +index_range(r.start(), idx, r.stride())
i <= idxindexThis is another syntax for specifying the finish +value. This notation includes +idx in the range of valid indices. It is equivalent to +index_range(r.start(), idx + 1, r.stride())
idx < iindexThis is another syntax for specifying the start +value. This notation does not include +idx in the range of valid indices. It is equivalent to +index_range(idx + 1, i.finish(), i.stride()).
idx <= iindexThis is another syntax for specifying the start +value. This notation includes +idx1 in the range of valid indices. It is equivalent to +index_range(idx, i.finish(), i.stride()).
i + idxindexThis expression shifts the start and finish values +of i up by idx. It is equivalent to +index_range(r.start()+idx1, r.finish()+idx, r.stride())
i - idxindexThis expression shifts the start and finish values +of i up by idx. It is equivalent to +index_range(r.start()-idx1, r.finish()-idx, r.stride())

index_gen

index_gen aggregates +index_range objects in order to specify view +parameters. Chained calls to operator[] store +range and dimension information used to +instantiate a new view into a MultiArray. +

Table 8. Notation

Dims,RangesUnsigned integral values.
xAn object of type +template gen_type<Dims,Ranges>::type.
iAn object of type +index_range.
idxObjects of type index.

Table 9. Associated Types

TypeDescription
indexThis is a signed integral type. It is used to +specify degenerate dimensions.
size_typeThis is an unsigned integral type. It is used to +report the size of the range an index_range +represents.
template gen_type::<Dims,Ranges>::typeThis type generator names the result of +Dims chained calls to +index_gen::operator[]. The +Ranges parameter is determined by the number of +degenerate ranges specified (i.e. calls to +operator[](index)). Note that +index_gen and +gen_type<0,0>::type are the same type.

Table 10. Valid Expressions

ExpressionReturn typeSemantics
index_gen()gen_type<0,0>::typeThis constructs an index_gen +object. This object can then be used to generate tuples of +index_range values.
x[i]gen_type<Dims+1,Ranges+1>::typeReturns a new object containing all previous +index_range objects in addition to +i. Chained calls to +operator[] are the means by which +index_range objects are aggregated.
x[idx]gen_type<Dims,Ranges>::typeReturns a new object containing all previous +index_range objects in addition to a degenerate +range, index_range(idx,idx). Note that this is NOT +equivalent to x[index_range(idx,idx)]., which will +return an object of type +gen_type<Dims+1,Ranges+1>::type. +

Models

  • multi_array
  • multi_array_ref
  • const_multi_array_ref
  • template array_view<Dims>::type
  • template const_array_view<Dims>::type
  • template subarray<Dims>::type
  • template const_subarray<Dims>::type

Array Components

+Boost.MultiArray defines an array class, +multi_array, and two adapter classes, +multi_array_ref and +const_multi_array_ref. The three classes model +MultiArray and so they share a lot of functionality. +multi_array_ref differs from +multi_array in that the +multi_array manages its own memory, while +multi_array_ref is passed a block of memory that it +expects to be externally managed. +const_multi_array_ref differs from +multi_array_ref 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. +

Note: Preconditions, Effects, and Implementation.  +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. +

Queries. 

element* data();
+const element* data() const;

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 origin(). Note that +const_multi_array_ref only provides the const +version of this function. +

element* origin();
+const element* origin() const;

This returns the origin element of the +multi_array. Note that +const_multi_array_ref only provides the const +version of this function. (Required by MultiArray) +

const index* index_bases();

This returns the index bases for the +multi_array. (Required by MultiArray) +

const index* strides();

This returns the strides for the +multi_array. (Required by MultiArray) +

const size_type* shape();

This returns the shape of the +multi_array. (Required by MultiArray) +

Comparators. 

+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);

Each comparator executes a lexicographical compare over +the value types of the two arrays. +(Required by MultiArray) +

Preconditions. element must support the +comparator corresponding to that called on +multi_array.

Complexity. O(num_elements()).

Modifiers. 

+
+
+template <typename SizeList>
+void reshape(const SizeList& sizes)
+
+
+

This changes the shape of the multi_array. 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.

SizeList Requirements. SizeList must model +Collection.

Preconditions.  +

+std::accumulate(sizes.begin(),sizes.end(),size_type(1),std::times<size_type>()) == this->num_elements();
+sizes.size() == NumDims;
+

Postconditions.  +std::equal(sizes.begin(),sizes.end(),this->shape) == true; +

+
+
+template <typename BaseList>
+void reindex(const BaseList& values);
+
+
+

This changes the index bases of the multi_array to +correspond to the the values in values.

BaseList Requirements. BaseList must model +Collection.

Preconditions. values.size() == NumDims;

Postconditions. std::equal(values.begin(),values.end(),this->index_bases()); +

+
+
+void reindex(index value);
+
+
+

This changes the index bases of all dimensions of the +multi_array to value.

Postconditions.  +

+
+std::count_if(this->index_bases(),this->index_bases()+this->num_dimensions(),
+              std::bind_2nd(std::equal_to<index>(),value)) == 
+              this->num_dimensions();
+
+
+

multi_array

+multi_array 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 +multi_array's lifetime, but the shape of the container can +be changed. A multi_array manages its data elements +using a replaceable allocator. +

Model Of.  +MultiArray, +CopyConstructible. Depending on the element type, +it may also model EqualityComparable and LessThanComparable. +

Synopsis. 

+
+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);
+};
+
+

Constructors. 

template <typename ExtentList>
+explicit multi_array(const ExtentList& sizes,
+                     const storage_order& store = c_storage_order(),
+                     const Allocator& alloc = Allocator());
+

+This constructs a multi_array using the specified +parameters. sizes specifies the shape of the +constructed multi_array. store +specifies the storage order or layout in memory of the array +dimensions. alloc is used to +allocate the contained elements. +

ExtentList Requirements.  +ExtentList must model Collection. +

Preconditions. sizes.size() == NumDims;

+
explicit multi_array(extent_gen::gen_type<NumDims>::type ranges,
+                     const storage_order& store = c_storage_order(),
+                     const Allocator& alloc = Allocator());
+

+This constructs a multi_array using the specified + parameters. ranges specifies the shape and +index bases of the constructed multi_array. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. alloc is the allocator used to +allocate the memory used to store multi_array +elements. +

+multi_array(const multi_array& x);
+

This constructs a multi_array and performs a deep +copy of x. +

Complexity.  This performs O(x.num_elements()) calls to +element's copy +constructor. +

Note on Constructors.  +The multi_array construction expressions, +

+     multi_array<int,3> A(boost::extents[5][4][3]);
+
+and +
+     boost::array<multi_array_base::index,3> my_extents = {{5, 4, 3}};
+     multi_array<int,3> A(my_extents);
+
+are equivalent. +

Modifiers. 

+multi_array& operator=(const multi_array& x);
+template <class Array> multi_array& operator=(const Array& x);
+
+

This performs an element-wise copy of x +into the current multi_array.

Array Requirements. Array must model MultiArray. +

Preconditions.  +

std::equal(this->shape(),this->shape()+this->num_dimensions(),
+x.shape());

Postconditions.  +

(*.this) == x;
+

Complexity. The assignment operators perform +O(x.num_elements()) calls to element's +copy constructor.

+
+
+template <typename InputIterator>
+void assign(InputIterator begin, InputIterator end);
+
+

This copies the elements in the range +[begin,end) into the array. It is equivalent to +std::copy(begin,end,this->data()). +

Preconditions. std::distance(begin,end) == this->num_elements(); +

Complexity.  +The assign member function performs +O(this->num_elements()) calls to +ValueType's copy constructor. +

multi_array_ref

+multi_array_ref is a multi-dimensional container +adaptor. It provides the MultiArray interface over any contiguous +block of elements. multi_array_ref exports the +same interface as multi_array, with the exception +of the constructors. +

Model Of.  +multi_array_ref models +MultiArray, +CopyConstructible. +and depending on the element type, it may also model +EqualityComparable and LessThanComparable. +Detailed descriptions are provided here only for operations that are +not described in the multi_array reference. +

Synopsis. 

+
+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);
+};
+
+

Constructors. 

template <typename ExtentList>
+explicit multi_array_ref(element* data, 
+                     const ExtentList& sizes,
+                     const storage_order& store = c_storage_order(),
+                     const Allocator& alloc = Allocator());
+

+This constructs a multi_array_ref using the specified +parameters. sizes specifies the shape of the +constructed multi_array_ref. store +specifies the storage order or layout in memory of the array +dimensions. alloc is used to +allocate the contained elements. +

ExtentList Requirements.  +ExtentList must model Collection. +

Preconditions. sizes.size() == NumDims;

+
explicit multi_array_ref(element* data,
+                     extent_gen::gen_type<NumDims>::type ranges,
+                     const storage_order& store = c_storage_order());
+

+This constructs a multi_array_ref using the specified + parameters. ranges specifies the shape and +index bases of the constructed multi_array_ref. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. +

+multi_array_ref(const multi_array_ref& x);
+

This constructs a shallow copy of x. +

Complexity.  Constant time (for contrast, compare this to +the multi_array class copy constructor. +

Modifiers. 

+multi_array_ref& operator=(const multi_array_ref& x);
+template <class Array> multi_array_ref& operator=(const Array& x);
+
+

This performs an element-wise copy of x +into the current multi_array_ref.

Array Requirements. Array must model MultiArray. +

Preconditions.  +

std::equal(this->shape(),this->shape()+this->num_dimensions(),
+x.shape());

Postconditions.  +

(*.this) == x;
+

Complexity. The assignment operators perform +O(x.num_elements()) calls to element's +copy constructor.

const_multi_array_ref

+const_multi_array_ref is a multi-dimensional container +adaptor. It provides the MultiArray interface over any contiguous +block of elements. const_multi_array_ref exports the +same interface as multi_array, with the exception +of the constructors. +

Model Of.  +const_multi_array_ref models +MultiArray, +CopyConstructible. +and depending on the element type, it may also model +EqualityComparable and LessThanComparable. + +Detailed descriptions are provided here only for operations that are +not described in the multi_array reference. +

Synopsis. 

+
+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);
+};
+
+

Constructors. 

template <typename ExtentList>
+explicit const_multi_array_ref(const element* data, 
+                     const ExtentList& sizes,
+                     const storage_order& store = c_storage_order());
+

+This constructs a const_multi_array_ref using the specified +parameters. sizes specifies the shape of the +constructed const_multi_array_ref. store +specifies the storage order or layout in memory of the array +dimensions. +

ExtentList Requirements.  +ExtentList must model Collection. +

Preconditions. sizes.size() == NumDims;

+
explicit const_multi_array_ref(const element* data,
+                     extent_gen::gen_type<NumDims>::type ranges,
+                     const storage_order& store = c_storage_order());
+

Effects.  +This constructs a const_multi_array_ref using the specified + parameters. ranges specifies the shape and +index bases of the constructed const_multi_array_ref. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. +

+const_multi_array_ref(const const_multi_array_ref& x);
+

Effects. This constructs a shallow copy of x. +

Auxiliary Components

multi_array_types

+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;
+}
+

Namespace multi_array_types defines types +associated with multi_array, +multi_array_ref, and +const_multi_array_ref 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 extent_gen and +extent_range, these types fulfill the roles of the +same name required by MultiArray and are described in its +concept definition. extent_gen and +extent_range are described below. +

extent_range

extent_range objects define half open +intervals. They provide shape and index base information to +multi_array, multi_array_ref, + and const_multi_array_ref constructors. +extent_ranges are passed in +aggregate to an array constructor (see +extent_gen for more details). +

Synopsis. 

+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();
+};

Model Of. DefaultConstructible,CopyConstructible

Methods and Types. 

extent_range(index start, index finish)

This constructor defines the half open interval +[start,finish). The expression +finish must be greater than start. +

extent_range(index finish)

This constructor defines the half open interval +[0,finish). The value of finish +must be positive.

index start()

This function returns the first index represented by the range

index finish()

This function returns the upper boundary value of the half-open +interval. Note that the range does not include this value.

size_type size()

This function returns the size of the specified range. It is +equivalent to finish()-start().

extent_gen

The extent_gen class defines an +interface for aggregating array shape and indexing information to be +passed to a multi_array, +multi_array_ref, or const_multi_array_ref +constructor. Its interface mimics + the syntax used to declare built-in array types +in C++. For example, while a 3-dimensional array of +int values in C++ would be +declared as: +

int A[3][4][5],
+a similar multi_array would be declared: +
multi_array<int,3> A(extents[3][4][5]).
+

Synopsis. 

+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;
+

Methods and Types. 

template gen_type::<Ranges>::type

This type generator is used to specify the result of +Ranges chained calls to +extent_gen::operator[]. The types +extent_gen and +gen_type<0>::type are the same.

gen_type<NumRanges+1>::type +operator[](const extent_range& a_range) const;

This function returns a new object containing all previous +extent_range objects in addition to +a_range. extent_range +objects are aggregated by chained calls to +operator[].

gen_type<NumRanges+1>::type +operator[](index idx) const;

This function returns a new object containing all previous +extent_range objects in addition to +extent_range(0,idx). This function gives the array +constructors a similar syntax to traditional C multidimensional array +declaration.

Global Objects

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. +

Under some circumstances, the two global objects may be +considered excessive overhead. Their construction can be prevented by +defining the preprocessor symbol +BOOST_MULTI_ARRAY_NO_GENERATORS before including +boost/multi_array.hpp.

extents

+namespace boost {
+  multi_array_base::extent_gen extents;
+}
+

Boost.MultiArray's array classes use the +extents global object to specify +array shape during their construction. +For example, +a 3 by 3 by 3 multi_array is constructed as follows: +

multi_array<int,3> A(extents[3][3][3]);
+The same array could also be created by explicitly declaring an extent_gen +object locally,, but the global object makes this declaration unnecessary. +

indices

+namespace boost {
+  multi_array_base::index_gen  indices;
+}
+

The MultiArray concept specifies an +index_gen associated type that is used to +create views. +indices is a global object that serves the role of +index_gen for all array components provided by this +library and their associated subarrays and views. +

For example, using the indices object, +a view of an array A is constructed as follows: +

+A[indices[index_range(0,5)][2][index_range(2,4)]];
+
+

View and SubArray Generators

+Boost.MultiArray provides traits classes, subarray_gen, +const_subarray_gen, +array_view_gen, +and const_array_view_gen, 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 array_view_gen +traits class and the array_view type associated to +an array: + +

+template <typename Array>
+void my_function() {
+  typedef typename Array::template array_view<3>::type view1_t;
+  typedef typename boost::array_view_gen<Array,3>::type view2_t;
+  // ...
+}
+
+ +In the above example, view1_t and +view2_t have the same type. +

Memory Layout Specifiers

+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. +

For example, consider the two dimensional array shown below in +matrix notation: + +

+ +Here is how the above array is expressed in C++: +

+int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+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: +
+int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+int s[] = { 4, 1 };
+
+ +With the latter declaration of a and +strides s, element a(i,j) +of the array can be +accessed using the expression +
*a+i*s[0]+j*s[1]
. +

The same two dimensional array could be laid out by column as follows: + +

+int a[] = { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11 };
+int s[] = { 3, 1 };
+
+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. +

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: + +

+int data[] = { 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 };
+int *a = data + 8;
+int s[] = { -4, 1 };
+
+ +Note that in this example a 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. +

+Alternatively, the second dimension, or the columns, could be reversed +and the rows stored in ascending order: + +

+int data[] = { 3, 2, 1, 0,  7, 6, 5, 4, 11, 10, 9, 8 };
+int *a = data + 3;
+int s[] = { 4, -1 };
+
+

+Finally, both dimensions could be stored in descending order: + +

+int data[] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+int *a = data + 11;
+int s[] = { -4, -1 };
+
+ + +

+All of the above arrays are equivalent. The expression +given above for a(i,j) 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 multi_array_ref or +const_multi_array_ref) 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. +

c_storage_order

+class c_storage_order {
+  c_storage_order();
+};
+

c_storage_order 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.

fortran_storage_order

+class fortran_storage_order {
+  fortran_storage_order();
+};
+

fortran_storage_order 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.

general_storage_order

+template <std::size_t NumDims> 
+class general_storage_order {
+
+  template <typename OrderingIter, typename AscendingIter>
+  general_storage_order(OrderingIter ordering, AscendingIter ascending);
+};
+

general_storage_order 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.

+OrderingIter and AscendingIter +must model the InputIterator concept. Both +iterators must refer to a range of NumDims +elements. AscendingIter points to objects +convertible to bool. A value of +true means that a dimension is stored in ascending +order while false means that a dimension is stored +in descending order. OrderingIter specifies the +order in which dimensions are stored. +

diff --git a/doc/test_cases.html b/doc/test_cases.html new file mode 100644 index 0000000..561a290 --- /dev/null +++ b/doc/test_cases.html @@ -0,0 +1,294 @@ + + + + + +Boost.MultiArray: Test Descriptions + + + +C++ Boost +

Boost.MultiArray: Test Descriptions

+ + The following is a description of the test cases that are included with + Boost.Multi_Array (B.M). + +

Terminology

+The following list is to clarify the use of terms in the following +descriptions: + + +

Acceptance Tests

+ + The following tests exercise various features of Boost.Multi_Array to + ensure proper operation at run time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProgramDescription
libs/multi_array/test/constructors.cpp +Exercises all of the constructors for B.M primary components. +
libs/multi_array/test/access.cpp +Tests operator[] and operator() on all B.M array types. +
libs/multi_array/test/compare.cpp +Tests all comparison operators for the B.M primary components. +
libs/multi_array/test/iterators.cpp +Test all iterator traversal and access functionality for all B.M array types. +
libs/multi_array/test/slice.cpp +Test all variations of subview generation for all B.M array types. +
libs/multi_array/test/assign.cpp +Tests out operator=() on the various B.M array types. +
libs/multi_array/test/index_bases.cpp +Test re-indexing functionality for the B.M primary components. +
libs/multi_array/test/storage_order.cpp +Test variations on storage_order for the B.M primary components. +
libs/multi_array/test/reshape.cpp +Test re-shaping functionality for the B.M primary components. +
libs/multi_array/test/range1.cpp +Test the various syntaxes for specifying index ranges using +array::index_range. +
libs/multi_array/test/idxgen1.cpp +Test the array::index_gen objects. +
libs/multi_array/test/stl_interaction.cpp +Test interaction between array types and STL containers. +
libs/multi_array/test/concept_checks.cpp +Ensure that all the array types meet the defined Concepts. +
libs/multi_array/test/generative_tests.hpp +A test harness used to simplify testing operations upon all array +types. Used by slice.cpp, iterators.cpp, and access.cpp. +
+ +

Compile-Fail Tests

+ + 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. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProgramDescription
libs/multi_array/test/fail_cbracket.cpp +
libs/multi_array/test/fail_ref_cbracket.cpp
+operator[] on a const array must not modify elements. +
libs/multi_array/test/fail_cdata.cpp +
libs/multi_array/test/fail_ref_cdata.cpp
+array::data() const must return a pointer to const data. +
libs/multi_array/test/fail_citerator.cpp +
libs/multi_array/test/fail_ref_citerator.cpp
+const_iterator must not be convertible to iterator. +
libs/multi_array/test/fail_cparen.cpp +
libs/multi_array/test/fail_ref_cparen.cpp
+operator() on a const array must not modify elements. +
libs/multi_array/test/fail_criterator.cpp +
libs/multi_array/test/fail_ref_criterator.cpp
+const_reverse_iterator must not be convertible to +reverse_iterator. +
libs/multi_array/test/fail_csubarray.cpp +
libs/multi_array/test/fail_ref_csubarray.cpp
+const_subarray must not be convertible to subarray. +
libs/multi_array/test/fail_csubarray2.cpp +
libs/multi_array/test/fail_ref_csubarray2.cpp
+array::operator[] const must not be convertible to subarray. +
libs/multi_array/test/fail_csubarray3.cpp +
libs/multi_array/test/fail_ref_csubarray3.cpp
+const_subarray into an array must not modify elements. +
libs/multi_array/test/fail_cview.cpp +
libs/multi_array/test/fail_ref_cview.cpp
+const_array_view of an array must not modify elements. +
libs/multi_array/test/fail_cview2.cpp +
libs/multi_array/test/fail_ref_cview2.cpp
+array::operator[] const must not be convertible to +array_view. +
libs/multi_array/test/fail_cview3.cpp +
libs/multi_array/test/fail_ref_cview3.cpp
+const_array_view of an array must not modify elements. +
+ +
+ + + + + +
Copyright © 2001Ronald Garcia, +Indiana University (garcia@cs.indiana.edu)
+Jeremy Siek, Indiana +University (jsiek@cs.indiana.edu)
+Andrew Lumsdaine, Indiana +University (lums@cs.indiana.edu)
+ +


+ +
+Ronald Garcia +
+ +Last modified: Wed Oct 31 19:46:44 EST 2001 + + + + + diff --git a/doc/user.html b/doc/user.html new file mode 100644 index 0000000..70da8b9 --- /dev/null +++ b/doc/user.html @@ -0,0 +1,624 @@ + + + + + + The Boost Multidimensional Array Library (Boost.MultiArray) + + + + +

+ boost logo +
The Boost Multidimensional Array Library +
(Boost.MultiArray) +

+ +

Synopsis

+ +

+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. + + +

Table of Contents

+ +
    +
  1. Rationale + +
  2. Related Work + +
  3. Short Example + +
  4. MultiArray Components + +
  5. Construction and Assignment + +
  6. Associated Types + +
  7. Array View and Subarray Type Generators + +
  8. Specifying Array Dimensions + +
  9. Accessing Elements + +
  10. Creating Views + +
  11. Storage Ordering + +
  12. Setting the Array Base + +
  13. Changing an Array's Shape + +
  14. MultiArray Concepts + +
  15. Test Cases +
+ + + +

Rationale

+ +The C++ standard library provides several generic containers, but +it does not provide any multidimensional array types. +Using std::vector, 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. int arr[2][2][2];), +or a dynamically allocated array of contigous data which you treat as +a multidimensional array. Using +array_traits, + 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 std::vector nor C++ array-based +solution provides a convenient method of honing in upon a specific +subset or "view" of a multi-dimensional array. + +

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. + + + +

Related Work

+ +boost::array + and std::vector are + one-dimensional containers of user data. Both manage their own + memory. std::valarray is a low-level + C++ Standard Library component + meant to provide portable high performance for numerical applications. +Blitz++ is + an array library developed by Todd + Veldhuizen. It uses + advanced C++ techniques to provide near-Fortran performance for + array-based numerical applications. +array_traits is a beta + library distributed with Boost that provides a means to create + iterators over native C++ arrays. + + +This library is analogous to +boost::array in that it augments C style N-dimensional +arrays, as boost::array does for C one-dimensional arrays. + + + +

Short Example

+What follows is a brief example of the use of multi_array: + +
+
+#include "boost/multi_array.hpp"
+#include <cassert>
+
+int 
+main () {
+  // Create a 3D array that is 3 x 4 x 2
+  typedef boost::multi_array<double, 3> 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;
+}
+
+
+ + +

MultiArray Components

+ +Boost.MultiArray provides three user-level class templates: + +
    +
  1. multi_array - + defined in "boost/multi_array.hpp", + +
  2. multi_array_ref - + defined in "boost/multi_array_ref.hpp", and + +
  3. const_multi_array_ref - + defined in "boost/multi_array_ref.hpp" +
+ +multi_array is a container template. When instantiated, it +allocates space for the number of elements corresponding to the +dimensions specified at construction time. + +

+multi_array_ref adapts an existing array of data to provide +the multi_array interface. multi_array_ref does not own the +data passed to it. + +

+const_multi_array_ref is similar to multi_array_ref +but guarantees that the contents of the array are immutable. It can +thus wrap pointers of type T const*. + +

+The three components exhibit very similar behavior. Aside from +constructor parameters, multi_array and +multi_array_ref export the same interface. +const_multi_array_ref provides only the const portions +of the multi_array_ref interface. + + +

Construction and Assignment

+

Each of the array types - +multi_array, +multi_array_ref, and +const_multi_array_ref - +provides a specialized set of constructors. For further information, +consult their reference pages. + +

All of the non-const array types in this library provide assignment +operatorsoperator=(). Each of the array types multi_array, + multi_array_ref, subarray, and + array_view can be assigned from any +of the others, so long as their shapes match. The + const variants, const_multi_array_ref, +const_subarray, and const_array_view, 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. + + +

Array View and Subarray Type Generators

+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, subarray_gen, +const_subarray_gen, array_view_gen, and +const_array_view_gen are provided. Thus, the two typedefs +in the following example result in the same type: +
+
+template <typename Array>
+void my_function() {
+  typedef typename Array::template array_view<3>::type view1_t;
+  typedef typename boost::array_view_gen<Array,3>::type view2_t;
+  // ...
+}
+
+
+ + +

Specifying Array Dimensions

+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. +

The first method involves passing a + +Collection of extents to a +constructor, most commonly a boost::array. 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. +

Example

+
+
+  typedef boost::multi_array<double, 3> array_type;
+  boost::array<array_type::index, 3> shape = {{ 3, 4, 2 }};
+  array_type A(shape);
+
+
+ +

The second method involves passing the constructor an extent_gen +object, specifying the matrix dimensions. By default, the library constructs a +global extent_gen object boost::extents. In case of +concern about memory used by these objects, defining +BOOST_MULTI_ARRAY_NO_GENERATORS before including the library +header inhibits its construction. + +

Example

+
+
+  typedef boost::multi_array<double, 3> array_type;
+  array_type A(boost::extents[3][4][2]);
+
+
+ + +

Accessing Elements

+The Boost.MultiArray components provide two ways of accessing +specific elements within a container. The first uses the traditional +C array notation, provided by operator[]. +

Example

+
+
+  typedef boost::multi_array<double, 3> array_type;
+  array_type A(boost::extents[3][4][2]);
+  A[0][0][0] = 3.14;
+  assert(A[0][0][0] == 3.14);
+
+
+ +

The second method involves passing a + +Collection of indices to operator(). N indices will be retrieved +from the Collection for the N dimensions of the container. +

Example

+
+
+  typedef boost::multi_array<double, 3> array_type;
+  array_type A(boost::extents[3][4][2]);
+  boost::array<array_type::index,3> idx = {{0,0,0}};
+  A(idx) = 3.14;
+  assert(A(idx) == 3.14);
+
+
+This can be useful for writing dimension-independent code, and under +some compilers may yield higher performance than operator[]. + + +

Creating Views

+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. + +

Sub-view creation occurs by placing a call to operator[], passing it +an index_gen type. The index_gen is populated by +passing index_range objects to its operator[]. +Similar to boost::extents, the library by default constructs +the object boost::indices. You can suppress this object +by defining BOOST_MULTI_ARRAY_NO_GENERATORS before +including the library header. A simple sub-view creation example follows. +

Example

+
+
+  // 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<3>::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]);
+
+
+ + +

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). +

Example

+
+
+  // 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<2>::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]);
+
+
+ +

More on index_range

+The index_range type provides several methods of specifying +ranges for subview generation. Here are a few range instantiations +that specify the same range. +

Example

+
+
+  // [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 <= range().stride(2) < 4;
+  a_range = 0 <= range().stride(2) <= 3;
+
+
+ +An index_range 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. + +

Example

+
+
+  typedef array_type::index_range range;
+  range a_range;
+
+  // All elements in this dimension
+  a_range = range(); 
+
+  // indices i where 3 <= i
+  a_range = range().start(3) 
+  a_range = 3 <= range();
+  a_range = 2 < range();
+
+  // indices i where i < 7
+  a_range = range().finish(7)
+  a_range = range() < 7;
+  a_range = range() <= 6;
+
+
+ +The following example slicing operations exhibit some of the +alternatives shown above +
+
+    // take all of dimension 1
+    // take i < 5 for dimension 2
+    // take 4 <= j <= 7 for dimension 3 with stride 2
+    myarray[ boost::indices[range()][range() < 5 ][4 <= range().stride(2) <= 7] ];
+
+
+ + +

Storage Ordering

+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 +c_storage_order, fortran_storage_order, and +general_storage_order. + +

c_storage_order, 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. + +

fortran_storage_order 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. +

Example

+
+
+  typedef boost::multi_array<double,3> array_type;
+  array_type A(boost::extents[3][4][2],boost::fortran_storage_order); 
+  call_fortran_function(A.data());
+
+
+ +

general_storage_order allows one to customize both the order in +which dimensions are stored in memory and whether dimensions are +stored in ascending or descending order. +

Example

+
+
+  typedef boost::general_storage_order<3> storage;
+  typedef boost::multi_array<int,3> 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)); 
+
+
+ + + +

Setting The Array Base

+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. +

Example

+
+
+  typedef boost::multi_array<double, 3> 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)]);
+
+
+ +

+An alternative is to first construct the array normally then +reset the bases. To set all bases to the same value, use the +reindex member function, passing it a single new index value. +

Example

+
+
+  typedef boost::multi_array<double, 3> 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)
+
+
+ +

+An alternative is to set each base separately using the +reindex member function, passing it a Collection of index bases. +

Example

+
+
+  typedef boost::multi_array<double, 3> 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<array_type::index,ndims> bases = {{0, 1, -1}};       
+  A.reindex(bases);
+
+
+ + + +

Changing an Array's Shape

+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. +

Example

+
+
+  typedef boost::multi_array<double, 3> array_type;
+  typedef array_type::extent_range range;
+
+  array_type::extent_gen extents;
+  array_type A(extents[2][3][4]);
+  boost::array<array_type::index,ndims> dims = {{4, 3, 2}};       
+  A.reshape(dims);
+
+
+ +

+Note that reshaping an array does not affect the indexing. + + +

MultiArray Concepts

+Boost.MultiArray defines and uses several concepts throughout: + + + +

Test Cases

+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 here. + +

Credits

+ + +
+ +
+Ronald Garcia +
+ + +Last modified: Mon May 6 14:48:18 EST 2002 + + + + diff --git a/doc/xml/MultiArray.xml b/doc/xml/MultiArray.xml new file mode 100644 index 0000000..d525261 --- /dev/null +++ b/doc/xml/MultiArray.xml @@ -0,0 +1,1002 @@ +MultiArray Concept + + +The MultiArray +concept defines an interface to hierarchically nested +containers. It specifies operations for accessing elements, +traversing containers, and creating views +of array data. +MultiArray defines +a flexible memory model that accomodates +a variety of data layouts. + + + +At each level (or dimension) of a MultiArray's +container hierarchy lie a set of ordered containers, each of which +contains the same number and type of values. The depth of this +container hierarchy is the MultiArray's dimensionality. +MultiArray is recursively defined; the +containers at each level of the container hierarchy model +MultiArray as well. While each dimension of a MultiArray +has its own size, the list of sizes for all dimensions +defines the shape of the entire MultiArray. +At the base of this hierarchy lie 1-dimensional +MultiArrays. Their values are the contained +objects of interest and not part of the container hierarchy. These are +the MultiArray's elements. + + + + +Like other container concepts, MultiArray exports +iterators to traverse its values. In addition, values can be +addressed directly using the familiar bracket notation. + + + +MultiArray also specifies +routines for creating +specialized views. A view lets you treat a +subset of the underlying +elements in a MultiArray as though it were a separate +MultiArray. Since a view refers to the same underlying elements, +changes made to a view's elements will be reflected in the original +MultiArray. For +example, given a 3-dimensional "cube" of elements, a 2-dimensional +slice can be viewed as if it were an independent +MultiArray. + +Views are created using index_gen and +index_range objects. +index_ranges denote elements from a certain +dimension that are to be included in a +view. index_gen aggregates range data and performs +bookkeeping to determine the view type to be returned. + +MultiArray's operator[] + must be passed the result +of N chained calls to +index_gen::operator[], i.e. + +indices[a0][a1]...[aN]; + + +where N is the +MultiArray's dimensionality and +indices an object of type index_gen. + +The view type is dependent upon the number of degenerate dimensions +specified to index_gen. A degenerate dimension +occurs when a single-index is specified to +index_gen for a certain dimension. For example, if +indices is an object of type +index_gen, then the following example: + +indices[index_range(0,5)][2][index_range(0,4)]; + + +has a degenerate second dimension. The view generated from the above +specification will have 2 dimensions with shape 5 x 2. +If the "2" above were replaced with +another index_range object, for example: + +indices[index_range(0,5)][index_range(0,2)][index_range(0,4)]; + + +then the view would have 3 dimensions. + + +MultiArray exports +information regarding the memory +layout of its contained elements. Its memory model for elements is +completely defined by 4 properties: the origin, shape, index bases, +and strides. The origin is the address in memory of the element +accessed as a[0][0]...[0], where +a is a MultiArray. The shape is a list of numbers +specifying the size of containers at each dimension. For example, the +first extent is the size of the outermost container, the second extent +is the size of its subcontainers, and so on. The index bases are a +list of signed values specifying the index of the first value in a +container. All containers at the same dimension share the same index +base. Note that since positive index bases are +possible, the origin need not exist in order to determine the location +in memory of the MultiArray's elements. + The strides determine how index values are mapped to memory offsets. +They accomodate a +number of possible element layouts. For example, the elements of a 2 +dimensional array can be stored by row (i.e., the elements of each row +are stored contiguously) or by column (i.e., the elements of each +column are stored contiguously). + + + +Notation +What follows are the descriptions of symbols that will be used +to describe the MultiArray interface. + + Notation + + + + A + A type that is a model of MultiArray + + + + a + An object of type A + + + NumDims + The numeric dimension parameter associated with +A. + + + Dims + Some numeric dimension parameter such that +0<Dims<NumDims. + + + + indices + An object created by some number of chained calls +to index_gen::operator[](index_range). + + + index_list + An object whose type models +Collection + + + + idx + A signed integral value. + + + tmp + An object of type + boost::array<index,NumDims> + + + +
+
+ +Associated Types + + +Associated Types + + + + +Type +Description + + + + + + +value_type + +This is the value type of the container. + If NumDims == 1, then this is +element. Otherwise, this is the value type of the +immediately nested containers. + + + + + +reference + + + +This is the reference type of the contained value. +If NumDims == 1, then this is +element&. Otherwise, this is the same type as +template subarray<NumDims-1>::type. + + + + + +const_reference + + +This is the const reference type of the contained value. +If NumDims == 1, then this is +const element&. Otherwise, this is the same +type as +template const_subarray<NumDims-1>::type. + + + + + +size_type + + +This is an unsigned integral type. It is primarily used to specify array shape. + + + + + + +difference_type + + +This is a signed integral type used to represent the distance between two +iterators. It is the same type as +std::iterator_traits<iterator>::difference_type. + + + + +iterator + +This is an iterator over the values of A. +If NumDims == 1, then it models + +Random Access Iterator. +Otherwise it models + +Random Access Traversal Iterator, + +Readable Iterator, and + +Writable Iterator. + + + + + +const_iterator + + +This is the const iterator over the values of A. + + + + + +reverse_iterator + + +This is the reversed iterator, used to iterate backwards over the values of +A. + + + + + +const_reverse_iterator + + +This is the reversed const iterator. +A. + + + + + +element + + +This is the type of objects stored at the base of the +hierarchy of MultiArrays. It is the same as +template subarray<1>::value_type + + + + + +index + + +This is a signed integral type used for indexing into A. It +is also used to represent strides and index bases. + + + + + +index_gen + + +This type is used to create a tuple of index_ranges +passed to operator[] to create +an array_view<Dims>::type object. + + + + + +index_range + + +This type specifies a range of indices over some dimension of a +MultiArray. This range will be visible through an +array_view<Dims>::type object. + + + + + +template subarray<Dims>::type + + +This is subarray type with Dims dimensions. +It is the reference type of the (NumDims - Dims) +dimension of A and also models +MultiArray. + + + + + +template const_subarray<Dims>::type + + +This is the const subarray type. + + + + + +template array_view<Dims>::type + + +This is the view type with Dims dimensions. It is +returned by calling operator[](indices). +It models MultiArray. + + + + + +template +const_array_view<Dims>::type + + +This is the const view type with Dims dimensions. + + + + + +
+ +
+ + + Valid expressions + + Valid Expressions + + + + Expression + Return type + Semantics + + + + + a.shape() + const size_type* + +This returns a list of NumDims elements specifying the +extent of each array dimension. + + + + + a.strides() + const index* + +This returns a list of NumDims elements specifying the +stride associated with each array dimension. When accessing values, +strides is used to calculate an element's location in memory. + + + + + a.index_bases() + const index* + +This returns a list of NumDims elements specifying the +numeric index of the first element for each array dimension. + + + + a.origin() + +element* if a is mutable, +const element* otherwise. + + +This returns the address of the element accessed by the expression +a[0][0]...[0].. If the index bases are positive, +this element won't exist, but the address can still be used to locate +a valid element given its indices. + + + + a.num_dimensions() + size_type + This returns the number of dimensions of the array +(note that a.num_dimensions() == NumDims). + + + + a.num_elements() + size_type + This returns the number of elements contained +in the array. It is equivalent to the following code: + +std::accumulate(a.shape(),a.shape+a.num_dimensions(), + size_type(1),std::multiplies<size_type>()); + + + + + + a.size() + size_type + +This returns the number of values contained in +a. It is equivalent to a.shape()[0]; + + + + a(index_list) + +element&; if a is mutable, +const element& otherwise. + + +This expression accesses a specific element of +a.index_list is the unique set +of indices that address the element returned. It is +equivalent to the following code (disregarding intermediate temporaries): + + // multiply indices by strides + std::transform(index_list.begin(), index_list.end(), + a.strides(), tmp.begin(), std::multiplies<index>()), + + // add the sum of the products to the origin + *std::accumulate(tmp.begin(), tmp.end(), a.origin()); + + + + + + a.begin() + +iterator if a is mutable, +const_iterator otherwise. + + This returns an iterator pointing to the beginning of +a. + + + + a.end() + +iterator if a is mutable, +const_iterator otherwise. + + This returns an iterator pointing to the end of +a. + + + + a.rbegin() + +reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + + This returns a reverse iterator pointing to the +beginning of a reversed. + + + + + a.rend() + +reverse_iterator if a is mutable, +const_reverse_iterator otherwise. + + +This returns a reverse iterator pointing to the end of a +reversed. + + + + a[idx] + +reference if a is mutable, +const_reference otherwise. + + +This returns a reference type that is bound to the index +idx value of a. Note that if +i is the index base for this dimension, the above +expression returns the (idx-i)th element (counting +from zero). The expression is equivalent to +*(a.begin()+idx-a.index_bases()[0]);. + + + + + a[indices] + +array_view<Dims>::type if +a is mutable, +const_array_view<Dims>::type otherwise. + + +This expression generates a view of the array determined by the +index_range and index values + used to construct indices. + + + + a == b + bool + This performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable for this +expression to be valid. + + + a < b + bool + This performs a lexicographical comparison of the +values of a and b. The element +type must model LessThanComparable for this +expression to be valid. + + + a <= b + bool + This performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable and +LessThanComparable for this +expression to be valid. + + + a > b + bool + This performs a lexicographical comparison of the +values of a and b. The element +type must model EqualityComparable and +LessThanComparable for this +expression to be valid. + + + a >= b + bool + This performs a lexicographical comparison of the +values of a and b. The element +type must model LessThanComparable for this +expression to be valid. + + + +
+
+ + +Complexity guarantees + +begin() and end() execute in amortized +constant time. +size() executes in at most linear time in the +MultiArray's size. + + + +Invariants +Invariants + + + + Valid range + [a.begin(),a.end()) is a valid range. + + + + + Range size + +a.size() == std::distance(a.begin(),a.end());. + + + + + Completeness + +Iteration through the range +[a.begin(),a.end()) will traverse across every +value_type of a. + + + + Accessor Equivalence + +Calling a[a1][a2]...[aN] where N==NumDims +yields the same result as calling +a(index_list), where index_list +is a Collection containing the values a1...aN. + + + + +
+
+ + + Associated Types for Views + The following MultiArray associated +types define the interface for creating views of existing +MultiArrays. Their interfaces and roles in the +concept are described below. + + + <literal>index_range</literal> + + index_range objects represent half-open +strided intervals. They are aggregated (using an +index_gen object) and passed to +a MultiArray's operator[] +to create an array view. When creating a view, +each index_range denotes a range of +valid indices along one dimension of a MultiArray. +Elements that are accessed through the set of ranges specified will be +included in the constructed view. In some cases, an +index_range is created without specifying start +or finish values. In those cases, the object is interpreted to +start at the beginning of a MultiArray dimension +and end at its end. + + +index_range objects can be constructed and modified +several ways in order to allow convenient and clear expression of a +range of indices. To specify ranges, index_range +supports a set of constructors, mutating member functions, and a novel +specification involving inequality operators. Using inequality +operators, a half open range [5,10) can be specified as follows: +5 <= range() < 10; or +4 < range() <= 9; and so on. + +The following describes the +index_range interface. + + + + Notation + + + + i + An object of type index_range. + + + idx,idx1,idx2,idx3 + Objects of type index. + + + +
+ + Associated Types + + + + Type + Description + + + + + index + This is a signed integral type. It is used to +specify the start, finish, and stride values. + + + size_type + This is an unsigned integral type. It is used to +report the size of the range an index_range +represents. + + + +
+ + + Valid Expressions + + + + Expression + Return type + Semantics + + + + + index_range(idx1,idx2,idx3) + index_range + This constructs an index_range + representing the interval [idx1,idx2) + with stride idx3. + + + index_range(idx1,idx2) + index_range + This constructs an index_range + representing the interval [idx1,idx2) + with unit stride. It is equivalent to + index_range(idx1,idx2,1). + + + index_range() + index_range + This construct an index_range +with unspecified start and finish values. + + + i.start(idx1) + index& + This sets the start index of i to + idx. + + + i.finish(idx) + index& + This sets the finish index of i to + idx. + + + i.stride(idx) + index& + This sets the stride length of i to + idx. + + + i.start() + index + This returns the start index of i. + + + i.finish() + index + This returns the finish index of i. + + + i.stride() + index + This returns the stride length of i. + + + i.get_start(idx) + index + If i specifies a start +value, this is equivalent to i.start(). Otherwise it +returns idx. + + + i.get_finish(idx) + index + If i specifies a finish +value, this is equivalent to i.finish(). Otherwise it +returns idx. + + + i.size(idx) + size_type + If i specifies a both finish and +start values, this is equivalent to +(i.finish()-i.start())/i.stride(). Otherwise it +returns idx. + + + i < idx + index + This is another syntax for specifying the finish +value. This notation does not include +idx in the range of valid indices. It is equivalent to +index_range(r.start(), idx, r.stride()) + + + i <= idx + index + This is another syntax for specifying the finish +value. This notation includes +idx in the range of valid indices. It is equivalent to +index_range(r.start(), idx + 1, r.stride()) + + + idx < i + index + This is another syntax for specifying the start +value. This notation does not include +idx in the range of valid indices. It is equivalent to +index_range(idx + 1, i.finish(), i.stride()). + + + idx <= i + index + This is another syntax for specifying the start +value. This notation includes +idx1 in the range of valid indices. It is equivalent to +index_range(idx, i.finish(), i.stride()). + + + i + idx + index + This expression shifts the start and finish values +of i up by idx. It is equivalent to +index_range(r.start()+idx1, r.finish()+idx, r.stride()) + + + i - idx + index + This expression shifts the start and finish values +of i up by idx. It is equivalent to +index_range(r.start()-idx1, r.finish()-idx, r.stride()) + + + +
+
+ + + <literal>index_gen</literal> + index_gen aggregates +index_range objects in order to specify view +parameters. Chained calls to operator[] store +range and dimension information used to +instantiate a new view into a MultiArray. + + + Notation + + + + Dims,Ranges + Unsigned integral values. + + + x + An object of type +template gen_type<Dims,Ranges>::type. + + + i + An object of type +index_range. + + + idx + Objects of type index. + + + +
+ + Associated Types + + + + Type + Description + + + + + index + This is a signed integral type. It is used to +specify degenerate dimensions. + + + size_type + This is an unsigned integral type. It is used to +report the size of the range an index_range +represents. + + + +template gen_type::<Dims,Ranges>::type + This type generator names the result of +Dims chained calls to +index_gen::operator[]. The +Ranges parameter is determined by the number of +degenerate ranges specified (i.e. calls to +operator[](index)). Note that +index_gen and +gen_type<0,0>::type are the same type. + + + +
+ + + + + Valid Expressions + + + + Expression + Return type + Semantics + + + + + index_gen() + gen_type<0,0>::type + This constructs an index_gen +object. This object can then be used to generate tuples of +index_range values. + + + + x[i] + gen_type<Dims+1,Ranges+1>::type + + Returns a new object containing all previous +index_range objects in addition to +i. Chained calls to +operator[] are the means by which +index_range objects are aggregated. + + + x[idx] + gen_type<Dims,Ranges>::type + + Returns a new object containing all previous +index_range objects in addition to a degenerate +range, index_range(idx,idx). Note that this is NOT +equivalent to x[index_range(idx,idx)]., which will +return an object of type +gen_type<Dims+1,Ranges+1>::type. + + + + +
+
+ +
+ + +Models + + + multi_array + multi_array_ref + const_multi_array_ref + + template array_view<Dims>::type + + + template const_array_view<Dims>::type + + + template subarray<Dims>::type + + + template const_subarray<Dims>::type + + + + +
diff --git a/doc/xml/const_multi_array_ref.xml b/doc/xml/const_multi_array_ref.xml new file mode 100644 index 0000000..149e90b --- /dev/null +++ b/doc/xml/const_multi_array_ref.xml @@ -0,0 +1,188 @@ + +<literal>const_multi_array_ref</literal> + + +const_multi_array_ref is a multi-dimensional container +adaptor. It provides the MultiArray interface over any contiguous +block of elements. const_multi_array_ref exports the +same interface as multi_array, with the exception +of the constructors. + + + + + Model Of. + +const_multi_array_ref models +MultiArray, +CopyConstructible. +and depending on the element type, it may also model +EqualityComparable and LessThanComparable. + +Detailed descriptions are provided here only for operations that are +not described in the multi_array reference. + + + + +Synopsis + + + > +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 struct subarray; + template struct const_subarray; + template struct array_view; + template struct const_array_view; + + + // structors + + template + 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 + const element& operator()(const IndexList& indices) const; + const_reference operator[](index i) const; + const_array_view::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 + void reshape(const SizeList& sizes) + template void reindex(const BaseList& values); + void reindex(index value); +}; +]]> + + + + +Constructors + + + +template <typename ExtentList> +explicit const_multi_array_ref(const element* data, + const ExtentList& sizes, + const storage_order& store = c_storage_order()); + + + + +This constructs a const_multi_array_ref using the specified +parameters. sizes specifies the shape of the +constructed const_multi_array_ref. store +specifies the storage order or layout in memory of the array +dimensions. + + +<literal>ExtentList</literal> Requirements + +ExtentList must model Collection. + + + +Preconditions +sizes.size() == NumDims; + + + + + + + +::type ranges, + const storage_order& store = c_storage_order());]]> + + +Effects + +This constructs a const_multi_array_ref using the specified + parameters. ranges specifies the shape and +index bases of the constructed const_multi_array_ref. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. + + + + + + + + + + + + +Effects + This constructs a shallow copy of x. + + + + + + + + + diff --git a/doc/xml/main.xml b/doc/xml/main.xml new file mode 100644 index 0000000..f4d8008 --- /dev/null +++ b/doc/xml/main.xml @@ -0,0 +1,71 @@ + + + +
+ + Class template <literal>multi_array</literal> + + GarciaRonald + + Indiana University + Open Systems Lab + + + BOOST + + 2002 + Ronald Garcia + + + blah blah legal blah blah + + + + 1 + 1/18/2002 + + Initial Revision. + + + + + + +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 diff --git a/doc/xml/multi_array.xml b/doc/xml/multi_array.xml new file mode 100644 index 0000000..385c01e --- /dev/null +++ b/doc/xml/multi_array.xml @@ -0,0 +1,299 @@ + +<literal>multi_array</literal> + + +multi_array 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 +multi_array's lifetime, but the shape of the container can +be changed. A multi_array manages its data elements +using a replaceable allocator. + + + + + Model Of. + +MultiArray, +CopyConstructible. Depending on the element type, +it may also model EqualityComparable and LessThanComparable. + + + + +Synopsis + + + > +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 struct subarray; + template struct const_subarray; + template struct array_view; + template struct const_array_view; + + + // constructors and destructors + + template + 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 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 + element& operator()(const IndexList& indices); + template + const element& operator()(const IndexList& indices) const; + reference operator[](index i); + const_reference operator[](index i) const; + array_view::type operator[](const indices_tuple& r); + const_array_view::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 + void assign(InputIterator begin, InputIterator end); + template + void reshape(const SizeList& sizes) + template void reindex(const BaseList& values); + void reindex(index value); +}; +]]> + + + + +Constructors + + + +template <typename ExtentList> +explicit multi_array(const ExtentList& sizes, + const storage_order& store = c_storage_order(), + const Allocator& alloc = Allocator()); + + + + +This constructs a multi_array using the specified +parameters. sizes specifies the shape of the +constructed multi_array. store +specifies the storage order or layout in memory of the array +dimensions. alloc is used to +allocate the contained elements. + + +<literal>ExtentList</literal> Requirements + +ExtentList must model Collection. + + + +Preconditions +sizes.size() == NumDims; + + + + + + + +::type ranges, + const storage_order& store = c_storage_order(), + const Allocator& alloc = Allocator());]]> + + + +This constructs a multi_array using the specified + parameters. ranges specifies the shape and +index bases of the constructed multi_array. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. alloc is the allocator used to +allocate the memory used to store multi_array +elements. + + + + + + + + + + +This constructs a multi_array and performs a deep +copy of x. + + + +Complexity + This performs O(x.num_elements()) calls to +element's copy +constructor. + + + + + + +Note on Constructors + +The multi_array construction expressions, + + multi_array<int,3> A(boost::extents[5][4][3]); + +and + + boost::array<multi_array_base::index,3> my_extents = {{5, 4, 3}}; + multi_array<int,3> A(my_extents); + +are equivalent. + + + + + +Modifiers + + + + + + multi_array& operator=(const Array& x);]]> + + + + +This performs an element-wise copy of x +into the current multi_array. + + +<literal>Array</literal> Requirements +Array must model MultiArray. + + + +Preconditions + +std::equal(this->shape(),this->shape()+this->num_dimensions(), +x.shape()); + + + +Postconditions + +(*.this) == x; + + + + +Complexity +The assignment operators perform +O(x.num_elements()) calls to element's +copy constructor. + + + + + + + +void assign(InputIterator begin, InputIterator end);]]> + + + + + This copies the elements in the range +[begin,end) into the array. It is equivalent to +std::copy(begin,end,this->data()). + + +Preconditions +std::distance(begin,end) == this->num_elements(); + + + + +Complexity + +The assign member function performs +O(this->num_elements()) calls to +ValueType's copy constructor. + + + + + + + diff --git a/doc/xml/multi_array_ref.xml b/doc/xml/multi_array_ref.xml new file mode 100644 index 0000000..2b6dcce --- /dev/null +++ b/doc/xml/multi_array_ref.xml @@ -0,0 +1,253 @@ + +<literal>multi_array_ref</literal> + + +multi_array_ref is a multi-dimensional container +adaptor. It provides the MultiArray interface over any contiguous +block of elements. multi_array_ref exports the +same interface as multi_array, with the exception +of the constructors. + + + + + Model Of. + +multi_array_ref models +MultiArray, +CopyConstructible. +and depending on the element type, it may also model +EqualityComparable and LessThanComparable. +Detailed descriptions are provided here only for operations that are +not described in the multi_array reference. + + + + +Synopsis + + + > +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 struct subarray; + template struct const_subarray; + template struct array_view; + template struct const_array_view; + + + // structors + + template + 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 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 + element& operator()(const IndexList& indices); + template + const element& operator()(const IndexList& indices) const; + reference operator[](index i); + const_reference operator[](index i) const; + array_view::type operator[](const indices_tuple& r); + const_array_view::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 + void assign(InputIterator begin, InputIterator end); + template + void reshape(const SizeList& sizes) + template void reindex(const BaseList& values); + void reindex(index value); +}; +]]> + + + + +Constructors + + + +template <typename ExtentList> +explicit multi_array_ref(element* data, + const ExtentList& sizes, + const storage_order& store = c_storage_order(), + const Allocator& alloc = Allocator()); + + + + +This constructs a multi_array_ref using the specified +parameters. sizes specifies the shape of the +constructed multi_array_ref. store +specifies the storage order or layout in memory of the array +dimensions. alloc is used to +allocate the contained elements. + + +<literal>ExtentList</literal> Requirements + +ExtentList must model Collection. + + + +Preconditions +sizes.size() == NumDims; + + + + + + + +::type ranges, + const storage_order& store = c_storage_order());]]> + + + +This constructs a multi_array_ref using the specified + parameters. ranges specifies the shape and +index bases of the constructed multi_array_ref. It is the result of +NumDims chained calls to + extent_gen::operator[]. store +specifies the storage order or layout in memory of the array +dimensions. + + + + + + + + + + +This constructs a shallow copy of x. + + + +Complexity + Constant time (for contrast, compare this to +the multi_array class copy constructor. + + + + + + + + + + +Modifiers + + + + + + multi_array_ref& operator=(const Array& x);]]> + + + + +This performs an element-wise copy of x +into the current multi_array_ref. + + +<literal>Array</literal> Requirements +Array must model MultiArray. + + + +Preconditions + +std::equal(this->shape(),this->shape()+this->num_dimensions(), +x.shape()); + + + + +Postconditions + +(*.this) == x; + + + + +Complexity +The assignment operators perform +O(x.num_elements()) calls to element's +copy constructor. + + + + + + diff --git a/doc/xml/reference.xml b/doc/xml/reference.xml new file mode 100644 index 0000000..af408cb --- /dev/null +++ b/doc/xml/reference.xml @@ -0,0 +1,786 @@ + + + + + +]> + +
+ + Boost.MultiArray Reference Manual + + GarciaRonald + + Indiana University + Open Systems Lab + + + BOOST + + 2002 + Ronald Garcia + + + + +Boost.MultiArray is composed of several components. +The MultiArray concept defines a generic interface to multidimensional +containers. +multi_array is a general purpose container class +that models MultiArray. multi_array_ref +and const_multi_array_ref are adapter +classes. Using them, +you can manipulate any block of contiguous data as though it were a +multi_array. +const_multi_array_ref differs from +multi_array_ref 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. + + +Library Synopsis + To use Boost.MultiArray, you must include the header +boost/multi_array.hpp in your source. This file +brings the following declarations into scope: + + > + class multi_array; + + template + class multi_array_ref; + + template + class const_multi_array_ref; + + multi_array_types::extent_gen extents; + multi_array_types::index_gen indices; + + template class subarray_gen; + template class const_subarray_gen; + template class array_view_gen; + template class const_array_view_gen; + + class c_storage_order; + class fortran_storage_order; + template class general_storage_order; + +}]]> + + + +&concepts; + + +Array Components + +Boost.MultiArray defines an array class, +multi_array, and two adapter classes, +multi_array_ref and +const_multi_array_ref. The three classes model +MultiArray and so they share a lot of functionality. +multi_array_ref differs from +multi_array in that the +multi_array manages its own memory, while +multi_array_ref is passed a block of memory that it +expects to be externally managed. +const_multi_array_ref differs from +multi_array_ref 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. + + + +Note: Preconditions, Effects, and Implementation + +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. + + + + +Queries + + + +element* data(); +const element* data() const; + +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 origin(). Note that +const_multi_array_ref only provides the const +version of this function. + + + + + +element* origin(); +const element* origin() const; + +This returns the origin element of the +multi_array. Note that +const_multi_array_ref only provides the const +version of this function. (Required by MultiArray) + + + + + +const index* index_bases(); + +This returns the index bases for the +multi_array. (Required by MultiArray) + + + + + +const index* strides(); + +This returns the strides for the +multi_array. (Required by MultiArray) + + + + + +const size_type* shape(); + +This returns the shape of the +multi_array. (Required by MultiArray) + + + + + + + + +Comparators + + +(const *array-type*& rhs); +bool operator>=(const *array-type*& rhs); +bool operator<=(const *array-type*& rhs);]]> + + +Each comparator executes a lexicographical compare over +the value types of the two arrays. +(Required by MultiArray) + + +Preconditions +element must support the +comparator corresponding to that called on +multi_array. + + + +Complexity +O(num_elements()). + + + + + + + + + +Modifiers + + + + + + + +void reshape(const SizeList& sizes) +]]> + + + + +This changes the shape of the multi_array. 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. + +<literal>SizeList</literal> Requirements +SizeList must model +Collection. + + +Preconditions + + +()) == this->num_elements(); +sizes.size() == NumDims;]]> + + + + +Postconditions + +std::equal(sizes.begin(),sizes.end(),this->shape) == true; + + + + + + + + + +void reindex(const BaseList& values); +]]> + + + +This changes the index bases of the multi_array to +correspond to the the values in values. + + +<literal>BaseList</literal> Requirements +BaseList must model +Collection. + + + +Preconditions +values.size() == NumDims; + + + + +Postconditions +std::equal(values.begin(),values.end(),this->index_bases()); + + + + + + + + + + + + +This changes the index bases of all dimensions of the +multi_array to value. + + +Postconditions + + +index_bases(),this->index_bases()+this->num_dimensions(), + std::bind_2nd(std::equal_to(),value)) == + this->num_dimensions(); +]]> + + + + + + + + + +&multi_array; +&multi_array_ref; +&const_multi_array_ref; + + + + + + Auxiliary Components + + +<literal>multi_array_types</literal> + + + + + +Namespace multi_array_types defines types +associated with multi_array, +multi_array_ref, and +const_multi_array_ref 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 extent_gen and +extent_range, these types fulfill the roles of the +same name required by MultiArray and are described in its +concept definition. extent_gen and +extent_range are described below. + + + + + + <classname>extent_range</classname> + +extent_range objects define half open +intervals. They provide shape and index base information to +multi_array, multi_array_ref, + and const_multi_array_ref constructors. +extent_ranges are passed in +aggregate to an array constructor (see +extent_gen for more details). + + + + Synopsis + + + + + Model Of + DefaultConstructible,CopyConstructible + + +Methods and Types + + +extent_range(index start, index finish) + + This constructor defines the half open interval +[start,finish). The expression +finish must be greater than start. + + + + +extent_range(index finish) + +This constructor defines the half open interval +[0,finish). The value of finish +must be positive. + + + +index start() + +This function returns the first index represented by the range + + + +index finish() + +This function returns the upper boundary value of the half-open +interval. Note that the range does not include this value. + + + + +size_type size() + +This function returns the size of the specified range. It is +equivalent to finish()-start(). + + + + + + + + + <classname>extent_gen</classname> + The extent_gen class defines an +interface for aggregating array shape and indexing information to be +passed to a multi_array, +multi_array_ref, or const_multi_array_ref +constructor. Its interface mimics + the syntax used to declare built-in array types +in C++. For example, while a 3-dimensional array of +int values in C++ would be +declared as: +int A[3][4][5], +a similar multi_array would be declared: +multi_array<int,3> A(extents[3][4][5]). + + +Synopsis + +class *implementation_defined* { +public: + typedef multi_array_types::index index; + typedef multi_array_types::size_type size_type; + + template class gen_type; + + gen_type::type operator[](const range& a_range) const; + gen_type::type operator[](index idx) const; +}; + +typedef *implementation_defined*<0> extent_gen; +]]> + + +Methods and Types + + +template gen_type::<Ranges>::type + +This type generator is used to specify the result of +Ranges chained calls to +extent_gen::operator[]. The types +extent_gen and +gen_type<0>::type are the same. + + + + +gen_type<NumRanges+1>::type +operator[](const extent_range& a_range) const; + +This function returns a new object containing all previous +extent_range objects in addition to +a_range. extent_range +objects are aggregated by chained calls to +operator[]. + + + + +gen_type<NumRanges+1>::type +operator[](index idx) const; + +This function returns a new object containing all previous +extent_range objects in addition to +extent_range(0,idx). This function gives the array +constructors a similar syntax to traditional C multidimensional array +declaration. + + + + + + + + + Global Objects + 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. + + + Under some circumstances, the two global objects may be +considered excessive overhead. Their construction can be prevented by +defining the preprocessor symbol +BOOST_MULTI_ARRAY_NO_GENERATORS before including +boost/multi_array.hpp. + + +<literal>extents</literal> + + + + + + Boost.MultiArray's array classes use the +extents global object to specify +array shape during their construction. +For example, +a 3 by 3 by 3 multi_array is constructed as follows: +multi_array<int,3> A(extents[3][3][3]); +The same array could also be created by explicitly declaring an extent_gen +object locally,, but the global object makes this declaration unnecessary. + + + + +<literal>indices</literal> + + + + + + The MultiArray concept specifies an +index_gen associated type that is used to +create views. +indices is a global object that serves the role of +index_gen for all array components provided by this +library and their associated subarrays and views. + +For example, using the indices object, +a view of an array A is constructed as follows: + +A[indices[index_range(0,5)][2][index_range(2,4)]]; + + + + + + +View and SubArray Generators + +Boost.MultiArray provides traits classes, subarray_gen, +const_subarray_gen, +array_view_gen, +and const_array_view_gen, 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 array_view_gen +traits class and the array_view type associated to +an array: + + +template <typename Array> +void my_function() { + typedef typename Array::template array_view<3>::type view1_t; + typedef typename boost::array_view_gen<Array,3>::type view2_t; + // ... +} + + +In the above example, view1_t and +view2_t have the same type. + + + + + +Memory Layout Specifiers + +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. + + +For example, consider the two dimensional array shown below in +matrix notation: + + + +Here is how the above array is expressed in C++: + +int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + +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: + +int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; +int s[] = { 4, 1 }; + + +With the latter declaration of a and +strides s, element a(i,j) +of the array can be +accessed using the expression +*a+i*s[0]+j*s[1]. + + +The same two dimensional array could be laid out by column as follows: + + +int a[] = { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11 }; +int s[] = { 3, 1 }; + +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. + + +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: + + +int data[] = { 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 }; +int *a = data + 8; +int s[] = { -4, 1 }; + + +Note that in this example a 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. + + + +Alternatively, the second dimension, or the columns, could be reversed +and the rows stored in ascending order: + + +int data[] = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8 }; +int *a = data + 3; +int s[] = { 4, -1 }; + + + + +Finally, both dimensions could be stored in descending order: + + +int data[] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; +int *a = data + 11; +int s[] = { -4, -1 }; + + + + + + +All of the above arrays are equivalent. The expression +given above for a(i,j) 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 multi_array_ref or +const_multi_array_ref) 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. + + + +<literal>c_storage_order</literal> + + + + +c_storage_order 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. + + + +<literal>fortran_storage_order</literal> + + + + +fortran_storage_order 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. + + + +<literal>general_storage_order</literal> + + +class general_storage_order { + + template + general_storage_order(OrderingIter ordering, AscendingIter ascending); +};]]> + + +general_storage_order 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. + + +OrderingIter and AscendingIter +must model the InputIterator concept. Both +iterators must refer to a range of NumDims +elements. AscendingIter points to objects +convertible to bool. A value of +true means that a dimension is stored in ascending +order while false means that a dimension is stored +in descending order. OrderingIter specifies the +order in which dimensions are stored. + + + + + + + +
diff --git a/example/basic1.cpp b/example/basic1.cpp new file mode 100644 index 0000000..262fc1a --- /dev/null +++ b/example/basic1.cpp @@ -0,0 +1,13 @@ +#include +#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 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; +} diff --git a/example/basic2.cpp b/example/basic2.cpp new file mode 100644 index 0000000..d48631e --- /dev/null +++ b/example/basic2.cpp @@ -0,0 +1,15 @@ + +#include +#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 shape = {{ 3, 4, 2 }}; + boost::multi_array 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; +} diff --git a/example/for_each.hpp b/example/for_each.hpp new file mode 100644 index 0000000..f63104c --- /dev/null +++ b/example/for_each.hpp @@ -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 +void for_each (const boost::type& type_dispatch, + Array A, Functor& xform) { + for_each(type_dispatch,A.begin(),A.end(),xform); +} + +template +void for_each (const boost::type&,Element& Val, Functor& xform) { + Val = xform(Val); +} + +template +void for_each (const boost::type& type_dispatch, + Iterator begin, Iterator end, + Functor& xform) { + while (begin != end) { + for_each(type_dispatch,*begin,xform); + ++begin; + } +} + + +template +void for_each (Array& A, Functor xform) { + // Dispatch to the proper function + for_each(boost::type(),A.begin(),A.end(),xform); +} + + +#endif // FOR_EACH_HPP diff --git a/example/foreach_test.cpp b/example/foreach_test.cpp new file mode 100644 index 0000000..13516b5 --- /dev/null +++ b/example/foreach_test.cpp @@ -0,0 +1,42 @@ +// foreach_test.cpp +// Let's see if this stuff works + +#include "boost/multi_array.hpp" +#include "for_each.hpp" +#include + +struct times_five { + double operator()(const int& val) { return val*5.0; } +}; + + +int main() { + + typedef boost::multi_array 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(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(std::cout,",")); + + std::cout << "\n"; +#endif + return 0; +} diff --git a/example/foreach_test2.cpp b/example/foreach_test2.cpp new file mode 100644 index 0000000..88d101e --- /dev/null +++ b/example/foreach_test2.cpp @@ -0,0 +1,40 @@ +#include "boost/multi_array.hpp" +#include "for_each.hpp" +#include + +struct times_five { + double operator()(const int& val) { return val*5.0; } +}; + + +int main() { + + typedef boost::multi_array 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(std::cout,",")); + + std::cout << "\n"; +#endif + + for_each(A,times_five()); + +#if 0 + std::copy(A.begin(),A.end(), + std::ostream_iterator(std::cout,",")); + + std::cout << "\n"; +#endif + return 0; +} diff --git a/example/op_paren.cpp b/example/op_paren.cpp new file mode 100644 index 0000000..51d75ba --- /dev/null +++ b/example/op_paren.cpp @@ -0,0 +1,17 @@ + +#include +#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 shape = {{ 3, 4, 2 }}; + boost::multi_array A(shape); + typedef boost::multi_array::index index; + // Assign a value to an element in the array + boost::array idx = {{ 0, 0, 0 }}; + A(idx) = 3.14; + assert(A(idx) == 3.14); + return boost::exit_success; +} diff --git a/example/print_array.cpp b/example/print_array.cpp new file mode 100644 index 0000000..f9f77d0 --- /dev/null +++ b/example/print_array.cpp @@ -0,0 +1,38 @@ + +#include +#include "boost/multi_array.hpp" +#include "boost/array.hpp" +#include "boost/cstdlib.hpp" + +template +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 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]] diff --git a/example/subview.cpp b/example/subview.cpp new file mode 100644 index 0000000..e5a1dca --- /dev/null +++ b/example/subview.cpp @@ -0,0 +1,41 @@ + +#include "boost/multi_array.hpp" +#include "boost/cstdlib.hpp" + +int +main() +{ + const int ndims=3; + typedef boost::multi_array 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::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; +} diff --git a/example/subview2.cpp b/example/subview2.cpp new file mode 100644 index 0000000..409ccc2 --- /dev/null +++ b/example/subview2.cpp @@ -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 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; +} diff --git a/include/boost/multi_array.hpp b/include/boost/multi_array.hpp new file mode 100644 index 0000000..af21011 --- /dev/null +++ b/include/boost/multi_array.hpp @@ -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 +#include +#include +#include +#include + +namespace boost { + +template +class multi_array : + public multi_array_ref +{ + typedef multi_array_ref 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + template + explicit multi_array(ExtentList const& extents) : + super_type((T*)initial_base_,extents) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + allocate_space(); + } + + template + explicit multi_array(ExtentList const& extents, + const general_storage_order& so) : + super_type((T*)initial_base_,extents,so) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + allocate_space(); + } + + template + explicit multi_array(ExtentList const& extents, + const general_storage_order& so, + Allocator const& alloc) : + super_type((T*)initial_base_,extents,so), allocator_(alloc) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + allocate_space(); + } + + + explicit multi_array(const detail::multi_array + ::extent_gen& ranges) : + super_type((T*)initial_base_,ranges) { + + allocate_space(); + } + + + explicit multi_array(const detail::multi_array + ::extent_gen& ranges, + const general_storage_order& so) : + super_type((T*)initial_base_,ranges,so) { + + allocate_space(); + } + + + explicit multi_array(const detail::multi_array + ::extent_gen& ranges, + const general_storage_order& 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 + multi_array(const detail::multi_array:: + const_sub_array& 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& 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 + 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_list; + typedef boost::array index_list; + + Allocator allocator_; + T* base_; + size_type allocated_elements_; + enum {initial_base_ = 0}; +}; + +} // namespace boost + +#endif // BOOST_MULTI_ARRAY_RG071801_HPP diff --git a/include/boost/multi_array/algorithm.hpp b/include/boost/multi_array/algorithm.hpp new file mode 100644 index 0000000..71e07e7 --- /dev/null +++ b/include/boost/multi_array/algorithm.hpp @@ -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 +OutputIter copy_n(InputIter first, Size count, + OutputIter result) { + for ( ; count > 0; --count) { + *result = *first; + ++first; + ++result; + } + return result; +} +#else // !1 + +template +OutputIter copy_n__(InputIter first, Size count, + OutputIter result, + std::input_iterator_tag) { + for ( ; count > 0; --count) { + *result = *first; + ++first; + ++result; + } + return result; +} + +template +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 +inline OutputIter +copy_n__(InputIter first, Size count, OutputIter result) { + typedef std::iterator_traits::iterator_category cat; + return copy_n__(first, count, result, cat()); +} + +template +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 diff --git a/include/boost/multi_array/base.hpp b/include/boost/multi_array/base.hpp new file mode 100644 index 0000000..74c0f63 --- /dev/null +++ b/include/boost/multi_array/base.hpp @@ -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 +#include +#include + +namespace boost { + +///////////////////////////////////////////////////////////////////////// +// class declarations +///////////////////////////////////////////////////////////////////////// + +template > +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_range; + typedef detail::multi_array::extent_range 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 +class sub_array; + +template +class const_sub_array; + +template +struct iterator_generator; + +template +struct const_iterator_generator; + +template +struct reverse_iterator_generator; + +template +struct const_reverse_iterator_generator; + +template +struct iterator_base; + +template +struct iterator_policies; + +template +class const_multi_array_view; + +template +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 +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 value_type; + typedef sub_array reference; + typedef const_sub_array const_reference; + +protected: + // used by array operator[] and iterators to get reference types. + template + Reference access(boost::type,index idx,TPtr base, + const size_type* extents, + const index* strides, + const index* index_base) const { + + // return a sub_array 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 +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 + Reference access(boost::type,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 + struct bind { + typedef value_accessor_n type; + }; +}; + +struct choose_value_accessor_one { + template + struct bind { + typedef value_accessor_one type; + }; +}; + + +template +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 +struct value_accessor_generator { +private: + typedef typename value_accessor_gen_helper::choice Choice; +public: + typedef typename Choice::template bind::type type; +}; + +// +// choose value accessor ends +///////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////// +// multi_array/sub_array base stuffs +///////////////////////////////////////////////////////////////////////// +template +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 +class multi_array_impl_base : + public value_accessor_generator::type { + typedef typename value_accessor_generator::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 + struct subarray { + typedef boost::detail::multi_array::sub_array type; + }; + + template + struct const_subarray { + typedef boost::detail::multi_array::const_sub_array type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + template + struct const_array_view { + public: + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + // + // iterator support + // + + typedef typename iterator_tag_selector::type iterator_tag; + + typedef typename + iterator_generator::type iterator; + + typedef typename + const_iterator_generator::type const_iterator; + + typedef typename + reverse_iterator_generator::type reverse_iterator; + + typedef typename + const_reverse_iterator_generator::type const_reverse_iterator; + +protected: + typedef iterator_base iter_base; + typedef iterator_base const_iter_base; + + multi_array_impl_base() { } + ~multi_array_impl_base() { } + + // Used by operator() in our array classes + template + Reference access_element(boost::type, 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 + void compute_strides(StrideList& stride_list, ExtentList& extent_list, + const general_storage_order& 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 + index + calculate_origin_offset(const StrideList& stride_list, + const ExtentList& extent_list, + const general_storage_order& 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 + index + calculate_descending_dimension_offset(const StrideList& stride_list, + const ExtentList& extent_list, + const general_storage_order& 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 + 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 + ArrayRef + generate_array_view(boost::type, + const boost::detail::multi_array:: + index_gen& indices, + const size_type* extents, + const index* strides, + const index* index_bases, + TPtr base) const { + + boost::array new_strides; + boost::array 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 diff --git a/include/boost/multi_array/collection_concept.hpp b/include/boost/multi_array/collection_concept.hpp new file mode 100644 index 0000000..36195f5 --- /dev/null +++ b/include/boost/multi_array/collection_concept.hpp @@ -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 + 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::function_requires >(); + boost::function_requires >(); + 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 diff --git a/include/boost/multi_array/concept_checks.hpp b/include/boost/multi_array/concept_checks.hpp new file mode 100644 index 0000000..2e470ad --- /dev/null +++ b/include/boost/multi_array/concept_checks.hpp @@ -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 + struct idgen_helper { + + template + 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::call(a,idgen[c],c); + } + }; + + template <> + struct idgen_helper<0> { + + template + 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 + struct ConstMultiArrayConcept + { + void constraints() { + // function_requires< CopyConstructibleConcept >(); + + // RG - a( CollectionArchetype) when available... + a[ id ]; + // Test slicing, keeping only the first dimension, losing the rest + idgen_helper::call(a,idgen[range],id); + + // Test slicing, keeping all dimensions. + idgen_helper::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 + struct MutableMultiArrayConcept + { + void constraints() { + // function_requires< CopyConstructibleConcept >(); + + // RG - a( CollectionArchetype) when available... + value_type vt = a[ id ]; + + // Test slicing, keeping only the first dimension, losing the rest + idgen_helper::call(a,idgen[range],id); + + // Test slicing, keeping all dimensions. + idgen_helper::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::call(a,idgen[range],id); + + // Test slicing, keeping all dimensions. + idgen_helper::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 diff --git a/include/boost/multi_array/copy_array.hpp b/include/boost/multi_array/copy_array.hpp new file mode 100644 index 0000000..5e47d8a --- /dev/null +++ b/include/boost/multi_array/copy_array.hpp @@ -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 + +namespace boost { +namespace detail { +namespace multi_array { + +template +class copy_dispatch { +public: + template + 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 + 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 +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:: + copy_array(source.begin(),source.end(),dest.begin()); +} + + +} // namespace multi_array +} // namespace detail +} // namespace boost + +#endif // COPY_ARRAY_RG092101_HPP diff --git a/include/boost/multi_array/extent_gen.hpp b/include/boost/multi_array/extent_gen.hpp new file mode 100644 index 0000000..46429a4 --- /dev/null +++ b/include/boost/multi_array/extent_gen.hpp @@ -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 + +namespace boost { +namespace detail { +namespace multi_array { + + +template +class extent_gen { +public: + typedef boost::detail::multi_array::index index; + typedef boost::detail::multi_array::size_type size_type; +private: + typedef extent_range range; + typedef typename range_list_generator::type range_list; +public: + template + struct gen_type { + typedef extent_gen type; + }; + + range_list ranges_; + + extent_gen() { } + + // Used by operator[] to expand extent_gens + extent_gen(const extent_gen& rhs, + const range& a_range) + { + std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin()); + *ranges_.rbegin() = a_range; + } + + extent_gen + operator[](const range& a_range) + { + return extent_gen(*this,a_range); + } + + extent_gen + operator[](index idx) + { + return extent_gen(*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 diff --git a/include/boost/multi_array/extent_range.hpp b/include/boost/multi_array/extent_range.hpp new file mode 100644 index 0000000..ddd9f68 --- /dev/null +++ b/include/boost/multi_array/extent_range.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_EXTENT_RANGE_RG071801_HPP +#define BOOST_EXTENT_RANGE_RG071801_HPP + +#include + +namespace boost { +namespace detail { +namespace multi_array { + +template +class extent_range : private std::pair { + typedef std::pair 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 diff --git a/include/boost/multi_array/index_gen.hpp b/include/boost/multi_array/index_gen.hpp new file mode 100644 index 0000000..d5c714e --- /dev/null +++ b/include/boost/multi_array/index_gen.hpp @@ -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 +#include + +namespace boost { +namespace detail { +namespace multi_array { + + +template +struct index_gen { +private: + typedef index Index; + typedef std::size_t SizeType; + typedef index_range range; +public: + template + struct gen_type { + typedef index_gen type; + }; + + typedef typename range_list_generator::type range_list; + range_list ranges_; + + index_gen() { } + + template + explicit index_gen(const index_gen& rhs, + const index_range& range) + { + std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin()); + *ranges_.rbegin() = range; + } + + index_gen + operator[](const index_range& range) const + { + index_gen tmp; + std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin()); + *tmp.ranges_.rbegin() = range; + return tmp; + } + + index_gen + operator[](Index idx) const + { + index_gen tmp; + std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin()); + *tmp.ranges_.rbegin() = index_range(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 diff --git a/include/boost/multi_array/index_range.hpp b/include/boost/multi_array/index_range.hpp new file mode 100644 index 0000000..7dfcbe3 --- /dev/null +++ b/include/boost/multi_array/index_range.hpp @@ -0,0 +1,189 @@ +#ifndef BOOST_INDEX_RANGE_RG071801_HPP +#define BOOST_INDEX_RANGE_RG071801_HPP + +#include +#include +#include + +// 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 + 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::min(); } + + static index to_end() + { return std::numeric_limits::max(); } + public: + index start_, finish_, stride_; + bool degenerate_; + }; + + // Express open and closed interval end-points using the comparison + // operators. + + // left closed + template + inline index_range + operator<=(Index s, const index_range& r) + { + return index_range(s, r.finish(), r.stride()); + } + + // left open + template + inline index_range + operator<(Index s, const index_range& r) + { + return index_range(s + 1, r.finish(), r.stride()); + } + + // right open + template + inline index_range + operator<(const index_range& r, Index f) + { + return index_range(r.start(), f, r.stride()); + } + + // right closed + template + inline index_range + operator<=(const index_range& r, Index f) + { + return index_range(r.start(), f + 1, r.stride()); + } + +} // namespace multi_array +} // namespace detail +} // namespace boost + +#endif // BOOST_INDEX_RANGE_RG071801_HPP diff --git a/include/boost/multi_array/iterator.hpp b/include/boost/multi_array/iterator.hpp new file mode 100644 index 0000000..356fb56 --- /dev/null +++ b/include/boost/multi_array/iterator.hpp @@ -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 +#include + +namespace boost { +namespace detail { +namespace multi_array { + +///////////////////////////////////////////////////////////////////////// +// iterator components +///////////////////////////////////////////////////////////////////////// + +template +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 + iterator_base(const iterator_base& rhs) : + idx_(rhs.idx_), base_(rhs.base_), extents_(rhs.extents_), + strides_(rhs.strides_), index_base_(rhs.index_base_) { + } + + // default constructor required + iterator_base() {} +}; + +template +struct iterator_policies : + public boost::detail::multi_array::default_iterator_policies, + private value_accessor_generator::type { +private: + typedef typename value_accessor_generator::type super_type; +public: + template + typename IteratorAdaptor::reference + dereference(const IteratorAdaptor& iter) const { + typedef typename IteratorAdaptor::reference reference; + return super_type::access(boost::type(), + iter.base().idx_, + iter.base().base_, + iter.base().extents_, + iter.base().strides_, + iter.base().index_base_); + } + + template + static void increment(IteratorAdaptor& x) { ++x.base().idx_; } + + template + static void decrement(IteratorAdaptor& x) { --x.base().idx_; } + + template + 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 + static void advance(IteratorAdaptor& x, DifferenceType n) { + x.idx_ += n; + } + + template + typename IteratorAdaptor1::difference_type + distance(IteratorAdaptor1& lhs, IteratorAdaptor2& rhs) const { + return rhs.base().idx_ - lhs.base().idx_; + } +}; + + +template +struct iterator_gen_helper { +private: + typedef iterator_policies policies; + typedef value_type* pointer_type; + typedef tag category; +public: + typedef boost::detail::multi_array::iterator_adaptor type; +}; + + +template +struct iterator_generator { +private: + typedef iterator_base base_type; +public: + typedef typename iterator_gen_helper::type type; +}; + +template +struct const_iterator_generator { +private: + typedef iterator_base base_type; +public: + typedef typename iterator_gen_helper::type type; +}; + +template +struct reverse_iterator_generator { +private: + typedef iterator_base base_type; + typedef typename iterator_gen_helper::type it_type; +public: + typedef typename boost::reverse_iterator_generator::type type; +}; + +template +struct const_reverse_iterator_generator { +private: + typedef iterator_base base_type; + typedef typename iterator_gen_helper::type it_type; +public: + typedef typename boost::reverse_iterator_generator::type type; +}; + +} // namespace multi_array +} // namespace detail +} // namespace boost + +#endif // ITERATOR_RG071801_HPP diff --git a/include/boost/multi_array/iterator_adaptors.hpp b/include/boost/multi_array/iterator_adaptors.hpp new file mode 100644 index 0000000..2359c5a --- /dev/null +++ b/include/boost/multi_array/iterator_adaptors.hpp @@ -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 +// 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 +# include +# include +# include +# include +# include +# include +# include +# include + +// 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 + void initialize(Base&) + { } + + template + typename IteratorAdaptor::reference dereference(const IteratorAdaptor& x) const + { return *x.base(); } + + template + void increment(IteratorAdaptor& x) + { ++x.base(); } + + template + void decrement(IteratorAdaptor& x) + { --x.base(); } + + template + void advance(IteratorAdaptor& x, DifferenceType n) + { x.base() += n; } + + template + typename IteratorAdaptor1::difference_type + distance(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const + { return y.base() - x.base(); } + + template + 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 +struct iterator_comparisons : Base { }; + +template +inline bool operator==(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(yb); + return x.policies().equal(x, y); +} + +template +inline bool operator!=(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(yb); + return !x.policies().equal(x, y); +} + +template +inline bool operator<(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(yb); + return x.policies().distance(y, x) < 0; +} + +template +inline bool operator>(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(yb); + return x.policies().distance(y, x) > 0; +} + +template +inline bool operator>=(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(yb); + return x.policies().distance(y, x) >= 0; +} + +template +inline bool operator<=(const iterator_comparisons& xb, + const iterator_comparisons& yb) +{ + const D1& x = static_cast(xb); + const D2& y = static_cast(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 + 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 + inline operator_arrow_proxy + 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(*i); + } + + template + inline typename Iter::pointer + operator_arrow(const Iter& i, std::forward_iterator_tag) { + return &(*i); + } + + template + struct operator_arrow_result_generator + { + //RG - another important change! + typedef operator_arrow_proxy proxy; + // Borland chokes unless it's an actual enum (!) + enum { use_proxy = !boost::is_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 + struct iterator_defaults_select + { + template + 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::pointer pointer; + typedef typename boost::detail::iterator_traits::reference reference; + }; + }; + + // Select default pointer and reference types for adapted pointer iterators + // given a (possibly-const) value_type. + template <> + struct iterator_defaults_select + { + template + struct traits + { + typedef Value* pointer; + typedef Value& reference; + }; + }; + + // Consolidate selection of the default pointer and reference type + template + struct iterator_defaults + { + BOOST_STATIC_CONSTANT(bool, is_ptr = boost::is_pointer::value); + + typedef typename iterator_defaults_select::template traits traits; + typedef typename traits::pointer pointer; + typedef typename traits::reference reference; + }; +# else + template + struct iterator_defaults : iterator_traits + { + // 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_type>::value + )>::template then< + typename iterator_traits::pointer, + Value* + >::type pointer; + + typedef typename if_true<( + ::boost::is_same::value_type>::value + )>::template then< + typename iterator_traits::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 + struct select { typedef default_argument type; }; + }; + // This class template is a workaround for MSVC. + template struct default_generator { + typedef dummy_default_gen type; + }; + + struct default_value_type { + template + struct select { + typedef typename boost::detail::iterator_traits::value_type type; + }; + }; + template <> struct default_generator + { typedef default_value_type type; }; // VC++ workaround + + struct default_difference_type { + template + struct select { + typedef typename boost::detail::iterator_traits::difference_type type; + }; + }; + template <> struct default_generator + { typedef default_difference_type type; }; // VC++ workaround + + struct default_iterator_category { + template + struct select { + typedef typename boost::detail::iterator_traits::iterator_category type; + }; + }; + template <> struct default_generator + { typedef default_iterator_category type; }; // VC++ workaround + + struct default_pointer { + template + struct select { + typedef typename Traits::value_type Value; + typedef typename boost::detail::multi_array::detail::iterator_defaults::pointer + type; + }; + }; + template <> struct default_generator + { typedef default_pointer type; }; // VC++ workaround + + struct default_reference { + template + struct select { + typedef typename Traits::value_type Value; + typedef typename boost::detail::multi_array::detail::iterator_defaults::reference + type; + }; + }; + template <> struct default_generator + { 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 + struct cons_type { + typedef A first_type; + typedef B second_type; + }; + +} // namespace detail + +template struct value_type_is : public named_template_param_base +{ + typedef detail::cons_type type; +}; +template struct reference_is : public named_template_param_base +{ + typedef detail::cons_type type; +}; +template struct pointer_is : public named_template_param_base +{ + typedef detail::cons_type type; +}; +template struct difference_type_is + : public named_template_param_base +{ + typedef detail::cons_type type; +}; +template struct iterator_category_is + : public named_template_param_base +{ + typedef detail::cons_type 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 + struct find_param; + + struct find_param_continue { + template 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::value)>::template + then::type + >::type type; + }; + }; + struct find_param_end { + template + struct select { typedef detail::default_argument type; }; + }; + template struct find_param_helper1 + { typedef find_param_continue type; }; + template <> struct find_param_helper1 + { typedef find_param_end type; }; + + template + struct find_param { + typedef typename find_param_helper1::type select1; + typedef typename select1::template select::type type; + }; +# else + template struct find_param; + + template + struct find_param { typedef default_argument type; }; + + // Found a matching Key, return the associated Value + template + struct find_param, Rest>, Key> { + typedef Value type; + }; + + // Non-matching keys, continue the search + template + struct find_param, Rest>, Key2> { + typedef typename find_param::type type; + }; +# endif + + struct make_named_arg { + template + struct select { typedef typename Value::type type; }; + }; + struct make_key_value { + template + struct select { typedef detail::cons_type type; }; + }; + + template + struct is_named_parameter + { + enum { value = is_convertible::value }; + }; + +# if defined(__MWERKS__) && __MWERKS__ <= 0x2406 // workaround for broken is_convertible implementation + template struct is_named_parameter > { enum { value = true }; }; + template struct is_named_parameter > { enum { value = true }; }; + template struct is_named_parameter > { enum { value = true }; }; + template struct is_named_parameter > { enum { value = true }; }; + template struct is_named_parameter > { enum { value = true }; }; +# endif + + template + struct make_arg { +# ifdef __BORLANDC__ + // Borland C++ doesn't like the extra indirection of is_named_parameter + typedef typename + if_true<(is_convertible::value)>:: + template then::type Make; +# else + enum { is_named = is_named_parameter::value }; + typedef typename if_true<(is_named)>::template + then::type Make; +# endif + typedef typename Make::template select::type type; + }; + + // Mechanism for resolving the default argument for a template parameter. + + template struct is_default { typedef type_traits::no_type type; }; + template <> struct is_default + { typedef type_traits::yes_type type; }; + + struct choose_default { + template + struct select { + typedef typename default_generator::type Gen; + typedef typename Gen::template select::type type; + }; + }; + struct choose_arg { + template + struct select { + typedef Arg type; + }; + }; + + template + struct choose_arg_or_default { typedef choose_arg type; }; + template <> struct choose_arg_or_default { + typedef choose_default type; + }; + + template + class resolve_default { + typedef typename choose_arg_or_default::type>::type + Selector; + public: + typedef typename Selector + ::template select::type type; + }; + + template + 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::type, + detail::cons_type::type, + detail::cons_type::type, + detail::cons_type::type, + detail::cons_type::type, + end_of_list> > > > > ArgList; + + // Search the list for particular parameters + typedef typename find_param::type Val; + typedef typename find_param::type Diff; + typedef typename find_param::type Cat; + typedef typename find_param::type Ptr; + typedef typename find_param::type Ref; + + typedef boost::iterator + Traits0; + + // Compute the defaults if necessary + typedef typename resolve_default::type + value_type; + // if getting default value type from iterator_traits, then it won't be const + typedef typename resolve_default::type difference_type; + typedef typename resolve_default::type iterator_category; + + typedef boost::iterator 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::type + pointer; + typedef typename resolve_default::type + reference; + + public: + typedef boost::iterator::type, + difference_type, pointer, reference> type; + }; + + // This is really a partial concept check for iterators. Should it + // be moved or done differently? + template + struct validator + { + BOOST_STATIC_CONSTANT( + bool, is_input_or_output_iter + = (boost::is_convertible::value + | boost::is_convertible::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::value) + | boost::is_same::value + | boost::is_same::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::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::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::pointer is used. +// +// Category - the iterator_category of the resulting iterator. If not +// supplied, iterator_traits::iterator_category is used. +// +// Distance - the difference_type of the resulting iterator. If not +// supplied, iterator_traits::difference_type is used. +template +struct iterator_adaptor : +#ifdef BOOST_RELOPS_AMBIGUITY_BUG + iterator_comparisons< + iterator_adaptor, + typename detail::iterator_adaptor_traits_gen::type + > +#else + detail::iterator_adaptor_traits_gen::type +#endif +{ + typedef iterator_adaptor self; + public: + typedef detail::iterator_adaptor_traits_gen 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 + iterator_adaptor ( + const iterator_adaptor& 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::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(*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(*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 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 +iterator_adaptor +operator+( + iterator_adaptor p, + Distance2 x) +{ + return p += x; +} + +template +iterator_adaptor +operator+( + Distance2 x, + iterator_adaptor p) +{ + return p += x; +} + +template +typename iterator_adaptor::difference_type +operator-( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + typedef typename iterator_adaptor::difference_type difference_type; + return x.policies().distance(y, x); +} + +#ifndef BOOST_RELOPS_AMBIGUITY_BUG +template +inline bool +operator==( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return x.policies().equal(x, y); +} + +template +inline bool +operator<( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return x.policies().distance(y, x) < 0; +} + +template +inline bool +operator>( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return x.policies().distance(y, x) > 0; +} + +template +inline bool +operator>=( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return x.policies().distance(y, x) >= 0; +} + +template +inline bool +operator<=( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return x.policies().distance(y, x) <= 0; +} + +template +inline bool +operator!=( + const iterator_adaptor& x, + const iterator_adaptor& y) +{ + return !x.policies().equal(x, y); +} +#endif + + +} // namespace multi_array +} // namespace detail +} // namespace boost +# undef BOOST_ARG_DEPENDENT_TYPENAME + + +#endif + + + diff --git a/include/boost/multi_array/range_list.hpp b/include/boost/multi_array/range_list.hpp new file mode 100644 index 0000000..9d0aaec --- /dev/null +++ b/include/boost/multi_array/range_list.hpp @@ -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 + struct bind { + typedef boost::array type; + }; +}; + +struct choose_range_list_zero { + template + struct bind { + typedef boost::array type; + }; +}; + + +template +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 +struct range_list_generator { +private: + typedef typename range_list_gen_helper::choice Choice; +public: + typedef typename Choice::template bind::type type; +}; + +// +// choose range list ends +///////////////////////////////////////////////////////////////////////// + +} // namespace multi_array +} // namespace detail +} // namespace boost + +#endif // RANGE_LIST_RG072501_HPP diff --git a/include/boost/multi_array/storage_order.hpp b/include/boost/multi_array/storage_order.hpp new file mode 100644 index 0000000..85779c8 --- /dev/null +++ b/include/boost/multi_array/storage_order.hpp @@ -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 +#include +#include +#include + +namespace boost { + + // RG - This is to make things work with VC++. So sad, so sad. + class c_storage_order; + class fortran_storage_order; + + template + class general_storage_order + { + public: + typedef detail::multi_array::size_type size_type; + template + 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 operator==(general_storage_order const& rhs) const { + return (ordering_ == rhs.ordering_) && + (ascending_ == rhs.ascending_); + } + + protected: + boost::array ordering_; + boost::array 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 + operator general_storage_order() const { + boost::array ordering; + boost::array ascending; + + for (size_type i=0; i != NumDims; ++i) { + ordering[i] = NumDims - 1 - i; + ascending[i] = true; + } + return general_storage_order(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 + operator general_storage_order() const { + boost::array ordering; + boost::array ascending; + + for (size_type i=0; i != NumDims; ++i) { + ordering[i] = i; + ascending[i] = true; + } + return general_storage_order(ordering.begin(), + ascending.begin()); + } +#endif + }; + +} // namespace boost + +#endif // BOOST_ARRAY_STORAGE_RG071801_HPP diff --git a/include/boost/multi_array/subarray.hpp b/include/boost/multi_array/subarray.hpp new file mode 100644 index 0000000..5b1ab06 --- /dev/null +++ b/include/boost/multi_array/subarray.hpp @@ -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 +#include +#include + +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 +class const_sub_array : + public boost::detail::multi_array::multi_array_impl_base +{ + typedef boost::detail::multi_array::multi_array_impl_base 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + // Allow default copy constructor as well. + + template + const_sub_array (const const_sub_array& 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(), + idx,base_,shape(),strides(),index_bases()); + } + + template + const element& operator()(const IndexList& indices) const { + return super_type::access_element(boost::type(), + origin(), + indices,strides()); + } + + // see generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const boost::detail::multi_array:: + index_gen& indices) + const { + typedef const_array_view::type return_type; + return + super_type::generate_array_view(boost::type(), + indices, + shape(), + strides(), + index_bases(), + base_); + } + + template + bool operator<(const const_sub_array& rhs) const { + return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); + } + + template + bool operator==(const const_sub_array& rhs) const { + if(std::equal(shape(),shape()+num_dimensions(),rhs.shape())) + return std::equal(begin(),end(),rhs.begin()); + else return false; + } + + template + bool operator!=(const const_sub_array& rhs) const { + return !(*this == rhs); + } + + template + bool operator>(const const_sub_array& rhs) const { + return rhs < *this; + } + + template + bool operator<=(const const_sub_array& rhs) const { + return !(*this > rhs); + } + + template + bool operator>=(const const_sub_array& 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()); + } + + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS +protected: + template friend class value_accessor_n; + template 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 +class sub_array : public const_sub_array +{ + typedef const_sub_array 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + // Assignment from other ConstMultiArray types. + template + 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(), + idx,base_,shape(),strides(),index_bases()); + } + + // see generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename array_view::type + operator[](const boost::detail::multi_array:: + index_gen& indices) { + typedef array_view::type return_type; + return + super_type::generate_array_view(boost::type(), + indices, + shape(), + strides(), + index_bases(), + origin()); + } + + template + element& operator()(const IndexList& indices) { + return super_type::access_element(boost::type(), + 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 + 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 +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const boost::detail::multi_array:: + index_gen& 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 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 +class subarray_gen { + typedef typename Array::element element; +public: + typedef boost::detail::multi_array::sub_array type; +}; + +template +class const_subarray_gen { + typedef typename Array::element element; +public: + typedef boost::detail::multi_array::const_sub_array type; +}; +} // namespace boost + +#endif // SUBARRAY_RG071801_HPP diff --git a/include/boost/multi_array/types.hpp b/include/boost/multi_array/types.hpp new file mode 100644 index 0000000..2f1cb1e --- /dev/null +++ b/include/boost/multi_array/types.hpp @@ -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 + +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 diff --git a/include/boost/multi_array/view.hpp b/include/boost/multi_array/view.hpp new file mode 100644 index 0000000..fe69ba6 --- /dev/null +++ b/include/boost/multi_array/view.hpp @@ -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 +#include +#include +#include + +namespace boost { +namespace detail { +namespace multi_array { + +// TPtr = const T* defaulted in base.hpp +template +class const_multi_array_view : + public boost::detail::multi_array::multi_array_impl_base +{ + typedef boost::detail::multi_array::multi_array_impl_base 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + template + const_multi_array_view(const + const_multi_array_view& 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 + 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 + const element& operator()(IndexList indices) const { + return super_type::access_element(boost::type(), + origin(), + indices,strides()); + } + + // Only allow const element access + const_reference operator[](index idx) const { + return super_type::access(boost::type(), + idx,origin(), + shape(),strides(), + index_bases()); + } + + // see generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const boost::detail::multi_array:: + index_gen& indices) + const { + typedef const_array_view::type return_type; + return + super_type::generate_array_view(boost::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 + bool operator==(const + const_multi_array_view& 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 + bool operator<(const + const_multi_array_view& rhs) + const { + return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); + } + + template + bool operator!=(const + const_multi_array_view& rhs) + const { + return !(*this == rhs); + } + + template + bool operator>(const + const_multi_array_view& rhs) + const { + return rhs < *this; + } + + template + bool operator<=(const + const_multi_array_view& rhs) + const { + return !(*this > rhs); + } + + template + bool operator>=(const + const_multi_array_view& rhs) + const { + return !(*this < rhs); + } + + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS +protected: + template friend class multi_array_impl_base; + template 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 + explicit const_multi_array_view(TPtr base, + const ExtentList& extents, + const boost::array& 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()); + assert(num_elements_ != 0); + } + + typedef boost::array size_list; + typedef boost::array 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 +class multi_array_view : + public const_multi_array_view +{ + typedef const_multi_array_view 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + // Assignment from other ConstMultiArray types. + template + multi_array_view& operator=(const ConstMultiArray& other) { + function_requires< + boost::detail::multi_array:: + ConstMultiArrayConcept >(); + + // 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 + element& operator()(const IndexList& indices) { + return super_type::access_element(boost::type(), + origin(), + indices,strides()); + } + + + reference operator[](index idx) { + return super_type::access(boost::type(), + idx,origin(), + shape(),strides(), + index_bases()); + } + + + // see generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename array_view::type + operator[](const boost::detail::multi_array:: + index_gen& indices) { + typedef array_view::type return_type; + return + super_type::generate_array_view(boost::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 + 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 +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const boost::detail::multi_array:: + index_gen& 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 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 + explicit multi_array_view(T* base, + const ExtentList& extents, + const boost::array& strides) : + super_type(base,extents,strides) { } + +}; + +} // namespace multi_array +} // namespace detail + +// +// traits classes to get array_view types +// +template +class array_view_gen { + typedef typename Array::element element; +public: + typedef boost::detail::multi_array::multi_array_view type; +}; + +template +class const_array_view_gen { + typedef typename Array::element element; +public: + typedef boost::detail::multi_array::const_multi_array_view type; +}; + +} // namespace boost + +#endif // BOOST_MULTI_ARRAY_VIEW_RG071301_HPP + diff --git a/include/boost/multi_array_ref.hpp b/include/boost/multi_array_ref.hpp new file mode 100644 index 0000000..43418df --- /dev/null +++ b/include/boost/multi_array_ref.hpp @@ -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 +#include +#include +#include +#include + +namespace boost { + +template +class const_multi_array_ref : + public detail::multi_array::multi_array_impl_base +{ + typedef detail::multi_array::multi_array_impl_base 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + // make const_multi_array_ref a friend of itself + template + friend class const_multi_array_ref; +#endif + + template + const_multi_array_ref(const const_multi_array_ref& 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 + explicit const_multi_array_ref(TPtr base, const ExtentList& extents) : + base_(base), storage_(c_storage_order()) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + + index_base_list_.assign(0); + init_multi_array_ref(extents.begin()); + } + + template + explicit const_multi_array_ref(TPtr base, const ExtentList& extents, + const general_storage_order& so) : + base_(base), storage_(so) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + + index_base_list_.assign(0); + init_multi_array_ref(extents.begin()); + } + + explicit const_multi_array_ref(TPtr base, + const detail::multi_array:: + extent_gen& 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& ranges, + const general_storage_order& so) : + base_(base), storage_(so) { + + init_from_extent_gen(ranges); + } + + template + void assign(InputIterator begin, InputIterator end) { + boost::function_requires >(); + + 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 + void reindex(const BaseList& values) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + 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 + void reshape(const SizeList& extents) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + assert(num_elements_ == + std::accumulate(extents.begin(),extents.end(), + size_type(1),std::multiplies())); + + 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 + const element& operator()(IndexList indices) const { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + return super_type::access_element(boost::type(), + origin(), + indices,strides()); + } + + // Only allow const element access + const_reference operator[](index idx) const { + return super_type::access(boost::type(), + idx,origin(), + shape(),strides(),index_bases()); + } + + // see generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const detail::multi_array:: + index_gen& indices) + const { + typedef const_array_view::type return_type; + return + super_type::generate_array_view(boost::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 + bool operator==(const + const_multi_array_ref& 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 + bool operator<(const + const_multi_array_ref& rhs) + const { + return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); + } + + template + bool operator!=(const + const_multi_array_ref& rhs) + const { + return !(*this == rhs); + } + + template + bool operator>(const + const_multi_array_ref& rhs) + const { + return rhs < *this; + } + + template + bool operator<=(const + const_multi_array_ref& rhs) + const { + return !(*this > rhs); + } + + template + bool operator>=(const + const_multi_array_ref& 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 + const_multi_array_ref(const detail::multi_array:: + const_sub_array& 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_list; + typedef boost::array index_list; + + TPtr base_; + general_storage_order 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& ranges) { + + typedef boost::array 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 + void init_multi_array_ref(InputIterator extents_iter) { + boost::function_requires >(); + + 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()); + 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 +class multi_array_ref : + public const_multi_array_ref +{ + typedef const_multi_array_ref 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 + struct const_array_view { + typedef boost::detail::multi_array::const_multi_array_view type; + }; + + template + struct array_view { + typedef boost::detail::multi_array::multi_array_view type; + }; + + template + explicit multi_array_ref(T* base, const ExtentList& extents) : + super_type(base,extents) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + } + + template + explicit multi_array_ref(T* base, const ExtentList& extents, + const general_storage_order& so) : + super_type(base,extents,so) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + } + + + explicit multi_array_ref(T* base, + const detail::multi_array:: + extent_gen& ranges) : + super_type(base,ranges) { } + + + explicit multi_array_ref(T* base, + const detail::multi_array:: + extent_gen& + ranges, + const general_storage_order& so) : + super_type(base,ranges,so) { } + + template + multi_array_ref(const detail::multi_array:: + const_sub_array& rhs) + : super_type(rhs) {} + + // Assignment from other ConstMultiArray types. + template + multi_array_ref& operator=(const ConstMultiArray& other) { + function_requires< + detail::multi_array:: + ConstMultiArrayConcept >(); + + // 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 + element& operator()(const IndexList& indices) { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + return super_type::access_element(boost::type(), + origin(), + indices,strides()); + } + + + reference operator[](index idx) { + return super_type::access(boost::type(), + idx,origin(), + shape(),strides(), + index_bases()); + } + + + // See note attached to generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename array_view::type + operator[](const detail::multi_array:: + index_gen& indices) { + typedef array_view::type return_type; + return + super_type::generate_array_view(boost::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 + const element& operator()(const IndexList& indices) const { + boost::function_requires< + detail::multi_array::CollectionConcept >(); + return super_type::operator()(indices); + } + + const_reference operator[](index idx) const { + return super_type::access(boost::type(), + idx,origin(), + shape(),strides(),index_bases()); + } + + // See note attached to generate_array_view in base.hpp +#ifndef BOOST_MSVC + template +#else + template // else ICE +#endif // BOOST_MSVC + typename const_array_view::type + operator[](const detail::multi_array:: + index_gen& 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 diff --git a/test/access.cpp b/test/access.cpp new file mode 100644 index 0000000..48b9d91 --- /dev/null +++ b/test/access.cpp @@ -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 +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 +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 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(); +} diff --git a/test/assign.cpp b/test/assign.cpp new file mode 100644 index 0000000..683c733 --- /dev/null +++ b/test/assign.cpp @@ -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 +#include + +template +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 +void access(Array& A, const mutable_array_tag&) { + assign(A); + typedef boost::multi_array 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 +void access(Array&, const const_array_tag&) { +} + + +int test_main(int,char**) { + return run_generative_tests(); +} diff --git a/test/compare.cpp b/test/compare.cpp new file mode 100644 index 0000000..d444d66 --- /dev/null +++ b/test/compare.cpp @@ -0,0 +1,131 @@ + + +#include "boost/multi_array.hpp" + +#define BOOST_INCLUDE_MAIN +#include "boost/test/test_tools.hpp" + +#include +#include + + +int +test_main(int, char*[]) +{ + typedef boost::multi_array array; + typedef array::size_type size_type; + boost::array sizes = { { 3, 3, 3 } }; + const size_type num_elements = 27; + + // Copy Constructor + { + array A(sizes); + std::vector 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 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 valsA(num_elements, 4.5); + std::vector 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; +} + + diff --git a/test/concept_checks.cpp b/test/concept_checks.cpp new file mode 100644 index 0000000..8c27414 --- /dev/null +++ b/test/concept_checks.cpp @@ -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 array; + typedef boost::multi_array_ref array_ref; + typedef boost::const_multi_array_ref const_array_ref; + typedef array::array_view::type array_view; + typedef array::const_array_view::type const_array_view; + typedef array::subarray::type subarray; + typedef array::const_subarray::type const_subarray; + +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::ConstMultiArrayConcept >(); + +boost::function_requires< + boost::detail::multi_array::MutableMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::MutableMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::MutableMultiArrayConcept >(); +boost::function_requires< + boost::detail::multi_array::MutableMultiArrayConcept >(); + + return boost::exit_success; +} diff --git a/test/constructors.cpp b/test/constructors.cpp new file mode 100644 index 0000000..d6494a0 --- /dev/null +++ b/test/constructors.cpp @@ -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 +#include + +template +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 +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::size_type size_type; + boost::array sizes = { { 3, 3, 3 } }; + int strides[] = { 9, 3, 1 }; + size_type num_elements = 27; + + // Constructor 1, default storage order and allocator + { + boost::multi_array A(sizes); + check_shape(A, &sizes[0], strides, num_elements); + + double* ptr = 0; + boost::multi_array_ref B(ptr,sizes); + check_shape(B, &sizes[0], strides, num_elements); + + const double* cptr = ptr; + boost::const_multi_array_ref C(cptr,sizes); + check_shape(C, &sizes[0], strides, num_elements); + } + + // Constructor 1, fortran storage order and user-supplied allocator + { + typedef boost::multi_array >::size_type size_type; + size_type num_elements = 27; + int col_strides[] = { 1, 3, 9 }; + + boost::multi_array > A(sizes,boost::fortran_storage_order()); + check_shape(A, &sizes[0], col_strides, num_elements); + + double *ptr=0; + boost::multi_array_ref + 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 + 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::size_type size_type; + size_type num_elements = 27; + + boost::multi_array::extent_gen extents; + boost::multi_array A(extents[3][3][3]); + check_shape(A, &sizes[0], strides, num_elements); + + double *ptr=0; + boost::multi_array_ref B(ptr,extents[3][3][3]); + check_shape(B, &sizes[0], strides, num_elements); + + const double *cptr=ptr; + boost::const_multi_array_ref C(cptr,extents[3][3][3]); + check_shape(C, &sizes[0], strides, num_elements); + } + + // Copy Constructors + { + typedef boost::multi_array::size_type size_type; + size_type num_elements = 27; + std::vector vals(27, 4.5); + + boost::multi_array A(sizes); + A.assign(vals.begin(),vals.end()); + boost::multi_array B(A); + check_shape(B, &sizes[0], strides, num_elements); + BOOST_TEST(equal(A, B)); + + double ptr[27]; + boost::multi_array_ref C(ptr,sizes); + A.assign(vals.begin(),vals.end()); + boost::multi_array_ref 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 E(cptr,sizes); + boost::const_multi_array_ref F(E); + check_shape(F, &sizes[0], strides, num_elements); + BOOST_TEST(E.data() == F.data()); + } + + + // Conversion construction + { + typedef boost::multi_array::size_type size_type; + size_type num_elements = 27; + std::vector vals(27, 4.5); + + boost::multi_array A(sizes); + A.assign(vals.begin(),vals.end()); + boost::multi_array_ref B(A); + boost::const_multi_array_ref 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 D(ptr,sizes); + D.assign(vals.begin(),vals.end()); + boost::const_multi_array_ref E(D); + check_shape(E, &sizes[0], strides, num_elements); + BOOST_TEST(E.data() == D.data()); + } + + // Assignment Operator + { + typedef boost::multi_array::size_type size_type; + size_type num_elements = 27; + std::vector vals(27, 4.5); + + boost::multi_array 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 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 array; + typedef array::size_type size_type; + size_type num_elements = 27; + std::vector vals(num_elements, 4.5); + + boost::multi_array 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; +} + + diff --git a/test/dimtest.cpp b/test/dimtest.cpp new file mode 100644 index 0000000..52ec4f2 --- /dev/null +++ b/test/dimtest.cpp @@ -0,0 +1,300 @@ +// +// Trying to diagnose problems under visual + +#include "boost/config.hpp" +#include "boost/array.hpp" +#include "boost/limits.hpp" +#include +#include + +typedef int index; +typedef std::size_t size_type; + + template + 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::min(); } + + static Index to_end() + { return std::numeric_limits::max(); } + public: + Index start_, finish_, stride_; + bool degenerate_; + }; + + // Express open and closed interval end-points using the comparison + // operators. + + // left closed + template + inline index_range + operator<=(Index s, const index_range& r) + { + return index_range(s, r.finish(), r.stride()); + } + + // left open + template + inline index_range + operator<(Index s, const index_range& r) + { + return index_range(s + 1, r.finish(), r.stride()); + } + + // right open + template + inline index_range + operator<(const index_range& r, Index f) + { + return index_range(r.start(), f, r.stride()); + } + + // right closed + template + inline index_range + operator<=(const index_range& r, Index f) + { + return index_range(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 + struct bind { + typedef boost::array type; + }; +}; + +struct choose_range_list_zero { + template + struct bind { + typedef boost::array type; + }; +}; + + +template +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 +struct range_list_generator { +private: + typedef typename range_list_gen_helper::choice Choice; +public: + typedef typename Choice::template bind::type type; +}; + +// +// choose range list ends +///////////////////////////////////////////////////////////////////////// + +// +// Index_gen.hpp stuff +// + +template +struct index_gen { +private: + typedef index Index; + typedef size_type SizeType; + typedef index_range range; +public: + typedef typename range_list_generator::type range_list; + range_list ranges_; + + index_gen() { } + + template + explicit index_gen(const index_gen& rhs, + const index_range& range) + { + std::copy(rhs.ranges_.begin(),rhs.ranges_.end(),ranges_.begin()); + *ranges_.rbegin() = range; + } + + index_gen + operator[](const index_range& range) const + { + index_gen tmp; + std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin()); + *tmp.ranges_.rbegin() = range; + return tmp; + } + + index_gen + operator[](Index idx) const + { + index_gen tmp; + std::copy(ranges_.begin(),ranges_.end(),tmp.ranges_.begin()); + *tmp.ranges_.rbegin() = index_range(idx); + return tmp; + } +}; + + +template +void accept_gen(index_gen& indices) { + // do nothing +} + +template +class foo { }; + +class boo { + + template + void operator[](index_gen& indices) { + + } +}; + +template +void take_foo(foo& f) { } + +int main() { + + index_gen<0,0> indices; + typedef index_range range; + + take_foo(foo()); + + 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; +} diff --git a/test/fail_cbracket.cpp b/test/fail_cbracket.cpp new file mode 100644 index 0000000..f867d2b --- /dev/null +++ b/test/fail_cbracket.cpp @@ -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 array; + + boost::array 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; +} diff --git a/test/fail_cdata.cpp b/test/fail_cdata.cpp new file mode 100644 index 0000000..c0bcd0d --- /dev/null +++ b/test/fail_cdata.cpp @@ -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 array; + + boost::array 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; +} diff --git a/test/fail_citerator.cpp b/test/fail_citerator.cpp new file mode 100644 index 0000000..959419f --- /dev/null +++ b/test/fail_citerator.cpp @@ -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 array; + + typedef array::iterator iterator1; + typedef array::const_iterator citerator1; + + // ILLEGAL conversion from const_iterator to iterator + iterator1 in = citerator1(); + + return boost::exit_success; +} diff --git a/test/fail_cparen.cpp b/test/fail_cparen.cpp new file mode 100644 index 0000000..46c5eab --- /dev/null +++ b/test/fail_cparen.cpp @@ -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 array; + + boost::array 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 indices = {{0,0,0}}; + + // FAIL! Cannot assign to csma + csma(indices) = 5; + + return boost::exit_success; +} diff --git a/test/fail_criterator.cpp b/test/fail_criterator.cpp new file mode 100644 index 0000000..9cc9b63 --- /dev/null +++ b/test/fail_criterator.cpp @@ -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 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; +} diff --git a/test/fail_csubarray.cpp b/test/fail_csubarray.cpp new file mode 100644 index 0000000..80edc7f --- /dev/null +++ b/test/fail_csubarray.cpp @@ -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 array; + + boost::array 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::type csba = sma[0]; + + // FAIL! Preserve constness (no const_subarray -> subarray conversion). + array::subarray::type sba = csba; + + return boost::exit_success; +} diff --git a/test/fail_csubarray2.cpp b/test/fail_csubarray2.cpp new file mode 100644 index 0000000..fc56351 --- /dev/null +++ b/test/fail_csubarray2.cpp @@ -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 array; + + boost::array 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::type sba = sma_const[0]; + + return boost::exit_success; +} diff --git a/test/fail_csubarray3.cpp b/test/fail_csubarray3.cpp new file mode 100644 index 0000000..d686428 --- /dev/null +++ b/test/fail_csubarray3.cpp @@ -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 array; + + boost::array 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::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; +} diff --git a/test/fail_cview.cpp b/test/fail_cview.cpp new file mode 100644 index 0000000..475a10b --- /dev/null +++ b/test/fail_cview.cpp @@ -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 array; + + boost::array 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::type csma2 = + csma[indices[range(0,2)][range(1,3)][range(0,4,2)]]; + + boost::array elmt = {{0,0,0}}; + + // FAIL! const_array_view cannot be assigned to. + csma2(elmt) = 5; + + return boost::exit_success; +} + + + + + + + diff --git a/test/fail_cview2.cpp b/test/fail_cview2.cpp new file mode 100644 index 0000000..4b346a9 --- /dev/null +++ b/test/fail_cview2.cpp @@ -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 array; + + boost::array 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::type csma2 = + csma[indices[range(0,2)][range(1,3)][range(0,4,2)]]; + + return boost::exit_success; +} + + + + + + + diff --git a/test/fail_cview3.cpp b/test/fail_cview3.cpp new file mode 100644 index 0000000..33e7760 --- /dev/null +++ b/test/fail_cview3.cpp @@ -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 array; + + boost::array 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::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; +} + + + + + + + diff --git a/test/fail_ref_cbracket.cpp b/test/fail_ref_cbracket.cpp new file mode 100644 index 0000000..6775a56 --- /dev/null +++ b/test/fail_ref_cbracket.cpp @@ -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 array_ref; + + boost::array 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; +} diff --git a/test/fail_ref_cdata.cpp b/test/fail_ref_cdata.cpp new file mode 100644 index 0000000..d592afe --- /dev/null +++ b/test/fail_ref_cdata.cpp @@ -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 array_ref; + + boost::array 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; +} diff --git a/test/fail_ref_citerator.cpp b/test/fail_ref_citerator.cpp new file mode 100644 index 0000000..9c4fb17 --- /dev/null +++ b/test/fail_ref_citerator.cpp @@ -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 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; +} diff --git a/test/fail_ref_cparen.cpp b/test/fail_ref_cparen.cpp new file mode 100644 index 0000000..8c86dab --- /dev/null +++ b/test/fail_ref_cparen.cpp @@ -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 array_ref; + + boost::array 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 indices = {{0,0,0}}; + + // FAIL! cannot assign to a const multi_array_ref + csma(indices) = 5; + + return boost::exit_success; +} diff --git a/test/fail_ref_criterator.cpp b/test/fail_ref_criterator.cpp new file mode 100644 index 0000000..5416a73 --- /dev/null +++ b/test/fail_ref_criterator.cpp @@ -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 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; +} diff --git a/test/fail_ref_csubarray.cpp b/test/fail_ref_csubarray.cpp new file mode 100644 index 0000000..9aef297 --- /dev/null +++ b/test/fail_ref_csubarray.cpp @@ -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 array_ref; + + boost::array 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::type csba = sma[0]; + + array_ref::subarray::type sba = csba; // FAIL! preserve constness. + + return boost::exit_success; +} diff --git a/test/fail_ref_csubarray2.cpp b/test/fail_ref_csubarray2.cpp new file mode 100644 index 0000000..af86386 --- /dev/null +++ b/test/fail_ref_csubarray2.cpp @@ -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 array_ref; + + boost::array 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::type sba = sma_const[0]; // FAIL! + // preserve constness + + return boost::exit_success; +} diff --git a/test/fail_ref_csubarray3.cpp b/test/fail_ref_csubarray3.cpp new file mode 100644 index 0000000..fc89516 --- /dev/null +++ b/test/fail_ref_csubarray3.cpp @@ -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 array_ref; + + boost::array 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::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; +} diff --git a/test/fail_ref_cview.cpp b/test/fail_ref_cview.cpp new file mode 100644 index 0000000..d8bb157 --- /dev/null +++ b/test/fail_ref_cview.cpp @@ -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 array_ref; + + boost::array 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::type csma2 = + csma[indices[range(0,2)][range(1,3)][range(0,4,2)]]; + + boost::array elmt = {{0,0,0}}; + + csma2(elmt) = 5; // FAIL! csma is read only + + return boost::exit_success; +} + + + + + + + diff --git a/test/fail_ref_cview2.cpp b/test/fail_ref_cview2.cpp new file mode 100644 index 0000000..b7f5f20 --- /dev/null +++ b/test/fail_ref_cview2.cpp @@ -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 array_ref; + + boost::array 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::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; +} + + + + + + + diff --git a/test/fail_ref_cview3.cpp b/test/fail_ref_cview3.cpp new file mode 100644 index 0000000..1604a88 --- /dev/null +++ b/test/fail_ref_cview3.cpp @@ -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 array_ref; + + boost::array 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::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; +} + + + + + + + diff --git a/test/generative_tests.hpp b/test/generative_tests.hpp new file mode 100644 index 0000000..68b573f --- /dev/null +++ b/test/generative_tests.hpp @@ -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 +// void access(Array& A, const mutable_array_tag&); +// +// template +// 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 +#include +#include + +namespace { + unsigned int tests_run = 0; +} // empty namespace + +struct mutable_array_tag { }; +struct const_array_tag { }; + +template +void assign_if_not_const(Array&, const const_array_tag&) { + // do nothing +} + +template +void assign_if_not_const(Array& A, const mutable_array_tag&); + +#ifndef MULTIARRAY_TEST_ASSIGN +template +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 +void assign(Array& A) { + assign_if_not_const(A,mutable_array_tag()); +} + +template +void access(Array& A, const mutable_array_tag&); + +template +void access(Array& A, const const_array_tag&); + +template +int run_configuration(const StorageOrder3& so3, + const StorageOrder4& so4, + const Modifier& modifier) { + // multi_array + { + typedef boost::multi_array 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 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 array_ref; + typedef boost::const_multi_array_ref 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 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 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 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 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 +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 + void modify(Array&) const { } +}; + +struct set_index_base_modifier { + template + void modify(Array& A) const { A.reindex(1); } +}; + +struct reindex_modifier { + template + void modify(Array& A) const { + boost::array bases = {{1,2,3,4}}; + A.reindex(bases); + } +}; + +struct reshape_modifier { + template + void modify(Array& A) const { + typedef typename Array::size_type size_type; + std::vector old_shape(A.num_dimensions()); + std::vector 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 diff --git a/test/idxgen1.cpp b/test/idxgen1.cpp new file mode 100644 index 0000000..08fb2b5 --- /dev/null +++ b/test/idxgen1.cpp @@ -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 + + +template +void check(const boost::detail::multi_array:: + index_gen&) { } + +bool operator==(const boost::detail::multi_array:: + index_range& lhs, + const boost::detail::multi_array:: + index_range& 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 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; +} + diff --git a/test/index_bases.cpp b/test/index_bases.cpp new file mode 100644 index 0000000..02a4ede --- /dev/null +++ b/test/index_bases.cpp @@ -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 +#include +int +test_main(int,char**) +{ + typedef boost::multi_array array; + typedef boost::multi_array_ref array_ref; + typedef boost::const_multi_array_ref 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 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 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 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 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 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; +} diff --git a/test/iterators.cpp b/test/iterators.cpp new file mode 100644 index 0000000..0f05770 --- /dev/null +++ b/test/iterators.cpp @@ -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 +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 +struct ittraits_const { + typedef typename Array::const_iterator iterator3; + typedef typename boost::subarray_gen::type::const_iterator + iterator2; + typedef typename boost::subarray_gen::type::const_iterator + iterator1; + + typedef typename Array::const_reverse_iterator riterator3; + typedef typename boost::subarray_gen::type::const_reverse_iterator + riterator2; + typedef typename boost::subarray_gen::type::const_reverse_iterator + riterator1; +}; + +template +struct ittraits_mutable { + typedef typename Array::iterator iterator3; + typedef typename boost::subarray_gen::type::iterator iterator2; + typedef typename boost::subarray_gen::type::iterator iterator1; + + typedef typename Array::reverse_iterator riterator3; + typedef typename boost::subarray_gen::type::reverse_iterator + riterator2; + typedef typename boost::subarray_gen::type::reverse_iterator + riterator1; +}; + +///////////////////////////////////////////////////////////////////////// +// choose ittraits begins +// + +struct choose_ittraits_const { + template + struct bind { + typedef ittraits_const type; + }; +}; + +struct choose_ittraits_mutable { + template + struct bind { + typedef ittraits_mutable type; + }; +}; + + +template +struct ittraits_gen_helper { + typedef choose_ittraits_mutable choice; +}; + +template <> +struct ittraits_gen_helper { + typedef choose_ittraits_const choice; +}; + +template +struct ittraits_generator { +private: + typedef typename ittraits_gen_helper::choice Choice; +public: + typedef typename Choice::template bind::type type; +}; + +// +// choose ittraits ends +///////////////////////////////////////////////////////////////////////// + + +template +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 +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 +void access(Array& A, const mutable_array_tag&) { + assign(A); + + construct_iterators(A); + + typedef typename ittraits_generator::type + m_iter_traits; + + typedef typename ittraits_generator::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 +void access(Array& A, const const_array_tag&) { + construct_iterators(A); + typedef typename ittraits_generator::type + c_iter_traits; + test_iterators(A,c_iter_traits()); +} + + +int +test_main(int, char**) +{ + return run_generative_tests(); +} diff --git a/test/range1.cpp b/test/range1.cpp new file mode 100644 index 0000000..a9fdfd3 --- /dev/null +++ b/test/range1.cpp @@ -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 + +int +test_main(int,char**) +{ + typedef boost::detail::multi_array::index_range 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; +} diff --git a/test/regression.cfg b/test/regression.cfg new file mode 100644 index 0000000..020b33e --- /dev/null +++ b/test/regression.cfg @@ -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 diff --git a/test/reshape.cpp b/test/reshape.cpp new file mode 100644 index 0000000..51d59cf --- /dev/null +++ b/test/reshape.cpp @@ -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 array; + typedef boost::multi_array_ref array_ref; + typedef boost::const_multi_array_ref const_array_ref; + + boost::array dims = {{2,3,4}}; + boost::array 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 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; +} + + + + + + + diff --git a/test/slice.cpp b/test/slice.cpp new file mode 100644 index 0000000..010cc05 --- /dev/null +++ b/test/slice.cpp @@ -0,0 +1,142 @@ +// +// slice.cpp - testing out slicing on a matrices +// + +#include "generative_tests.hpp" +#include "boost/array.hpp" + +template +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::type array_view3; + typedef typename boost::array_view_gen::type array_view2; +}; + +template +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::type array_view3; + typedef typename boost::const_array_view_gen::type array_view2; +}; + + +///////////////////////////////////////////////////////////////////////// +// choose view_traits begins +// + +struct choose_view_traits_const { + template + struct bind { + typedef view_traits_const type; + }; +}; + +struct choose_view_traits_mutable { + template + struct bind { + typedef view_traits_mutable type; + }; +}; + + +template +struct view_traits_gen_helper { + typedef choose_view_traits_mutable choice; +}; + +template <> +struct view_traits_gen_helper { + typedef choose_view_traits_const choice; +}; + +template +struct view_traits_generator { +private: + typedef typename view_traits_gen_helper::choice Choice; +public: + typedef typename Choice::template bind::type type; +}; + +// +// choose view_traits ends +///////////////////////////////////////////////////////////////////////// + +template +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 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 elmts; + elmts[0]=i; elmts[1]=j; + BOOST_TEST(B(elmts) == A[idx0+i][idx1+1][idx2+j*2]); + } + } + ++tests_run; +} + + +template +void access(Array& A, const mutable_array_tag&) { + assign(A); + + typedef typename view_traits_generator::type + m_view_traits; + + typedef typename view_traits_generator::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 +void access(Array& A, const const_array_tag&) { + typedef typename view_traits_generator::type + c_view_traits; + test_views(A,c_view_traits()); +} + + +int test_main(int,char**) { + return run_generative_tests(); +} diff --git a/test/stl_interaction.cpp b/test/stl_interaction.cpp new file mode 100644 index 0000000..7408dfe --- /dev/null +++ b/test/stl_interaction.cpp @@ -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 +#include + +int +test_main(int, char**) +{ + using boost::extents; + using boost::indices; + typedef boost::multi_array_types::index_range range; + typedef boost::multi_array array3; + typedef boost::multi_array array2; + + typedef std::vector 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; +} diff --git a/test/storage_order.cpp b/test/storage_order.cpp new file mode 100644 index 0000000..8a2eade --- /dev/null +++ b/test/storage_order.cpp @@ -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 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 storage; + typedef boost::multi_array 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 storage; + typedef boost::multi_array 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 storage; + typedef boost::multi_array 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; +} diff --git a/test/storage_order_convert.cpp b/test/storage_order_convert.cpp new file mode 100644 index 0000000..1b800fa --- /dev/null +++ b/test/storage_order_convert.cpp @@ -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 c_ordering = {{4,3,2,1,0}};; + array fortran_ordering = {{0,1,2,3,4}}; + array 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; +} diff --git a/test/vc_death.cpp b/test/vc_death.cpp new file mode 100644 index 0000000..33502dc --- /dev/null +++ b/test/vc_death.cpp @@ -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 +#include +int +test_main(int,char**) +{ + typedef boost::multi_array 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; +}