/*************************************************************************** * blitz/array/indirect.h Array indirection * * Copyright (C) 1997-2001 Todd Veldhuizen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Suggestions: blitz-dev@oonumerics.org * Bugs: blitz-bugs@oonumerics.org * * For more information, please see the Blitz++ Home Page: * http://oonumerics.org/blitz/ * ****************************************************************************/ #ifndef BZ_ARRAY_INDIRECT_H #define BZ_ARRAY_INDIRECT_H #include #include BZ_NAMESPACE(blitz) template class IndirectArray { public: IndirectArray(T_array& array, T_index& index) : array_(array), index_(index) { } template void operator=(T_expr expr); protected: T_array& array_; T_index& index_; }; // Forward declarations template inline void applyOverSubdomain(const T_array& array, T_arrayiter& arrayIter, T_subdomain subdomain, T_expr expr); template inline void applyOverSubdomain(const T_array& array, T_arrayiter& arrayIter, RectDomain subdomain, T_expr expr); template template void IndirectArray::operator=(T_rhs rhs) { typedef _bz_typename asExpr::T_expr T_expr; T_expr expr(rhs); _bz_typename T_array::T_iterator arrayIter(array_); _bz_typename T_index::iterator iter = index_.begin(), end = index_.end(); for (; iter != end; ++iter) { _bz_typename T_index::value_type subdomain = *iter; applyOverSubdomain(array_, arrayIter, subdomain, expr); } } template inline void applyOverSubdomain(const T_array& BZ_DEBUG_PARAM(array), T_arrayiter& arrayIter, T_subdomain subdomain, T_expr expr) { BZPRECHECK(array.isInRange(subdomain), "In indirection using an STL container of TinyVector, one of the" << endl << "positions is out of" " range: " << endl << subdomain << endl << "Array lower bounds: " << array.lbound() << endl << "Array upper bounds: " << array.ubound() << endl) arrayIter.moveTo(subdomain); expr.moveTo(subdomain); *const_cast<_bz_typename T_arrayiter::T_numtype*>(arrayIter.data()) = *expr; } // Specialization for RectDomain template inline void applyOverSubdomain(const T_array& BZ_DEBUG_PARAM(array), T_arrayiter& arrayIter, RectDomain subdomain, T_expr expr) { typedef _bz_typename T_array::T_numtype T_numtype; // Assume that the RectDomain is a 1-D strip. // Find the dimension in which the strip is oriented. This // variable is static so that we cache the value; likely to be // the same for all strips within a container. static int stripDim = 0; if (subdomain.lbound(stripDim) == subdomain.ubound(stripDim)) { // Cached value was wrong, find the correct value of stripDim for (stripDim=0; stripDim < N_rank; ++stripDim) if (subdomain.lbound(stripDim) != subdomain.ubound(stripDim)) break; // Handle case where the strip is just a single point if (stripDim == N_rank) stripDim = 0; } #ifdef BZ_DEBUG // Check that this is in fact a 1D strip for (int i=0; i < N_rank; ++i) if ((i != stripDim) && (subdomain.lbound(i) != subdomain.ubound(i))) BZPRECHECK(0, "In indirection using an STL container of RectDomain<" << N_rank << ">, one of" << endl << "the RectDomain objects was not" " a one-dimensional strip:" << endl << "RectDomain<" << N_rank << ">::lbound() = " << subdomain.lbound() << endl << "RectDomain<" << N_rank << ">::ubound() = " << subdomain.ubound()) #endif // Check that the start and end position are in range BZPRECHECK(array.isInRange(subdomain.lbound()), "In indirection using an STL container of RectDomain<" << N_rank << ">, one of" << endl << "the RectDomain objects has a" " lbound which is out of range:" << endl << subdomain.lbound() << endl << "Array lower bounds: " << array.lbound() << endl << "Array upper bounds: " << array.ubound() << endl) BZPRECHECK(array.isInRange(subdomain.ubound()), "In indirection using an STL container of RectDomain<" << N_rank << ">, one of" << endl << "the RectDomain objects has a" " ubound which is out of range:" << endl << subdomain.lbound() << endl << "Array lower bounds: " << array.lbound() << endl << "Array upper bounds: " << array.ubound() << endl) // Position at the beginning of the strip arrayIter.moveTo(subdomain.lbound()); expr.moveTo(subdomain.lbound()); // Loop through the strip #ifdef BZ_USE_FAST_READ_ARRAY_EXPR bool useUnitStride = arrayIter.isUnitStride(stripDim) && expr.isUnitStride(stripDim); int lbound = subdomain.lbound(stripDim); int ubound = subdomain.ubound(stripDim); if (useUnitStride) { T_numtype* restrict data = const_cast(arrayIter.data()); int length = ubound - lbound + 1; for (int i=0; i < length; ++i) *data++ = expr.fastRead(i); } else { #endif arrayIter.loadStride(stripDim); expr.loadStride(stripDim); for (int i=lbound; i <= ubound; ++i) { *const_cast<_bz_typename T_arrayiter::T_numtype*>(arrayIter.data()) = *expr; expr.advance(); arrayIter.advance(); } #ifdef BZ_USE_FAST_READ_ARRAY_EXPR } #endif } // Global functions for cartesian product of index sets template CartesianProduct,T_container,2> indexSet(const T_container& container0, const T_container& container1) { return CartesianProduct,T_container,2>( const_cast(container0), const_cast(container1)); } template CartesianProduct,T_container,3> indexSet(const T_container& container0, const T_container& container1, const T_container& container2) { return CartesianProduct,T_container,3>( const_cast(container0), const_cast(container1), const_cast(container2)); } template CartesianProduct,T_container,4> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3) { return CartesianProduct,T_container,4>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3)); } template CartesianProduct,T_container,5> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4) { return CartesianProduct,T_container,5>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4)); } template CartesianProduct,T_container,6> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5) { return CartesianProduct,T_container,6>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5)); } template CartesianProduct,T_container,7> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5, const T_container& container6) { return CartesianProduct,T_container,7>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5), const_cast(container6)); } template CartesianProduct,T_container,8> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5, const T_container& container6, const T_container& container7) { return CartesianProduct,T_container,8>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5), const_cast(container6), const_cast(container7)); } template CartesianProduct,T_container,9> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5, const T_container& container6, const T_container& container7, const T_container& container8) { return CartesianProduct,T_container,9>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5), const_cast(container6), const_cast(container7), const_cast(container8)); } template CartesianProduct,T_container,10> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5, const T_container& container6, const T_container& container7, const T_container& container8, const T_container& container9) { return CartesianProduct,T_container,10>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5), const_cast(container6), const_cast(container7), const_cast(container8), const_cast(container9)); } template CartesianProduct,T_container,11> indexSet(const T_container& container0, const T_container& container1, const T_container& container2, const T_container& container3, const T_container& container4, const T_container& container5, const T_container& container6, const T_container& container7, const T_container& container8, const T_container& container9, const T_container& container10) { return CartesianProduct,T_container,11>( const_cast(container0), const_cast(container1), const_cast(container2), const_cast(container3), const_cast(container4), const_cast(container5), const_cast(container6), const_cast(container7), const_cast(container8), const_cast(container9), const_cast(container10)); } // Mixture of singletons and containers, e.g. A[indexSet(I,3,K)] // cp_findContainerType::T_container // The set of parameters T1, T2, T3, ... Tn is a mixture of // int and T_container. This traits class finds the container // type, and sets T_container. // // e.g. cp_findContainerType,int>::T_container is list // cp_findContainerType,deque>::T_container // is deque template struct cp_findContainerType { typedef T1 T_container; }; template struct cp_findContainerType { typedef _bz_typename cp_findContainerType::T_container T_container; }; // The cp_traits class handles promotion of singleton integers to // containers. It takes two template parameters: // T = argument type // T2 = container type // If T is an integer, then a container of type T2 is created and the // integer is inserted. This container is returned. // Otherwise, T is assumed to be the same type as T2, and the original // container is returned. template struct cp_traits { typedef T T_container; static const T_container& make(const T& x) { return x; } }; template struct cp_traits { typedef T2 T_container; static T2 make(int x) { T2 singleton; singleton.push_back(x); return singleton; } }; // These versions of indexSet() allow mixtures of integer // and container arguments. At least one integer must be // specified. template CartesianProduct, _bz_typename cp_findContainerType::T_container,2> indexSet(const T1& c1, const T2& c2) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 2>( cp_traits::make(c1), cp_traits::make(c2)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 3> indexSet(const T1& c1, const T2& c2, const T3& c3) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 3>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 4> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 4>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 5> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 5>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 6> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 6>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 7> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6, const T7& c7) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 7>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6), cp_traits::make(c7)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 8> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6, const T7& c7, const T8& c8) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 8>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6), cp_traits::make(c7), cp_traits::make(c8)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 9> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6, const T7& c7, const T8& c8, const T9& c9) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 9>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6), cp_traits::make(c7), cp_traits::make(c8), cp_traits::make(c9)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 10> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6, const T7& c7, const T8& c8, const T9& c9, const T10& c10) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 10>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6), cp_traits::make(c7), cp_traits::make(c8), cp_traits::make(c9), cp_traits::make(c10)); } template CartesianProduct, _bz_typename cp_findContainerType::T_container, 11> indexSet(const T1& c1, const T2& c2, const T3& c3, const T4& c4, const T5& c5, const T6& c6, const T7& c7, const T8& c8, const T9& c9, const T10& c10, const T11& c11) { typedef _bz_typename cp_findContainerType::T_container T_container; return CartesianProduct, T_container, 11>( cp_traits::make(c1), cp_traits::make(c2), cp_traits::make(c3), cp_traits::make(c4), cp_traits::make(c5), cp_traits::make(c6), cp_traits::make(c7), cp_traits::make(c8), cp_traits::make(c9), cp_traits::make(c10), cp_traits::make(c11)); } BZ_NAMESPACE_END #endif // BZ_ARRAY_INDIRECT_H