00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00045
00046
00047
00048
00049 template <class T> class N_2D_array;
00050 typedef N_2D_Array<double> N_2D_Array_d;
00051
00052
00053
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
00076
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
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
00107
00108
00109
00110
00111
00112
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
00123
00124 N_2D_Array(const N_2D_Array& parent, int left, int top, int width, int height);
00125
00126
00127
00128 N_2D_Array& operator= (const T& rhs);
00129 N_2D_Array& operator= (const N_2D_Array& rhs);
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
00148
00149 int get_size() const { return _num_of_rows*_num_of_cols; }
00150
00151
00152 int ncols() const { return _num_of_cols; }
00153 int get_num_of_cols() const { return _num_of_cols; }
00154
00155
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
00162
00163
00164
00165
00166
00167
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
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
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
00188
00189
00190
00191 delete [] _mem_base;
00192 delete [] _index;
00193 _init(newNumRows, newNumCols);
00194 }
00195 }
00196 }
00197
00198 bool is_subarray() const { return _isSubarray; }
00199
00200
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
00218
00219
00220
00221
00222
00223 N_2D_Array& displace_subarray(int delta_x, int delta_y);
00224
00225
00226
00227
00228
00229 N_2D_Array& resize_subarray(int left, int top, int width, int height);
00230
00231
00232
00233
00234
00235 N_2D_Array& associate_subarray(const N_2D_Array& parent,
00236 int left, int top, int width, int height);
00237
00238
00239 int get_full_num_cols() const { return _mem_width; }
00240
00241 int get_full_num_rows() const { return _mem_height; }
00242
00243
00244
00245
00246
00247
00248
00249
00250
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;
00263 _num_of_cols = 0;
00264 }
00265 if (_ref_count->get_value() != 1) {
00266 _ref_count->decrement();
00267 _mem_base = 0;
00268 _num_of_rows = 0;
00269 _num_of_cols = 0;
00270 _ref_count = new Reference_Count(1);
00271 }
00272
00273 if((nrows != _num_of_rows) || (ncols != _num_of_cols)) {
00274 resize(nrows, ncols);
00275 }
00276 }
00277
00278
00279
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
00294
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
00300
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
00311
00312 void write(std::ostream& os) const;
00313
00314
00315
00316
00317
00318 operator void *() const;
00319
00320
00321
00322 N_2D_Array operator== (const N_2D_Array& rhs) const;
00323 N_2D_Array transpose() const;
00324
00325 bool io(FDM_Map map);
00326
00327 protected:
00328
00329
00330
00331 T& element(int i) { return _elements[i]; }
00332 const T& element(int i) const { return _elements[i]; }
00333
00334
00335
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);
00343
00344 void _copy (T filler);
00345
00346 template <class rhsType>
00347 int _check_size (SIZE_TYPE type, const N_2D_Array<rhsType>& rhs) const;
00348
00349
00350
00351
00352
00353
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
00361
00362 void _init (int n_rows, int n_cols);
00363 void _init_index(bool allocate = true);
00364
00365
00366
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
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
00403
00404
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
00423
00424 _init_index();
00425 }
00426
00427
00428 template <class T>
00429 void N_2D_Array<T>::_init_index(bool allocate)
00430 {
00431
00432
00433
00434 typedef T* p_T;
00435
00436 if (allocate)
00437 _index = new p_T[_num_of_rows];
00438
00439
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;
00454 } else {
00455 T *it = _elements, *last = _elements + _num_of_rows * _num_of_cols;
00456 for (; it != last; ++it, ++start)
00457 *it = (int)*start;
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
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
00479
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
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) {
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) {
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
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
00633
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
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
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
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 }
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
00798
00799
00800
00801
00802
00803
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
00816
00817
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 }
00842
00843 #endif // N_2D_ARRAY_H