nec2++ 2.1.1
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 with
15 this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18#pragma once
19
20#include <iostream>
21#include <cstring>
22#include <sstream>
23#include <stdint.h>
24#include <Eigen/Dense>
25
26#include "nec_exception.h"
27
28/* BoundsViol is always defined so that the throw target is consistent
29 across translation units, regardless of NEC_ERROR_CHECK. */
30class BoundsViol : public nec_exception {
31public:
32 BoundsViol(const char* message, int64_t index, int64_t bound)
33 : nec_exception(message)
34 {
35 m_message << "array index: " << index << " exceeds " << bound << std::endl;
36 }
37};
38
46template<typename T>
48public:
49 using Vector = Eigen::Matrix<T, Eigen::Dynamic, 1>;
50
52 : _len(0), _rows(0), _cols(0), _capacity(0), _resize_chunk(2),
53 _view_ptr(nullptr), _own_data(true)
54 { }
55
56 safe_array(int64_t in_size)
57 : _len(0), _rows(0), _cols(0), _capacity(0), _resize_chunk(2),
58 _view_ptr(nullptr), _own_data(true)
59 {
60 resize(in_size);
61 }
62
63 safe_array(const safe_array<T>& in_array)
64 : _len(0), _rows(0), _cols(0), _capacity(0), _resize_chunk(2),
65 _view_ptr(nullptr), _own_data(true)
66 {
67 copy(in_array);
68 }
69
70 ~safe_array() { /* Eigen::Matrix destructor handles cleanup */ }
71
72 int64_t size() const { return _len; }
73 int64_t rows() const { return _rows; }
74 int64_t cols() const { return _cols; }
75 int64_t capacity() const { return _own_data ? _capacity : _len; }
76
77 void resize(int64_t n_rows, int64_t n_cols) {
78 _rows = n_rows;
79 _cols = n_cols;
80 resize(_rows * _cols);
81 }
82
83 void copy(const safe_array<T>& in_array) {
84 if (in_array._rows == 0)
85 resize(in_array._len);
86 else
87 resize(in_array._rows, in_array._cols);
88 _storage.head(_len) = in_array._eigen_view();
89 }
90
91 void resize(int64_t new_length) {
92#ifdef NEC_ERROR_CHECK
93 if (!_own_data)
94 throw nec_exception("attempt to resize data we do not own");
95#endif
96 if (new_length > _capacity) {
97 _capacity = new_length + new_length / 2; // 1.5x growth
98 try {
99 Vector new_storage(_capacity);
100 if (_len > 0)
101 new_storage.head(_len) = _storage.head(_len);
102 _storage.swap(new_storage);
103 } catch (std::bad_alloc& ba) {
104 throw nec_exception("Error: Out of Memory ");
105 }
106 }
107 _len = new_length;
108 }
109
110 T maxCoeff() const {
111 if (0 == _len)
112 throw nec_exception("No elements in maxCoeff");
113 return _eigen_view().maxCoeff();
114 }
115
116 T minCoeff() const {
117 if (0 == _len)
118 throw nec_exception("No elements in minCoeff");
119 return _eigen_view().minCoeff();
120 }
121
122 T sum(int64_t start_index, int64_t stop_index) {
123 return _eigen_view().segment(start_index, stop_index - start_index).sum();
124 }
125
126 T sum() { return _eigen_view().sum(); }
127
128 void fill(int64_t start, int64_t N, const T& x) {
129 _eigen_view().segment(start, N).setConstant(x);
130 }
131
132 void setConstant(const T& x) { fill(0, _len, x); }
133
134 void set_col_major(int64_t col_dim, int64_t col, int64_t row, const T& val) {
135 (*this)[check(row * col_dim + col)] = val;
136 }
137
138 T& get_col_major(int64_t col_dim, int64_t col, int64_t row) {
139 return (*this)[check(row * col_dim + col)];
140 }
141
142 T& getItem(int64_t row, int64_t col) {
143 return (*this)[check(row, col)];
144 }
145
146 T& operator()(int64_t row, int64_t col) {
147 return getItem(row, col);
148 }
149
150 const T& operator()(int64_t row, int64_t col) const {
151 return (*this)[check(row, col)];
152 }
153
154 T& getItem(int64_t i) {
155 return (*this)[check(i)];
156 }
157
158 const T& operator[](int64_t i) const {
159 return _own_data ? _storage(check(i)) : _view_ptr[check(i)];
160 }
161
162 T& operator[](int64_t i) {
163 return _own_data ? _storage(check(i)) : _view_ptr[check(i)];
164 }
165
166 safe_array<T> segment(int64_t start_index, int64_t end_index) {
167 if (int64_t(-1) == end_index)
168 throw "foo";
169 int64_t n = end_index - start_index + 1;
170 safe_array<T> result;
171 result._view_ptr = data() + start_index;
172 result._len = n;
173 result._rows = 0;
174 result._cols = 0;
175 result._own_data = false;
176 return result;
177 }
178
179 safe_array<T> eigen_segment(int64_t start_index, int64_t n) {
180 return segment(start_index, start_index + n - 1);
181 }
182
183 T* data() {
184 return _own_data ? _storage.data() : _view_ptr;
185 }
186
187 const T* data() const {
188 return _own_data ? _storage.data() : _view_ptr;
189 }
190
191 safe_array<T>& operator=(const safe_array<T>& in_array) {
192 copy(in_array);
193 return *this;
194 }
195
196protected:
197 int64_t _len;
198 int64_t _rows;
199 int64_t _cols;
200 int64_t _capacity;
201 int64_t _resize_chunk;
202
203 Vector _storage; // owning storage (unused when !_own_data)
204 T* _view_ptr; // non-owning view pointer
205 bool _own_data;
206
207 safe_array(const safe_array<T>& in_array, int64_t start_index,
208 int64_t end_index, bool in_copy_data)
209 {
210 _resize_chunk = in_array._resize_chunk;
211 _len = (end_index - start_index) + 1;
212 _rows = 0;
213 _cols = 0;
214
215 if (in_copy_data) {
216 _capacity = _len;
217 _storage.resize(_len);
218 _storage = in_array._eigen_view().segment(start_index, _len);
219 _own_data = true;
220 _view_ptr = nullptr;
221 } else {
222 _view_ptr = in_array.data() + start_index;
223 _capacity = 0;
224 _own_data = false;
225 }
226 }
227
228 inline int64_t check(int64_t i) const {
229#ifdef NEC_ERROR_CHECK
230 if (i < 0 || i >= _len)
231 throw BoundsViol("safe_array: ", i, _len);
232#endif
233 return i;
234 }
235
236 inline int64_t check(int64_t row, int64_t col) const {
237#ifdef NEC_ERROR_CHECK
238 if (row < 0 || row >= _rows)
239 throw BoundsViol("safe_array: ", row, _rows);
240 if (col < 0 || col >= _cols)
241 throw BoundsViol("safe_array: ", col, _cols);
242#endif
243 return check(int64_t(col) * _rows + row);
244 }
245
246private:
247 Eigen::Map<Vector> _eigen_view() {
248 return Eigen::Map<Vector>(data(), _len);
249 }
250
251 const Eigen::Map<const Vector> _eigen_view() const {
252 return Eigen::Map<const Vector>(data(), _len);
253 }
254};
255
256
257template<typename T>
258class safe_matrix : public safe_array<T> {
259public:
260 safe_matrix(int64_t in_rows, int64_t in_cols) : safe_array<T>(in_rows * in_cols) {
261 this->resize(in_rows, in_cols);
262 }
263 safe_matrix() : safe_array<T>() { }
264
265private:
266 using safe_array<T>::operator[];
267};
Definition safe_array.h:30
Definition nec_exception.h:28
A Safe Array class backed by Eigen for SIMD-accelerated operations.
Definition safe_array.h:47
Definition safe_array.h:258
Definition CurrentInput.h:26