1 | /*
|
---|
2 | * $Id: methods.cc,v 1.1.1.1 1999-04-09 17:59:03 ansari Exp $
|
---|
3 | *
|
---|
4 | * $Log: not supported by cvs2svn $
|
---|
5 | * Revision 1.4 1998/03/14 00:04:47 tveldhui
|
---|
6 | * 0.2-alpha-05
|
---|
7 | *
|
---|
8 | * Revision 1.3 1997/08/18 19:13:08 tveldhui
|
---|
9 | * Just prior to implementing fastRead() optimization for array
|
---|
10 | * expression evaluation.
|
---|
11 | *
|
---|
12 | * Revision 1.2 1997/08/15 21:14:10 tveldhui
|
---|
13 | * Just prior to loop-collapse change
|
---|
14 | *
|
---|
15 | */
|
---|
16 |
|
---|
17 | #ifndef BZ_ARRAYMETHODS_CC
|
---|
18 | #define BZ_ARRAYMETHODS_CC
|
---|
19 |
|
---|
20 | #ifndef BZ_ARRAY_H
|
---|
21 | #error <blitz/array/methods.cc> must be included via <blitz/array.h>
|
---|
22 | #endif
|
---|
23 |
|
---|
24 | #include <blitz/minmax.h> // Needed for resizeAndPreserve()
|
---|
25 |
|
---|
26 | BZ_NAMESPACE(blitz)
|
---|
27 |
|
---|
28 | template<class P_numtype, int N_rank> template<class T_expr>
|
---|
29 | Array<P_numtype,N_rank>::Array(_bz_ArrayExpr<T_expr> expr)
|
---|
30 | {
|
---|
31 | BZ_NOT_IMPLEMENTED();
|
---|
32 |
|
---|
33 | // Obtain storage order from an operand in the expression
|
---|
34 | // (if possible). Probably best to assume C-style storage,
|
---|
35 | // then pass the storage object to the expression for possible
|
---|
36 | // modification.
|
---|
37 |
|
---|
38 | // Obtain ubounds/lbounds from array operands. Precondition
|
---|
39 | // failure if any bounds missing.
|
---|
40 |
|
---|
41 | // Size array.
|
---|
42 |
|
---|
43 | // assignment of expression.
|
---|
44 | }
|
---|
45 |
|
---|
46 | template<class T_numtype, int N_rank>
|
---|
47 | Array<T_numtype,N_rank>::Array(const TinyVector<int, N_rank>& lbounds,
|
---|
48 | const TinyVector<int, N_rank>& extent,
|
---|
49 | const GeneralArrayStorage<N_rank>& storage)
|
---|
50 | : storage_(storage)
|
---|
51 | {
|
---|
52 | length_ = extent;
|
---|
53 | storage_.setBase(lbounds);
|
---|
54 | setupStorage(N_rank - 1);
|
---|
55 | }
|
---|
56 |
|
---|
57 |
|
---|
58 | /*
|
---|
59 | * This routine takes the storage information for the array
|
---|
60 | * (ascendingFlag_[], base_[], and ordering_[]) and the size
|
---|
61 | * of the array (length_[]) and computes the stride vector
|
---|
62 | * (stride_[]) and the zero offset (see explanation in array.h).
|
---|
63 | */
|
---|
64 | template<class P_numtype, int N_rank>
|
---|
65 | _bz_inline2 void Array<P_numtype, N_rank>::computeStrides()
|
---|
66 | {
|
---|
67 | if (N_rank > 1)
|
---|
68 | {
|
---|
69 | int stride = 1;
|
---|
70 |
|
---|
71 | // This flag simplifies the code in the loop, encouraging
|
---|
72 | // compile-time computation of strides through constant folding.
|
---|
73 | _bz_bool allAscending = storage_.allRanksStoredAscending();
|
---|
74 |
|
---|
75 | // BZ_OLD_FOR_SCOPING
|
---|
76 | int n;
|
---|
77 | for (n=0; n < N_rank; ++n)
|
---|
78 | {
|
---|
79 | int strideSign = +1;
|
---|
80 |
|
---|
81 | // If this rank is stored in descending order, then the stride
|
---|
82 | // will be negative.
|
---|
83 | if (!allAscending)
|
---|
84 | {
|
---|
85 | if (!isRankStoredAscending(ordering(n)))
|
---|
86 | strideSign = -1;
|
---|
87 | }
|
---|
88 |
|
---|
89 | // The stride for this rank is the product of the lengths of
|
---|
90 | // the ranks minor to it.
|
---|
91 | stride_[ordering(n)] = stride * strideSign;
|
---|
92 |
|
---|
93 | stride *= length_[ordering(n)];
|
---|
94 | }
|
---|
95 | }
|
---|
96 | else {
|
---|
97 | // Specialization for N_rank == 1
|
---|
98 | // This simpler calculation makes it easier for the compiler
|
---|
99 | // to propagate stride values.
|
---|
100 |
|
---|
101 | if (isRankStoredAscending(0))
|
---|
102 | stride_[0] = 1;
|
---|
103 | else
|
---|
104 | stride_[0] = -1;
|
---|
105 | }
|
---|
106 |
|
---|
107 | calculateZeroOffset();
|
---|
108 | }
|
---|
109 |
|
---|
110 | template<class T_numtype, int N_rank>
|
---|
111 | void Array<T_numtype, N_rank>::calculateZeroOffset()
|
---|
112 | {
|
---|
113 | // Calculate the offset of (0,0,...,0)
|
---|
114 | zeroOffset_ = 0;
|
---|
115 |
|
---|
116 | // zeroOffset_ = - sum(where(ascendingFlag_, stride_ * base_,
|
---|
117 | // (length_ - 1 + base_) * stride_))
|
---|
118 | for (int n=0; n < N_rank; ++n)
|
---|
119 | {
|
---|
120 | if (!isRankStoredAscending(n))
|
---|
121 | zeroOffset_ -= (length_[n] - 1 + base(n)) * stride_[n];
|
---|
122 | else
|
---|
123 | zeroOffset_ -= stride_[n] * base(n);
|
---|
124 | }
|
---|
125 | }
|
---|
126 |
|
---|
127 |
|
---|
128 |
|
---|
129 | template<class P_numtype, int N_rank>
|
---|
130 | void Array<P_numtype, N_rank>::dumpStructureInformation(ostream& os) const
|
---|
131 | {
|
---|
132 | os << "Dump of Array<" << BZ_DEBUG_TEMPLATE_AS_STRING_LITERAL(P_numtype)
|
---|
133 | << ", " << N_rank << ">:" << endl
|
---|
134 | << "ordering_ = " << storage_.ordering() << endl
|
---|
135 | << "ascendingFlag_ = " << storage_.ascendingFlag() << endl
|
---|
136 | << "base_ = " << storage_.base() << endl
|
---|
137 | << "length_ = " << length_ << endl
|
---|
138 | << "stride_ = " << stride_ << endl
|
---|
139 | << "zeroOffset_ = " << zeroOffset_ << endl
|
---|
140 | << "numElements() = " << numElements() << endl
|
---|
141 | << "storageContiguous = " << storageContiguous_ << endl;
|
---|
142 | }
|
---|
143 |
|
---|
144 | /*
|
---|
145 | * Make this array a view of another array's data.
|
---|
146 | */
|
---|
147 | template<class P_numtype, int N_rank>
|
---|
148 | void Array<P_numtype, N_rank>::reference(Array<P_numtype, N_rank>& array)
|
---|
149 | {
|
---|
150 | storage_ = array.storage_;
|
---|
151 | length_ = array.length_;
|
---|
152 | stride_ = array.stride_;
|
---|
153 | zeroOffset_ = array.zeroOffset_;
|
---|
154 | storageContiguous_ = array.storageContiguous_;
|
---|
155 |
|
---|
156 | MemoryBlockReference<P_numtype>::changeBlock(array, array.zeroOffset_);
|
---|
157 |
|
---|
158 | data_ = array.data_;
|
---|
159 | }
|
---|
160 |
|
---|
161 | /*
|
---|
162 | * This method is called to allocate memory for a new array.
|
---|
163 | */
|
---|
164 | template<class P_numtype, int N_rank>
|
---|
165 | _bz_inline2 void Array<P_numtype, N_rank>::setupStorage(int lastRankInitialized)
|
---|
166 | {
|
---|
167 | TAU_TYPE_STRING(p1, "Array<T,N>::setupStorage() [T="
|
---|
168 | + CT(P_numtype) + ",N=" + CT(N_rank) + "]");
|
---|
169 | TAU_PROFILE(" ", p1, TAU_BLITZ);
|
---|
170 |
|
---|
171 | /*
|
---|
172 | * If the length of some of the ranks was unspecified, fill these
|
---|
173 | * in using the last specified value.
|
---|
174 | *
|
---|
175 | * e.g. Array<int,3> A(40) results in a 40x40x40 array.
|
---|
176 | */
|
---|
177 | for (int i=lastRankInitialized + 1; i < N_rank; ++i)
|
---|
178 | {
|
---|
179 | storage_.setBase(i, storage_.base(lastRankInitialized));
|
---|
180 | length_[i] = length_[lastRankInitialized];
|
---|
181 | }
|
---|
182 |
|
---|
183 | // Compute strides
|
---|
184 | computeStrides();
|
---|
185 |
|
---|
186 | // Allocate a block of memory
|
---|
187 | MemoryBlockReference<P_numtype>::newBlock(numElements());
|
---|
188 |
|
---|
189 | // Adjust the base of the array to account for non-zero base
|
---|
190 | // indices and reversals
|
---|
191 | data_ += zeroOffset_;
|
---|
192 |
|
---|
193 | // A new array will always have contiguous storage
|
---|
194 | storageContiguous_ = _bz_true;
|
---|
195 | }
|
---|
196 |
|
---|
197 | template<class T_numtype, int N_rank>
|
---|
198 | Array<T_numtype, N_rank> Array<T_numtype, N_rank>::copy() const
|
---|
199 | {
|
---|
200 | if (numElements())
|
---|
201 | {
|
---|
202 | Array<T_numtype, N_rank> z(length_, storage_);
|
---|
203 | z = *this;
|
---|
204 | return z;
|
---|
205 | }
|
---|
206 | else {
|
---|
207 | // Null array-- don't bother allocating an empty block.
|
---|
208 | return *this;
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | template<class T_numtype, int N_rank>
|
---|
213 | void Array<T_numtype, N_rank>::makeUnique()
|
---|
214 | {
|
---|
215 | if (numReferences() > 1)
|
---|
216 | {
|
---|
217 | T_array tmp = copy();
|
---|
218 | reference(tmp);
|
---|
219 | }
|
---|
220 | }
|
---|
221 |
|
---|
222 | template<class T_numtype, int N_rank>
|
---|
223 | Array<T_numtype, N_rank> Array<T_numtype, N_rank>::transpose(int r0, int r1,
|
---|
224 | int r2, int r3, int r4, int r5, int r6, int r7, int r8, int r9, int r10)
|
---|
225 | {
|
---|
226 | T_array B(*this);
|
---|
227 | B.transposeSelf(r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10);
|
---|
228 | return B;
|
---|
229 | }
|
---|
230 |
|
---|
231 | template<class T_numtype, int N_rank>
|
---|
232 | void Array<T_numtype, N_rank>::transposeSelf(int r0, int r1, int r2, int r3,
|
---|
233 | int r4, int r5, int r6, int r7, int r8, int r9, int r10)
|
---|
234 | {
|
---|
235 | BZPRECHECK(r0+r1+r2+r3+r4+r5+r6+r7+r8+r9+r10 == N_rank * (N_rank-1) / 2,
|
---|
236 | "Invalid array transpose() arguments." << endl
|
---|
237 | << "Arguments must be a permutation of the numerals (0,...,"
|
---|
238 | << (N_rank - 1) << ")");
|
---|
239 |
|
---|
240 | // Create a temporary reference copy of this array
|
---|
241 | Array<T_numtype, N_rank> x(*this);
|
---|
242 |
|
---|
243 | // Now reorder the dimensions using the supplied permutation
|
---|
244 | doTranspose(0, r0, x);
|
---|
245 | doTranspose(1, r1, x);
|
---|
246 | doTranspose(2, r2, x);
|
---|
247 | doTranspose(3, r3, x);
|
---|
248 | doTranspose(4, r4, x);
|
---|
249 | doTranspose(5, r5, x);
|
---|
250 | doTranspose(6, r6, x);
|
---|
251 | doTranspose(7, r7, x);
|
---|
252 | doTranspose(8, r8, x);
|
---|
253 | doTranspose(9, r9, x);
|
---|
254 | doTranspose(10, r10, x);
|
---|
255 | }
|
---|
256 |
|
---|
257 | template<class T_numtype, int N_rank>
|
---|
258 | void Array<T_numtype, N_rank>::doTranspose(int destRank, int sourceRank,
|
---|
259 | Array<T_numtype, N_rank>& array)
|
---|
260 | {
|
---|
261 | // BZ_NEEDS_WORK: precondition check
|
---|
262 |
|
---|
263 | if (destRank >= N_rank)
|
---|
264 | return;
|
---|
265 |
|
---|
266 | length_[destRank] = array.length_[sourceRank];
|
---|
267 | stride_[destRank] = array.stride_[sourceRank];
|
---|
268 | storage_.setAscendingFlag(destRank,
|
---|
269 | array.isRankStoredAscending(sourceRank));
|
---|
270 | storage_.setBase(destRank, array.base(sourceRank));
|
---|
271 |
|
---|
272 | // BZ_NEEDS_WORK: Handling the storage ordering is currently O(N^2)
|
---|
273 | // but it can be done fairly easily in linear time by constructing
|
---|
274 | // the appropriate permutation.
|
---|
275 |
|
---|
276 | // Find sourceRank in array.storage_.ordering_
|
---|
277 | int i=0;
|
---|
278 | for (; i < N_rank; ++i)
|
---|
279 | if (array.storage_.ordering(i) == sourceRank)
|
---|
280 | break;
|
---|
281 |
|
---|
282 | storage_.setOrdering(i, destRank);
|
---|
283 | }
|
---|
284 |
|
---|
285 | template<class T_numtype, int N_rank>
|
---|
286 | void Array<T_numtype, N_rank>::reverseSelf(int rank)
|
---|
287 | {
|
---|
288 | BZPRECONDITION(rank < N_rank);
|
---|
289 |
|
---|
290 | storage_.setAscendingFlag(rank, !isRankStoredAscending(rank));
|
---|
291 |
|
---|
292 | int adjustment = stride_[rank] * (length_[rank] - 1);
|
---|
293 | zeroOffset_ += adjustment;
|
---|
294 | data_ += adjustment;
|
---|
295 | stride_[rank] *= -1;
|
---|
296 | }
|
---|
297 |
|
---|
298 | template<class T_numtype, int N_rank>
|
---|
299 | Array<T_numtype, N_rank> Array<T_numtype,N_rank>::reverse(int rank)
|
---|
300 | {
|
---|
301 | T_array B(*this);
|
---|
302 | B.reverseSelf(rank);
|
---|
303 | return B;
|
---|
304 | }
|
---|
305 |
|
---|
306 | template<class T_numtype, int N_rank> template<class T_numtype2>
|
---|
307 | Array<T_numtype2,N_rank> Array<T_numtype,N_rank>::extractComponent(T_numtype2,
|
---|
308 | int componentNumber, int numComponents)
|
---|
309 | {
|
---|
310 | BZPRECONDITION((componentNumber >= 0) && (componentNumber < numComponents));
|
---|
311 |
|
---|
312 | TinyVector<int,N_rank> stride2;
|
---|
313 | stride2 = stride_ * numComponents;
|
---|
314 | T_numtype2* dataFirst2 = ((T_numtype2*)dataFirst()) + componentNumber;
|
---|
315 | return Array<T_numtype2,N_rank>(dataFirst2, length_, stride2, storage_);
|
---|
316 | }
|
---|
317 |
|
---|
318 | BZ_NAMESPACE_END
|
---|
319 |
|
---|
320 | #endif // BZ_ARRAY_CC
|
---|
321 |
|
---|