[221] | 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 |
|
---|