Follow this link to skip to the main content

2d_array.h

Go to the documentation of this file.
00001 // -*-c++-*-
00002 //----------------------------< /-/ CLARAty /-/ >------------------------------
00003 /**
00004  * @file  2d_array.h
00005  *
00006  * Defines a two dimensional array class and its functionality. The
00007  * two-dimensional array serves as a base class for math Matrix,
00008  * Vector and Image classes.  2D_Array class allocates continguous
00009  * memory for the arrays and carries out matrix indexing and some
00010  * basic operations such as == comparsions. This class requires and
00011  * guarantees that the elements are contiguous (but not necessarily
00012  * the memory allocated inside each element).
00013  *
00014  * <br>@b Designer(s):  Issa A.D. Nesnas 
00015  * <br>@b Author(s):    Issa A.D. Nesnas, Clay Kunz
00016  * <br>@b Date:         March 22, 2001
00017  *
00018  * <b>Software License:</b><br>
00019  * <code> http://claraty.jpl.nasa.gov/license/open_src/  or 
00020  *        file: license/open_src.txt </code>
00021  *
00022  * &copy; 2006, Jet Propulsion Laboratory, California Institute of Technology<br>
00023  *
00024  * $Revision: 1.8 $
00025  */
00026 //-----------------------------------------------------------------------------
00027 
00028 #ifndef N_2D_ARRAY_H
00029 #define N_2D_ARRAY_H
00030 
00031 #include "claraty/share.h"
00032 #include "claraty/2d_array_iterator.h"
00033 #include "claraty/reference_count.h"
00034 #include "claraty/2d_point.h"
00035 #include "claraty/fdm.h"
00036 
00037 #include <iostream>
00038 #include <iomanip>
00039 #include <assert.h>
00040 
00041 namespace claraty {
00042 
00043 /**
00044  * @ingroup math_data_structure
00045  */
00046 
00047 // Forward declarations
00048 
00049 template <class T> class N_2D_array;
00050 typedef N_2D_Array<double> N_2D_Array_d;
00051 
00052 //------------------------------------------------------------------------
00053 //----------------------------< 2D_Array Class >--------------------------
00054 //------------------------------------------------------------------------
00055 
00056 template <typename T>
00057 class N_2D_Array {
00058 
00059 public:
00060   enum SIZE_TYPE { SQUARE, 
00061                    EQUALS,
00062                    NCOLS_EQUALS_NROWS };
00063 
00064   typedef T value_type;
00065   typedef value_type* pointer;
00066   typedef const value_type* const_pointer;
00067   typedef N_2D_Array_Iterator<T> iterator;
00068   typedef N_2D_Array_const_Iterator<T> const_iterator;
00069   typedef value_type& reference;
00070   typedef const value_type& const_reference;
00071   typedef size_t size_type;
00072   typedef ptrdiff_t difference_type;
00073 
00074 protected: 
00075   // _mem_height isn't needed for any internals - it's just ept so that the
00076   // user can ask for it.
00077   int _num_of_rows, _num_of_cols, _mem_width, _mem_height;
00078 
00079   T   *_elements;
00080   T  **_index;
00081 
00082   T   *_mem_base;
00083   Reference_Count *_ref_count;
00084 
00085   bool _isSubarray;
00086 
00087 public:
00088 
00089   // Constructors - not inherited
00090   //
00091   N_2D_Array()
00092     : _num_of_rows(0), 
00093       _num_of_cols(0), 
00094       _mem_width(0), 
00095       _mem_height(0),
00096       _elements(NULL), 
00097       _index(NULL), 
00098       _mem_base(0) 
00099   {
00100     _ref_count = new Reference_Count(1);
00101     _isSubarray = false;
00102   }
00103 
00104   N_2D_Array(int n_rows, int n_cols);
00105 
00106   // This constructor can be used to build an array from a sequence, passing
00107   // in an iterator as the third argument, or to build an array from a single
00108   // element, which will be copied into every element of the array. If the
00109   // type of argument three is the same as the type T of the array, then the
00110   // value is interpreted as a "filler" value to be copied into each element,
00111   // rather than as an iterator. The specialization happens in the _copy
00112   // function, declared below.
00113   template <class In>
00114   N_2D_Array(int n_rows, int n_cols, In start) {
00115     _init(n_rows, n_cols);
00116     _copy(start);
00117     _ref_count = new Reference_Count(1);
00118   }
00119 
00120   N_2D_Array(const N_2D_Array& m);
00121 
00122   // Subarray constructor. Subarrays are shallow copies of their parents, with
00123   // windows into shared data, which is reference-counted.
00124   N_2D_Array(const N_2D_Array& parent, int left, int top, int width, int height);
00125 
00126   // Assignments - not inherited
00127   //
00128   N_2D_Array& operator=  (const T&   rhs);        // Scalar Op - not inherited
00129   N_2D_Array& operator=  (const N_2D_Array& rhs);   // Array Op - not inherited
00130 
00131   virtual ~N_2D_Array() {
00132     _ref_count->decrement();
00133     delete [] _index;
00134     if (_ref_count->get_value() == 0) {
00135       delete [] _mem_base;
00136       delete _ref_count;
00137     }
00138   }
00139 
00140   template <class In>
00141   N_2D_Array& set_diagonal(int size, In start);
00142 
00143   N_2D_Array& set_diagonal(const N_2D_Array<T>& a) {
00144     return set_diagonal(a.get_size(), a.begin());
00145   }
00146 
00147   // Return matrix dimensions
00148   //
00149   int get_size() const { return _num_of_rows*_num_of_cols; }
00150 
00151   // ncols() is a short form of the original get_num_of_cols()
00152   int ncols() const { return _num_of_cols; }
00153   int get_num_of_cols() const { return _num_of_cols; }
00154   
00155   // nrows() is a short form of the original get_num_of_rows()
00156   int nrows() const { return _num_of_rows; }
00157   int get_num_of_rows() const { return _num_of_rows; }
00158   
00159   bool is_square() const { return _num_of_rows == _num_of_cols; }
00160 
00161   // This resizes the array, destroying its contents and re-allocating the
00162   // underlying space. It cannot be used on subarrays.
00163   // This has to be inlined here, or else a bug in the sparcSol2.6-CC compiler
00164   // surfaces, and there are link errors.
00165   //  virtual void resize(int newNumRows, int newNumCols) {
00166 
00167 // had to comment virtual because it was causing warnings once we added resize function for N1D_Array: implementetion ofN1D_Array::resize hides N_2D_Array::resize. Warnings aren't generated once virtual is removed here.
00168     void resize(int newNumRows, int newNumCols) {
00169     if (_num_of_rows != newNumRows || _num_of_cols != newNumCols) {
00170       if (_isSubarray) {
00171         std::cerr << "N_2D_Array::resize cannot be used on a subarray!"
00172                   << std::endl;
00173         // throw exception
00174       } else if (_ref_count->get_value() != 1) {
00175         std::cerr << "N_2D_Array::resize cannot be used on an array being "
00176           "shared by subarrays" << std::endl;
00177         // throw exception
00178       } else if (get_size() == newNumRows * newNumCols &&
00179                  get_size() != 0) {
00180         delete [] _index;
00181         _num_of_rows = newNumRows;
00182         _num_of_cols = newNumCols;
00183         _mem_width = newNumCols;
00184         _mem_height = newNumRows;
00185         _init_index(true);
00186       } else {
00187         // total array size is different - reallocate everything. technically,
00188         // we could check the number of rows, and save a new/delete cycle on
00189         // the _index, but it's not that big of a deal if we're reallocating
00190         // the underlying data space anyway.
00191         delete [] _mem_base;
00192         delete [] _index;
00193         _init(newNumRows, newNumCols);
00194       }
00195     }
00196   }
00197 
00198   bool is_subarray() const { return _isSubarray; }
00199 
00200   // Iterator creators
00201   iterator begin() {
00202     return iterator(_elements, _is_noncontiguous(), _num_of_cols, _mem_width);
00203   }
00204   const_iterator begin() const {
00205     return const_iterator(_elements, _is_noncontiguous(), _num_of_cols,
00206                           _mem_width);
00207   }
00208   iterator end() {
00209     return iterator(_elements + _num_of_rows * _mem_width,
00210                     _is_noncontiguous(), _num_of_cols, _mem_width);
00211   }
00212   const_iterator end() const {
00213     return const_iterator(_elements + _num_of_rows * _mem_width,
00214                           _is_noncontiguous(), _num_of_cols, _mem_width);
00215   }
00216 
00217   // Subarray manipulation functions. These are not range-checked or
00218   // bounds-checked, so be sure you know your "parent" array dimensions before
00219   // changing the size or location of a subarray.
00220   
00221   // Move the subarray window into the parent array by the given
00222   // offset. Returns *this.
00223   N_2D_Array& displace_subarray(int delta_x, int delta_y);
00224 
00225   // Change the size and/or location of the subarray window into the
00226   // parent. Note that this sets the window with respect to the topmost parent
00227   // array (i.e. the actual memory buffer), which may not be the array that
00228   // this was created from. Returns *this.
00229   N_2D_Array& resize_subarray(int left, int top, int width, int height);
00230 
00231   // Makes this array a sub-array of another array. This can only be done on
00232   // arrays that have size zero (that have been built with the default
00233   // constructor or with initial size 0, 0) -- typically this isn't necessary,
00234   // since one can use the subarray constructor directly.
00235   N_2D_Array& associate_subarray(const N_2D_Array& parent,
00236                                int left, int top, int width, int height);
00237 
00238   // Returns the width (number of columns) of the topmost parent array.
00239   int get_full_num_cols() const { return _mem_width; }
00240   // Returns the height (number of rows) of the topmost parent array.
00241   int get_full_num_rows() const { return _mem_height; }
00242 
00243   // Dissociate relationship with shared memory block or parent if a
00244   // subarray and create a new memory block.  If the optional
00245   // arguments are specified they will be used for the new dimensions,
00246   // otherwise the dimensions will be kept the same as they were
00247   // before.  If the new size is the same as the old size and the
00248   // memory block is not shared, this does nothing.  Either way, it is
00249   // guaranteed after this operation that the memory will not be
00250   // shared.
00251   void dissociate(int new_nrows=-1, int new_ncols=-1) {
00252     int nrows = new_nrows, ncols = new_ncols;
00253     if(nrows < 0) {
00254       nrows = _num_of_rows;
00255     }
00256     if(ncols < 0) {
00257       ncols = _num_of_cols;
00258     }
00259     
00260     if (_isSubarray) {
00261       _isSubarray = false;
00262       _num_of_rows = 0;    // force re-allocation / compaction
00263       _num_of_cols = 0;
00264     }
00265     if (_ref_count->get_value() != 1) {
00266       _ref_count->decrement();
00267       _mem_base = 0;    // to prevent destruction of shared space on resize
00268       _num_of_rows = 0; // force re-allocation
00269       _num_of_cols = 0;
00270       _ref_count = new Reference_Count(1);  // get an independent reference count
00271     }
00272     // Resize if necessary
00273     if((nrows != _num_of_rows) || (ncols != _num_of_cols)) {
00274       resize(nrows, ncols);
00275     }
00276   }
00277 
00278 
00279   // Return rows and cols
00280   N_2D_Array<T> get_row(int row) const;
00281   N_2D_Array<T> get_col(int col) const;
00282 
00283   const T *get_row_pointer(int row) const { return _index[row]; }
00284   
00285   iterator column_iterator(int col) {
00286     return iterator(_elements + col, true, 1, _mem_width);
00287   }
00288   const_iterator column_iterator(int col) const {
00289     return const_iterator(_elements + col, true, 1, _mem_width);
00290   }
00291   
00292 
00293   // Indexing for read and write operations. Using the _index is 2.5 times
00294   // faster than using the _elements[r*_num_of_cols+c].
00295   //
00296   T& operator()(int r, int c) { return _index[r][c]; }
00297   const T& operator()(int r, int c) const { return _index[r][c]; }
00298 
00299   // more explicit indexing operators, to keep order of operations from
00300   // getting confused
00301   T& rc(int row, int column) { return operator()(row, column); }
00302   const T& rc(int row, int column) const { return operator()(row, column); }
00303 
00304   T& xy(int x, int y) { return operator()(y, x); }
00305   const T& xy(int x, int y) const { return operator()(y, x); }
00306 
00307   T& xy(const N_2D_Point_i &p) { return xy(p.x(), p.y()); }
00308   const T& xy(const N_2D_Point_i &p) const { return xy(p.x(), p.y()); }
00309   
00310   // Writes the whole array to the stream (operator<< only writes the
00311   // first 10 rows and columns).
00312   void write(std::ostream& os) const;
00313 
00314   // Conversion operators
00315   //
00316   // bool operator (see function definition)
00317  
00318   operator void *() const;              
00319 
00320   // N_2D_Array operations
00321   //
00322   N_2D_Array operator== (const N_2D_Array& rhs) const;       // Array Op
00323   N_2D_Array transpose() const;             
00324 
00325   bool io(FDM_Map map);
00326 
00327 protected: 
00328   // This is a dangerous operation, which will definately fail on subarrays,
00329   // and is only provided for quick element lookup, when you know doing this
00330   // will do the right thing.
00331   T& element(int i) { return _elements[i]; }
00332   const T& element(int i) const { return _elements[i]; }
00333 
00334   // this is evil, but may be necessary to avoid unnecessary double allocation
00335   // on large block copies (like image grabs from framegrabbers)
00336   T *get_data() { assert(!is_subarray()); return _mem_base; }
00337   const T *get_data() const { assert(!is_subarray()); return _mem_base; }
00338 
00339 protected: 
00340 
00341   template <class In>
00342   void    _copy         (In start);         // copy from sequence
00343 
00344   void    _copy         (T filler);  // fill array with filler
00345 
00346   template <class rhsType>
00347   int     _check_size   (SIZE_TYPE type, const N_2D_Array<rhsType>& rhs) const;
00348 
00349   // For subclasses that do their own memory management, these functions are
00350   // provided to short-circuit the allocation and deallocation of the
00351   // _elements array. The _init_special function allows the subclass to set
00352   // the pointers to reasonable values (so that the _index can be created
00353   // correctly), while allowing allocation to be skipped.
00354   void _init_special(int nr, int nc, T *data, int memwidth);
00355   void _drop_memory() {
00356     _elements = NULL;
00357     _mem_base = NULL;
00358   }
00359 
00360   // it's helpful for derived classes to have access to these (e.g. for resize f-n)
00361 //private:
00362   void    _init         (int n_rows, int n_cols);
00363   void    _init_index(bool allocate = true);
00364 
00365   // returns true if the elements of the array are in noncontiguous memory
00366   // (i.e. this is a subarray which doesn't span the width of the parent).
00367   bool _is_noncontiguous() const {
00368     return _num_of_cols != _mem_width;
00369   }
00370 };
00371 //------------------------------------------------------------------------
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 //------------------------------------------------------------------------- 
00383 //---------------------< N_2D_Array Member Functions >-----------------------
00384 //------------------------------------------------------------------------- 
00385 
00386 template <class T>
00387 void N_2D_Array<T>::_init_special(int n_rows, int n_cols, T *data, int memwidth)
00388 {
00389   _num_of_rows = n_rows;
00390   _num_of_cols = n_cols;
00391   _mem_width = memwidth;
00392 
00393   _elements = data;
00394   _mem_base = data;
00395 
00396   _init_index();
00397 }
00398 
00399 template <class T>
00400 void N_2D_Array<T>::_init(int n_rows, int n_cols)
00401 {
00402   // Allocate contiguous space for all the elements in the array.
00403 
00404   // Init only gets called on non-subarray
00405   _isSubarray = false;
00406 
00407   _num_of_rows = n_rows;
00408   _num_of_cols = n_cols;
00409   _mem_width = _num_of_cols;
00410   _mem_height = _num_of_rows;
00411 
00412   if (n_rows==0 || n_cols==0) {
00413     _elements = NULL;
00414     _mem_base = NULL;
00415     _index = NULL;
00416     return; 
00417   }
00418 
00419   _mem_base = new T[n_rows*n_cols];
00420   _elements = _mem_base;
00421 
00422   // Copy pointer to the beginning of every row into index pointer array
00423   //
00424   _init_index();
00425 }
00426 //------------------------------------------------------------------------- 
00427 
00428 template <class T>
00429 void N_2D_Array<T>::_init_index(bool allocate)
00430 {
00431   // Allocate memory for the row pointers. These are needed to address the 
00432   // individual elements of the matrix using the index **
00433   
00434   typedef T* p_T;
00435 
00436   if (allocate)
00437     _index = new p_T[_num_of_rows];
00438 
00439   // Initialize index vector that points to the beginning of every row
00440   int i;
00441   T *p_row;
00442   for (i = 0, p_row = _elements; i < _num_of_rows; i++, p_row += _mem_width)
00443     _index[i]= p_row;
00444 }
00445 //------------------------------------------------------------------------- 
00446 template <class T>
00447 template <class In>
00448 void N_2D_Array<T>::_copy(In start)
00449 {
00450   if (is_subarray()) {
00451     iterator it = begin(), last = end();
00452     for (; it != last; ++it, ++start)
00453       *it = (int)*start; // compiler warning *it is an int
00454   } else {
00455     T *it = _elements, *last = _elements + _num_of_rows * _num_of_cols;
00456     for (; it != last; ++it, ++start)
00457       *it = (int)*start; // compiler waring *it is an int
00458   }    
00459 }
00460 //-------------------------------------------------------------------------
00461 
00462 template <class T>
00463 void N_2D_Array<T>::_copy(T filler)
00464 {
00465   iterator it = begin(), last = end();
00466   for (; it != last; ++it)
00467     *it = filler;
00468 }
00469 
00470 //-------------------------------------------------------------------------
00471 // CONSTRUCTORS
00472 //-------------------------------------------------------------------------
00473 
00474 
00475 template <class T>
00476 N_2D_Array<T>::N_2D_Array(int num_of_rows, int num_of_cols)
00477 {
00478   // elements are created using the default constructor (so may have undefined
00479   // values)
00480   _init(num_of_rows, num_of_cols);
00481   _ref_count = new Reference_Count(1);
00482 }
00483 //-------------------------------------------------------------------------
00484 
00485 template <class T>
00486 N_2D_Array<T>::N_2D_Array(const N_2D_Array& m)
00487 {
00488   _init(m._num_of_rows, m._num_of_cols);
00489   if (m.is_subarray())
00490     _copy(m.begin());
00491   else
00492     _copy(m._elements);
00493   _ref_count = new Reference_Count(1);
00494 
00495   // cout << "N_2D_Array constructor N_2D_Array(const N_2D_Array&)" << std::endl;
00496 }
00497 //-------------------------------------------------------------------------
00498 
00499 template <class T>
00500 N_2D_Array<T>::N_2D_Array(const N_2D_Array& parent, int left, int top, int width,
00501                       int height)
00502   : _num_of_rows(height), _num_of_cols(width),
00503     _mem_width(parent._mem_width), _mem_height(parent._mem_height),
00504     _mem_base(parent._mem_base), _ref_count(parent._ref_count)
00505 {
00506   _isSubarray = true;
00507   _ref_count->increment();
00508   _elements = parent._elements + top * _mem_width + left;
00509   _init_index();
00510 }
00511 
00512 //-------------------------------------------------------------------------
00513 
00514 template <class T>
00515 template <class In>
00516 N_2D_Array<T>& N_2D_Array<T>::set_diagonal(int size, In start) 
00517 {
00518   if (!is_square()) 
00519     std::cerr << "matrix error: cannot set diagonal on a non-square matrix"
00520               << std::endl;
00521   else if (size!=_num_of_cols) 
00522     std::cerr << "matrix error: number of diagonal elements (" << size << ") "
00523               << "is not the same as matrix dimension of " << _num_of_cols
00524               << std::endl;
00525   else 
00526     for (int i = 0; i < _num_of_cols; ++i, ++start)
00527       operator()(i, i) = *start;
00528   return *this;
00529 }
00530 
00531 //-------------------------------------------------------------------------
00532 
00533 template <class T>
00534 N_2D_Array<T>& N_2D_Array<T>::displace_subarray(int delta_x, int delta_y)
00535 {
00536   if (!_isSubarray) { // @@ This should throw an exception
00537     std::cerr << "N_2D_Array::displace_subarray requires *this to be a subarray!"
00538          << std::endl;
00539     return *this;
00540   }
00541   size_t offset = delta_y * _mem_width + delta_x;
00542   _elements += offset;
00543   for (int i = 0; i < _num_of_rows; i++)
00544     _index[i] += offset;
00545   return *this;
00546 }
00547 //-------------------------------------------------------------------------
00548 
00549 template <class T>
00550 N_2D_Array<T>& N_2D_Array<T>::resize_subarray(int left, int top,
00551                                           int width, int height)
00552 {
00553   if (!_isSubarray) { // @@ This should throw an exception
00554     std::cerr << "N_2D_Array::resize_subarray requires *this to be a subarray!"
00555          << std::endl;
00556     return *this;
00557   }
00558   _num_of_cols = width;
00559   _elements = _mem_base + top * _mem_width + left;
00560   if (height == _num_of_rows) {
00561     // same number of rows - don't reallocate the _index
00562     _init_index(false);
00563   } else {
00564     _num_of_rows = height;
00565     delete [] _index;
00566     _init_index();
00567   }
00568   return *this;
00569 }
00570 //-------------------------------------------------------------------------
00571 
00572 template <class T>
00573 N_2D_Array<T>& N_2D_Array<T>::associate_subarray(const N_2D_Array& parent,
00574                                              int left, int top,
00575                                              int width, int height)
00576 {
00577   if (_isSubarray || _elements != NULL || _index != NULL) {
00578     std::cerr << "N_2D_Array::associate_subarray: this function can only be used "
00579       "on uninitialized arrays" << std::endl;
00580     return *this;
00581   }
00582   delete _ref_count;
00583   _ref_count = parent._ref_count;
00584   _ref_count->increment();
00585   _isSubarray = true;
00586 
00587   _num_of_rows = height;
00588   _num_of_cols = width;
00589   _mem_width = parent._mem_width;
00590   _mem_height = parent._mem_height;
00591   _mem_base = parent._mem_base;
00592   _elements = parent._elements + top * _mem_width + left;
00593   _init_index();
00594   return *this;
00595 }
00596 
00597 //-------------------------------------------------------------------------
00598 
00599 template <class T>
00600 N_2D_Array<T> N_2D_Array<T>::get_row(int row) const
00601 {
00602   if (row < 0 || row > _num_of_rows) {
00603     std::cerr << "array error: row " << row << " exceeds matrix number of rows = " 
00604          <<  _num_of_cols << std::endl;
00605     return N_2D_Array<T>();
00606   }
00607   else 
00608     return N_2D_Array<T>(1, _num_of_cols, _index[row]);
00609 }
00610 //-------------------------------------------------------------------------
00611 
00612 template <class T>
00613 N_2D_Array<T> N_2D_Array<T>::get_col(int col) const
00614 {
00615   if (col < 0 || col > _num_of_cols) {
00616     std::cerr << "array error: col " << col << " exceeds matrix number of columns = " 
00617          <<  _num_of_cols << std::endl;      
00618     return N_2D_Array<T>();
00619   }
00620   else {
00621     N_2D_Array<T> col_array(_num_of_rows, 1);
00622     for (int row = 0; row < _num_of_rows; row++)
00623       col_array(row, 0) = operator()(row, col);
00624     return col_array;
00625   }
00626 }
00627 //-------------------------------------------------------------------------
00628 
00629 template <class T>
00630 N_2D_Array<T>::operator void *() const
00631 {
00632   // Bool operator but using void * instead to avoid direct conversion to int
00633   // so when you type 3*array, you do not get 3, rather you get a compile error
00634 
00635   for (const_iterator it = begin(); it != end(); ++it)
00636     if (*it == 0)
00637       return (void *)false;
00638   return (void *)true;
00639 }
00640 //-------------------------------------------------------------------------
00641 
00642 template <class T>
00643 N_2D_Array<T>& N_2D_Array<T>::operator=(const T& filler)
00644 {
00645   _copy(filler);
00646   return *this;
00647 }
00648 //-------------------------------------------------------------------------
00649 
00650 template <class T>
00651 N_2D_Array<T>& N_2D_Array<T>::operator=(const N_2D_Array& rhs)
00652 {
00653   if (this == &rhs) return *this;
00654   
00655   resize(rhs.get_num_of_rows(), rhs.get_num_of_cols());
00656 
00657   _copy(rhs.begin());
00658 
00659   return *this;
00660 }
00661 //-------------------------------------------------------------------------
00662 // RETURNS OBJECT
00663 
00664 template <class T> 
00665 N_2D_Array<T> N_2D_Array<T>::transpose() const
00666 { 
00667   N_2D_Array tmp(_num_of_cols, _num_of_rows);
00668   iterator it_tmp = tmp.begin();
00669   for (int i = 0; i < _num_of_cols; ++i) 
00670     for (int j = 0; j < _num_of_rows; ++j, ++it_tmp)
00671       *it_tmp = operator()(j, i);
00672   return tmp;
00673 }
00674 //-------------------------------------------------------------------------
00675 // RETURNS OBJECT
00676 
00677 template <class T> 
00678 N_2D_Array<T> N_2D_Array<T>::operator==(const N_2D_Array& rhs) const 
00679 { 
00680   if (this == &rhs) return N_2D_Array(_num_of_rows, _num_of_cols, (T)true); 
00681 
00682   if (_check_size(EQUALS, rhs) == ERROR) {
00683     // MUST THROW AN EXCEPTION HERE, BUT FOR NOW
00684     return N_2D_Array(1, 1, (T)false);
00685   }
00686 
00687   N_2D_Array result(_num_of_rows, _num_of_cols);
00688   const_iterator it_lhs = begin(), it_rhs = rhs.begin();
00689   iterator it_res = result.begin();
00690   for (int i = 0; i < get_size(); ++i, ++it_lhs, ++it_rhs, ++it_res) 
00691     *it_res = (*it_lhs == *it_rhs);
00692   return result;
00693 }
00694 //-------------------------------------------------------------------------
00695 
00696 template <class T>
00697 void N_2D_Array<T>::write(std::ostream& os) const
00698 {
00699   std::ios::fmtflags oldBase;
00700   int oldPrecision;
00701 
00702   os << "size: (" << get_num_of_rows() << ", " << get_num_of_cols()
00703      << " )" << std::endl;
00704   os.setf(std::ios::showpoint);
00705 
00706   if (sizeof(T)==1) {
00707     oldBase = os.setf(std::ios::hex, std::ios::basefield);
00708   } 
00709   else {
00710     oldPrecision = os.precision();
00711     os.precision(4);
00712   }
00713 
00714   if (get_num_of_cols() != 0)
00715     for (int i = 0; i < get_num_of_rows(); ++i) {
00716       os << "[ ";
00717       for (int j = 0; j < get_num_of_cols(); ++j) {
00718         const T& el = rc(i, j);
00719         os << " " << std::setw(8) << el;
00720       }
00721       os << " ]" << std::endl;
00722     }
00723   if (sizeof(T)==1) 
00724     os.setf(oldBase, std::ios::basefield);
00725   else
00726     os.precision(oldPrecision);
00727 }
00728 
00729 //-------------------------------------------------------------------------
00730 
00731 template <class T>
00732 std::ostream& operator<<(std::ostream& os, const N_2D_Array<T>& m)
00733 {
00734   std::ios::fmtflags oldBase;
00735   int oldPrecision;
00736 
00737   os << "size: (" << m.get_num_of_rows() << ", " << m.get_num_of_cols()
00738      << " )" << std::endl;
00739 
00740   os.setf(std::ios::showpoint);
00741 
00742   if (sizeof(T)==1) {
00743     oldBase = os.setf(std::ios::hex, std::ios::basefield);
00744   } 
00745   else {
00746     oldPrecision = os.precision();
00747     os.precision(4);
00748   }
00749 
00750   if (m.get_num_of_cols() != 0)
00751     for (int i = 0; i < cl_min(10, m.get_num_of_rows()); ++i) {
00752       os << "[ ";
00753       for (int j = 0; j < cl_min(10, m.get_num_of_cols()); ++j) {
00754         const T& el = m(i, j);
00755         os << " " << std::setw(8) << ((sizeof(T)==1) ? (int)el : el);
00756       }
00757       os << " ]" << std::endl;
00758     }
00759   if (sizeof(T)==1) 
00760     os.setf(oldBase, std::ios::basefield);
00761   else
00762     os.precision(oldPrecision);
00763 
00764   return os;
00765 }
00766 //-------------------------------------------------------------------------
00767 
00768 template <class T>
00769 template <class rhsType>
00770 int N_2D_Array<T>::_check_size (SIZE_TYPE operation, 
00771                               const N_2D_Array<rhsType>& rhs) const
00772 {
00773   int status = ERROR;
00774 
00775   switch (operation) {
00776   case EQUALS:
00777     status = ((_num_of_rows == rhs.get_num_of_rows()) &&
00778               (_num_of_cols == rhs.get_num_of_cols())) ? OK : ERROR;
00779     break;
00780   case NCOLS_EQUALS_NROWS:
00781     status = (_num_of_cols == rhs.get_num_of_rows()) ? OK : ERROR; 
00782     break;
00783   case SQUARE:
00784     status = (_num_of_rows == _num_of_cols)  ? OK : ERROR;
00785     break;
00786   } // switch
00787 
00788   if (status==ERROR) 
00789     std::cerr << "Array 2D error: array dimensions do not match lhs(" << _num_of_rows 
00790          << "x" << _num_of_cols << "), rhs (" << rhs.get_num_of_rows() << "x" 
00791          << rhs.get_num_of_cols() << ")" << std::endl;
00792 
00793   return status;
00794 }
00795 //-------------------------------------------------------------------------
00796 
00797 // i/o flattens an array - subarrays are written just like
00798 // non-shared-memory arrays, and loading into an array always
00799 // repackages the object into its own proper memory space.  It is
00800 // broken up into multiple calls in order to allow subclasses to put
00801 // fields in the same map node.  Note that unlike normal io_object
00802 // routines these use a reference for the node, and should be used
00803 // with care.
00804 template <typename T>
00805 bool N_2D_Array<T>::
00806 io(FDM_Map map)
00807 {
00808   int nr = nrows(), nc = ncols();
00809 
00810   bool ok = true;
00811 
00812   ok &= map.field("nrows", nr);
00813   ok &= map.field("ncols", nc);
00814 
00815   // If we're reading, dissociate from any sharing and set to the new
00816   // size.  If the memory isn't shared and the size hasn't changed,
00817   // this does nothing.
00818   if (map.is_read()) {
00819     dissociate(nr, nc);
00820   }
00821 
00822   FDM_Array a = map.field_node("elements");
00823 
00824   for (int r = 0; r < nr; r++)
00825     for (int c = 0; c < nc; c++)
00826       ok &= a.element(_index[r][c]);
00827   
00828   return ok;
00829 }
00830 //------------------------------------------------------------------------
00831 
00832 template <typename T>
00833 bool io_object(FDM_Untyped_Node node, N_2D_Array<T>& rhs)
00834 {
00835   FDM_Map map(node);
00836 
00837   return(rhs.io(map, rhs));
00838 }
00839 //------------------------------------------------------------------------
00840 
00841 } // namespace claraty
00842 
00843 #endif // N_2D_ARRAY_H