nec2++  1.7.0
safe_array.h
1 /*
2  Copyright (C) 2004-2013,2015 Timothy C.A. Molteno
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  aint32_t with this program; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #ifndef __safe_array__
19 #define __safe_array__
20 
21 #include <iostream>
22 #include <cstring>
23 #include <sstream>
24 #include <stdint.h>
25 
26 #include "nec_exception.h"
27 
28 #ifdef NEC_ERROR_CHECK
29 
30 
31 class BoundsViol : public nec_exception {
32 public:
33  BoundsViol(const char* message, int64_t index, int64_t bound)
34  : nec_exception(message)
35  {
36  m_message << "array index: " << index << " exceeds " << bound << std::endl;
37  }
38 };
39 #endif
40 
47 template<typename T>
48 class safe_array {
49 public:
50  safe_array()
51  : len_(0), rows_(0), cols_(0), resize_chunk_(2), data_(NULL), data_size_(0), own_data_(true)
52  { }
53 
54  safe_array(int64_t in_size)
55  : len_(0), rows_(0), cols_(0), resize_chunk_(2), data_(NULL), data_size_(0), own_data_(true)
56  {
57  resize(in_size);
58  }
59 
60  safe_array(const safe_array<T>& in_array)
61  : len_(0), rows_(0), cols_(0), resize_chunk_(2), data_(NULL), data_size_(0), own_data_(true)
62  {
63  copy(in_array);
64  }
65 
66  ~safe_array() {
67  if (own_data_) {
68  delete[] data_;
69  data_ = NULL;
70  }
71  }
72 
73 
74  int64_t size() const {
75  return len_;
76  }
77 
78  int32_t rows() const {
79  return rows_;
80  }
81 
82  int32_t cols() const {
83  return cols_;
84  }
85 
86  int64_t capacity() const {
87  return data_size_;
88  }
89 
90  void resize(int32_t n_rows, int32_t n_cols) {
91  rows_ = n_rows;
92  cols_ = n_cols;
93 
94  resize(rows_ * cols_);
95  }
96 
97  // Copy the contents of in_array to our array
98  // resizing as appropriate.
99  void copy(const safe_array<T>& in_array) {
100  if (in_array.rows_ == 0)
101  resize(in_array.len_);
102  else
103  resize(in_array.rows_,in_array.cols_);
104 
105  for (int64_t i=0; i<len_; i++)
106  data_[i] = in_array[i];
107  }
108 
109 
110  void resize(int64_t new_length) {
111 #ifdef NEC_ERROR_CHECK
112  if (! own_data_)
113  throw new nec_exception("attempt to resize data we do not own");
114 #endif
115  if (new_length > data_size_) {
116  // We allocate resize_chunk_ more bytes than we need to avoid
117  // resizing too often.
118  data_size_ = new_length + resize_chunk_;
119  try {
120  T* new_data_ = new T[data_size_];
121  if (0 != len_)
122  std::memcpy(new_data_, data_, len_ * sizeof(T));
123 
124  delete[] data_;
125  data_ = new_data_;
126  } catch (std::bad_alloc& ba) {
127  throw new nec_exception("Error: Out of Memory ");
128  }
129  }
130  len_ = new_length;
131  }
132 
134  T maxCoeff() const {
135  if (0 == len_)
136  throw new nec_exception("No elements in maxCoeff");
137 
138  T ret = data_[check(0)];
139 
140  for (int64_t i = 1; i < len_; i++ ) {
141  if ( data_[check(i)] > ret)
142  ret = data_[check(i)];
143  }
144  return ret;
145  }
146 
148  T minCoeff() const {
149  if (int64_t(0) == len_)
150  throw new nec_exception("No elements in minCoeff");
151 
152  T ret = data_[check(0)];
153 
154  for (int64_t i = 1; i < len_; i++ ) {
155  if ( data_[check(i)] < ret)
156  ret = data_[check(i)];
157  }
158  return ret;
159  }
160 
162  T sum(int64_t start_index, int64_t stop_index) {
163  T ret = data_[check(start_index)];
164 
165  for (int64_t i = start_index+1; i < stop_index; i++ ) {
166  ret += data_[check(i)];
167  }
168  return ret;
169  }
170 
172  T sum() {
173  return sum(0,len_);
174  }
175 
176  // fill specified elements of the array with x
177  void fill(int64_t start, int64_t N, const T& x) {
178  int64_t stop = start + N;
179  for (int64_t i = start; i < stop; i++ ) {
180  data_[check(i)] = x;
181  }
182  }
183 
184  // fill all elements of the array with x
185  void setConstant(const T& x) {
186  fill(0,len_,x);
187  }
188 
191  void set_col_major(int32_t col_dim, int32_t col, int32_t row, const T& val) {
192  data_[check(row*col_dim + col)] = val;
193  }
194 
197  T& get_col_major(int32_t col_dim, int32_t col, int32_t row) {
198  return data_[check(row*col_dim + col)];
199  }
200 
201 
205  T& getItem(int32_t row, int32_t col) {
206  return data_[check(row,col)];
207  }
208 
209 
213  T& operator()(int32_t row, int32_t col) {
214  return getItem(row, col);
215  }
216 
217  const T& operator()(int32_t row, int32_t col) const {
218  return data_[check(row,col)];
219  }
220 
221  /* \brief An accessor method to help with wrapping the C++ objects
222  * into other languages (like python, ruby)
223  */
224  T& getItem(int64_t i) {
225  return data_[check(i)];
226  }
227 
228  const T& operator[](int64_t i) const {
229  return data_[check(i)];
230  }
231 
232  T& operator[](int64_t i) {
233  return getItem(i);
234  }
235 
240  safe_array<T> segment(int64_t start_index, int64_t end_index) {
241  if (int64_t(-1) == end_index)
242  throw "foo";
243  return safe_array<T>(*this, start_index, end_index, false);
244  }
245 
250  safe_array<T> eigen_segment(int64_t start_index, int64_t n) {
251  int64_t end_index = start_index + n;
252  return safe_array<T>(*this, start_index, end_index, false);
253  }
254 
255 
256  T* data() const {
257  return data_;
258  }
259 
260  safe_array<T>& operator=(const safe_array<T>& in_array) {
261  copy(in_array);
262  return *this;
263  }
264 
265 
266 protected:
267  int64_t len_;
268  int32_t rows_;
269  int32_t cols_;
270  int64_t resize_chunk_;
271 
272  T* data_;
273  int64_t data_size_;
274 
275  bool own_data_;
276 
282  safe_array(const safe_array<T>& in_array, int64_t start_index, int64_t end_index, bool in_copy_data)
283  {
284  resize_chunk_ = in_array.resize_chunk_;
285  len_ = (end_index - start_index)+1; // include the end_index element
286  rows_ = 0;
287  cols_ = 0;
288 
289  if (in_copy_data) {
290  data_ = new T[len_];
291  data_size_ = len_;
292 
293  for (int64_t i=0; i<len_; i++)
294  data_[check(i)] = in_array[start_index + i];
295 
296  own_data_ = true;
297  } else {
298  data_ = in_array.data() + start_index;
299  data_size_ = 0;
300  own_data_ = false;
301  }
302  }
303 
304  inline int64_t check(int64_t i) const {
305 #ifdef NEC_ERROR_CHECK
306  if (i < 0 || i >= len_)
307  throw new BoundsViol("safe_array: ", i, len_);
308 #endif
309  return i;
310  }
311 
312  inline int64_t check(int32_t row, int32_t col) const {
313 #ifdef NEC_ERROR_CHECK
314  if (row < 0 || row >= rows_)
315  throw new BoundsViol("safe_array: ", row, rows_);
316  if (col < 0 || col >= cols_)
317  throw new BoundsViol("safe_array: ", col, cols_);
318 #endif
319  return check(int64_t(col)*rows_ + row);
320  }
321 };
322 
323 
324 template<typename T>
325 class safe_matrix : public safe_array<T> {
326 public:
327  safe_matrix(int32_t _rows, int32_t _cols) : safe_array<T>(_rows*_cols) {
328  this->resize(_rows, _cols);
329  }
331  { }
332 
333 
334 private:
335  using safe_array<T>::operator[]; /* Stop folk from using square bracket indexing */
336 
337 };
338 
339 #endif /* __safe_array__ */
T & operator()(int32_t row, int32_t col)
Definition: safe_array.h:213
T sum(int64_t start_index, int64_t stop_index)
return the sum of the specified elements in the array
Definition: safe_array.h:162
T minCoeff() const
return the largest element of the array
Definition: safe_array.h:148
Definition: safe_array.h:325
Definition: nec_exception.h:28
safe_array(const safe_array< T > &in_array, int64_t start_index, int64_t end_index, bool in_copy_data)
Constructor only used to construct segment.
Definition: safe_array.h:282
T & get_col_major(int32_t col_dim, int32_t col, int32_t row)
Get an element assuming that the data is stored in column major form.
Definition: safe_array.h:197
safe_array< T > segment(int64_t start_index, int64_t end_index)
Return a representation of a subset of this array.
Definition: safe_array.h:240
T maxCoeff() const
return the largest element of the array
Definition: safe_array.h:134
safe_array< T > eigen_segment(int64_t start_index, int64_t n)
Return a representation of a subset of this array.
Definition: safe_array.h:250
A Safe Array class for nec2++ that performs bounds checking.
Definition: safe_array.h:48
T & getItem(int32_t row, int32_t col)
Definition: safe_array.h:205
void set_col_major(int32_t col_dim, int32_t col, int32_t row, const T &val)
Set an element assuming that the data is stored in column major form.
Definition: safe_array.h:191
T sum()
return the sum of all elements in the array
Definition: safe_array.h:172