utils_array.h
Go to the documentation of this file.
1/*!
2 * \file utils_array.h
3 * \brief Template functions to initialize and release arrays.
4 *
5 * \remarks
6 * - 1. 2018-05-02 - lj - Make part of CCGL.
7 * - 2. 2021-07-20 - lj - Initialize 2D array in a succesive memory.
8 *
9 * \author Liangjun Zhu, zlj(at)lreis.ac.cn
10 * \version 1.1
11 */
12#ifndef CCGL_UTILS_ARRAY_H
13#define CCGL_UTILS_ARRAY_H
14
15#include <new> // std::nothrow
16#include <cstdarg> // variable arguments
17#include <iostream>
18#include <vector>
19
20#include "basic.h"
21
22using std::vector;
23using std::cout;
24using std::endl;
25using std::nothrow;
26
27namespace ccgl {
28/*!
29 * \namespace ccgl::utils_array
30 * \brief Array related functions include vector and pointer array.
31 */
32namespace utils_array {
33/*!
34 * \brief Initialize DT_Array1D data
35 * \param[in] row
36 * \param[in] data
37 * \param[in] init_value
38 * \return True if succeed, else false and the error message will print as well.
39 */
40template <typename T, typename INI_T>
41bool Initialize1DArray(int row, T*& data, INI_T init_value);
42
43/*!
44 * \brief Initialize DT_Array1D data based on an existed array
45 * \param[in] row
46 * \param[in] data
47 * \param[in] init_data
48 * \return True if succeed, else false and the error message will print as well.
49 */
50template <typename T, typename INI_T>
51bool Initialize1DArray(int row, T*& data, INI_T* init_data);
52
53template <typename T, typename INI_T>
54bool Initialize1DArray4ItpWeight(int row, T*& data, INI_T* init_data, int itp_weight_data_length);
55/*!
56 * \brief Initialize DT_Array2D data
57 *
58 * The 2D array are created in a successive memory.
59 * 1. Create a 1D array of row data pointers with the length of row
60 * 2. Create a 1D array of data pool with the length of row * col
61 * 3. Iteratively point row pointers to appropriate positions in data pool
62 *
63 * Refers to https://stackoverflow.com/a/21944048/4837280
64 *
65 * \param[in] row
66 * \param[in] col
67 * \param[in] data
68 * \param[in] init_value
69 * \return True if succeed, else false and the error message will print as well.
70 */
71template <typename T, typename INI_T>
72bool Initialize2DArray(int row, int col, T**& data, INI_T init_value);
73
74/*!
75 * \brief Initialize DT_Array2D data based on an existed array
76 * The usage of `const T * const *` is refers to http://blog.csdn.net/pmt123456/article/details/50813564
77 * \param[in] row
78 * \param[in] col
79 * \param[in] data
80 * \param[in] init_data dimension MUST BE (row, col)
81 * \return True if succeed, else false and the error message will print as well.
82 */
83template <typename T, typename INI_T>
84bool Initialize2DArray(int row, int col, T**& data, INI_T** init_data);
85
86/*!
87 * \brief Initialize irregular DT_Array2D data based on an existed 1D array
88 * \param[in] init_data Initial 1D array
89 * \param[out] rows Rows count
90 * \param[out] max_cols Maximum cols count
91 * \param[out] data Irregular 2D array
92 * \return True if succeed, else false and the error message will print as well.
93 */
94template <typename T1, typename T2>
95bool Initialize2DArray(T1* init_data, int& rows, int& max_cols, T2**& data);
96
97/*!
98 * \brief Release DT_Array1D data
99 * \param[in] data
100 */
101template <typename T>
102void Release1DArray(T*& data);
103
104/*!
105 * \brief Release DT_Array2D data
106 * \param[in] data
107 */
108template <typename T>
109void Release2DArray(T**& data);
110
111/*!
112 * \brief Batch release of 1D array
113 * Variable arguments with the end of `nullptr`.
114 *
115 * The input parameters are listed as `data`, `data2`, ... , `dataN`, and ended with `nullptr`.
116 *
117 * Example:
118 * \code
119 * BatchRelease1DArray(array1, array2, array3, nullptr);
120 * \endcode
121 *
122 * \warning After batch release, the variable will not be set to nullptr.
123 * So, do not use these variables any more.
124 * BTW, this function will not cause memory leak.
125 *
126 * USE WITH ALL CAUTIONS CLEARLY AWARED.
127 */
128template <typename T>
129void BatchRelease1DArray(T*& data, ...);
130
131/*!
132 * \brief Batch release of 2D array, \sa BatchRelease1DArray
133 * Variable arguments with the end of nullptr.
134 *
135 * Example:
136 * \code
137 * BatchRelease2DArray(rows, array1, array2, array3, nullptr);
138 * \endcode
139 *
140 * \param[in] nrows Rows
141 * \param[in] data The input parameters are listed as `data`, `data2`, ... , `dataN`, and ended with `nullptr`.
142 * \warning USE WITH ALL CAUTIONS CLEARLY AWARED.
143 */
144template <typename T>
145void BatchRelease2DArray(int nrows, T**& data, ...);
146
147/*!
148 * \brief Write 1D array to a file
149 * \sa Read1DArrayFromTxtFile(), Read2DArrayFromTxtFile(), Output2DArrayToTxtFile()
150 * \param[in] n, data, filename
151*/
152void Output1DArrayToTxtFile(int n, const float* data, const char* filename);
153
154/*!
155 * \brief Write 2D array to a file
156 * \sa Read1DArrayFromTxtFile(), Read2DArrayFromTxtFile(), Output1DArrayToTxtFile()
157 * \param[in] rows, cols, data, filename
158 */
159void Output2DArrayToTxtFile(int rows, int cols, const float** data, const char* filename);
160
161/*!
162 * \brief Read 1D array from file
163 * The input file should follow the format:
164 * a 1D array sized rows * 1
165 *
166 * The size of data is rows
167 *
168 * \sa Read2DArrayFromTxtFile(), Output1DArrayToTxtFile(), Output2DArrayToTxtFile()
169 * \param[in] filename
170 * \param[out] rows, data
171 */
172template <typename T>
173void Read1DArrayFromTxtFile(const char* filename, int& rows, T*& data);
174
175/*!
176 * \brief Read 2D array from file
177 * The input file should follow the format:
178 * a 2D array sized rows * rows
179 *
180 * The size of data is rows * (rows + 1), the first element of each row is the rows
181 *
182 * \sa Read1DArrayFromTxtFile(), Output1DArrayToTxtFile(), Output2DArrayToTxtFile()
183 * \param[in] filename
184 * \param[out] rows, data
185 */
186template <typename T>
187void Read2DArrayFromTxtFile(const char* filename, int& rows, T**& data);
188
189/*!
190 * \brief Read 2D array from string
191 * The input string should follow the format:
192 * float value, total number is rows * rows
193 *
194 * The size of data is rows * (rows + 1), the first element of each row is the rows.
195 *
196 * \param[in] s
197 * \param[out] rows, data
198 */
199template <typename T>
200void Read2DArrayFromString(const char* s, int& rows, T**& data);
201
202/*!
203 * \brief If value in vector container
204 * \param[in] val Value, e.g., a int, or float
205 * \param[in] vec Vector container, data type is consistent with val
206 * \return True if val is in vec, otherwise False
207 */
208template <typename T>
209bool ValueInVector(T val, const vector<T>& vec);
210
211/*!
212 * \brief Remove value in vector container
213 * \param[in] val Value to be removed, e.g., a int, or float
214 * \param[in] vec Vector container, data type is consistent with val
215 */
216template <typename T>
217void RemoveValueInVector(T val, vector<T>& vec);
218
219/*!
220 * \brief Rudimentary RAII class of 2D Array which occupy successive memory
221 *
222 * Currently not used in CCGL, but maybe in future!
223 *
224 * Refers to:
225 * origin implementation: https://stackoverflow.com/a/21944048/4837280 and
226 * memory leak fixed: https://stackoverflow.com/a/58309862/4837280
227 */
228template <typename T>
229class Array2D {
230 T** data_ptr;
231 vuint32_t m_rows;
232 vuint32_t m_cols;
233
234 T** create2DArray(vuint32_t nrows, vuint32_t ncols, const T& val = T()) {
235 T** ptr = nullptr;
236 T* pool = nullptr;
237 try {
238 ptr = new(nothrow) T*[nrows]; // allocate pointers (Do not throw here)
239 pool = new(nothrow) T[nrows*ncols]; // allocate pool (Do not throw here)
240 for (vuint32_t i = 0; i < nrows * ncols; i++) {
241 pool[i] = val;
242 }
243 // now point the row pointers to the appropriate positions in the memory pool
244 for (vuint32_t i = 0; i < nrows; ++i, pool += ncols) {
245 ptr[i] = pool;
246 }
247 return ptr;
248 } catch (std::bad_alloc& ex) {
249 delete[] ptr; // either this is nullptr or it was allocated
250 // throw ex; // memory allocation error
251 }
252 }
253
254public:
255 typedef T value_type;
256 T** data() {
257 return data_ptr;
258 }
259
260 vuint32_t get_rows() const { return m_rows; }
261
262 vuint32_t get_cols() const { return m_cols; }
263
264 Array2D() : data_ptr(nullptr), m_rows(0), m_cols(0) {}
265 Array2D(vuint32_t rows, vuint32_t cols, const T& val = T()) {
266 if (rows <= 0)
267 throw std::invalid_argument("number of rows is 0"); // TODO, DO not throw here
268 if (cols <= 0)
269 throw std::invalid_argument("number of columns is 0"); // TODO, DO not throw here
270 data_ptr = create2DArray(rows, cols, val);
271 m_rows = rows;
272 m_cols = cols;
273 }
274
275 ~Array2D() {
276 if (data_ptr) {
277 delete[] data_ptr[0]; // remove the pool
278 delete[] data_ptr; // remove the pointers
279 }
280 }
281
282 Array2D(const Array2D& rhs) : m_rows(rhs.m_rows), m_cols(rhs.m_cols) {
283 data_ptr = create2DArray(m_rows, m_cols);
284 std::copy(&rhs.data_ptr[0][0], &rhs.data_ptr[m_rows - 1][m_cols], &data_ptr[0][0]);
285 }
286
287 Array2D(Array2D&& rhs) NOEXCEPT {
288 data_ptr = rhs.data_ptr;
289 m_rows = rhs.m_rows;
290 m_cols = rhs.m_cols;
291 rhs.data_ptr = nullptr;
292 }
293
294 Array2D& operator=(Array2D&& rhs) NOEXCEPT {
295 if (&rhs != this) {
296 swap(rhs, *this);
297 }
298 return *this;
299 }
300
301 void swap(Array2D& left, Array2D& right) {
302 std::swap(left.data_ptr, right.data_ptr);
303 std::swap(left.m_cols, right.m_cols);
304 std::swap(left.m_rows, right.m_rows);
305 }
306
307 Array2D& operator = (const Array2D& rhs) {
308 if (&rhs != this) {
309 Array2D temp(rhs);
310 swap(*this, temp);
311 }
312 return *this;
313 }
314
315 T* operator[](vuint32_t row) {
316 return data_ptr[row];
317 }
318
319 const T* operator[](vuint32_t row) const {
320 return data_ptr[row];
321 }
322
323 void create(vuint32_t rows, vuint32_t cols, const T& val = T()) {
324 *this = Array2D(rows, cols, val);
325 }
326};
327
328
329/************ Implementation of template functions ******************/
330template <typename T, typename INI_T>
331bool Initialize1DArray(const int row, T*& data, const INI_T init_value) {
332 if (nullptr != data) {
333 //Should allow an array to re-enter this function then just return? --wyj
334 //cout << "The input 1D array pointer is not nullptr. No initialization performed!" << endl;
335 return false;
336 }
337 if (row <= 0) {
338 cout << "The data length MUST be greater than 0!" << endl;
339 data = nullptr;
340 return false;
341 }
342 data = new(nothrow)T[row];
343 if (nullptr == data) {
344 delete[] data;
345 cout << "Bad memory allocated during 1D array initialization!" << endl;
346 data = nullptr;
347 return false;
348 }
349 T init = static_cast<T>(init_value);
350#pragma omp parallel for
351 for (int i = 0; i < row; i++) {
352 data[i] = init;
353 }
354 return true;
355}
356
357template <typename T, typename INI_T>
358bool Initialize1DArray(const int row, T*& data, INI_T* const init_data) {
359 if (nullptr != data) {
360 cout << "The input 1D array pointer is not nullptr. No initialization performed!" << endl;
361 return false;
362 }
363 data = new(nothrow) T[row];
364 if (nullptr == data) {
365 delete[] data;
366 cout << "Bad memory allocated during 1D array initialization!" << endl;
367 return false;
368 }
369 if (nullptr == init_data) {
370 cout << "The input parameter init_data MUST NOT be nullptr!" << endl;
371 return false;
372 }
373#pragma omp parallel for
374 for (int i = 0; i < row; i++) {
375 data[i] = static_cast<T>(init_data[i]);
376 }
377 return true;
378}
379
380template <typename T, typename INI_T>
381bool Initialize2DArray(const int row, const int col, T**& data,
382 const INI_T init_value) {
383 if (nullptr != data) {
384 cout << "The input 2D array pointer is not nullptr. No initialization performed!" << endl;
385 return false;
386 }
387 data = new(nothrow) T*[row];
388 if (nullptr == data) {
389 delete[] data;
390 cout << "Bad memory allocated during initialize rows of the 2D array!" << endl;
391 return false;
392 }
393 T* pool = nullptr;
394 pool = new(nothrow) T[row * col];
395 if (nullptr == pool) {
396 delete[] pool;
397 cout << "Bad memory allocated during initialize data pool of the 2D array!" << endl;
398 return false;
399 }
400 // Initialize the data pool
401 T init = static_cast<T>(init_value);
402#pragma omp parallel for
403 for (int i = 0; i < row * col; i++) {
404 pool[i] = init;
405 }
406 // Now point the row pointers to the appropriate positions in the data pool
407 for (int i = 0; i < row; ++i, pool += col) {
408 data[i] = pool;
409 }
410 return true;
411}
412
413template <typename T, typename INI_T>
414bool Initialize2DArray(const int row, const int col, T**& data,
415 INI_T** const init_data) {
416 bool flag = Initialize2DArray(row, col, data, init_data[0][0]);
417 if (!flag) { return false; }
418#pragma omp parallel for
419 for (int i = 0; i < row; i++) {
420 for (int j = 0; j < col; j++) {
421 data[i][j] = static_cast<T>(init_data[i][j]);
422 }
423 }
424 return true;
425}
426
427template <typename T1, typename T2>
428bool Initialize2DArray(T1* init_data, int& rows, int& max_cols, T2**& data) {
429 int idx = 0;
430 rows = CVT_INT(init_data[idx++]);
431 data = new(nothrow) T2* [rows];
432 if (nullptr == data) {
433 delete[] data;
434 cout << "Bad memory allocated during initialize rows of the 2D array!" << endl;
435 return false;
436 }
437 T2* pool = nullptr;
438 // Get actual data length of init_data, excluding the first element which is 'rows'
439 int* cols = new int[rows];
440 max_cols = -1;
441 for (int i = 0; i < rows; i++) {
442 cols[i] = CVT_INT(init_data[idx]);
443 idx += cols[i] + 1;
444 if (cols[i] > max_cols) { max_cols = cols[i]; }
445 }
446 int length = idx - 1;
447 // New a 1d array to store data
448 Initialize1DArray(length, pool, init_data + 1);
449 // Now point the row pointers to the appropriate positions in the data pool
450 int pos = 0;
451 for (int i = 0; i < rows; ++i) {
452 data[i] = pool + pos;
453 pos += cols[i] + 1;
454 }
455 delete[] cols;
456 return true;
457}
458
459template <typename T>
460void Release1DArray(T*& data) {
461 if (nullptr != data) {
462 delete[] data;
463 data = nullptr;
464 }
465}
466
467template <typename T>
468void Release2DArray(T**& data) {
469 if (nullptr == data) {
470 return;
471 }
472 delete[] data[0]; // delete the memory pool
473 delete[] data; // delete row pointers
474 data = nullptr;
475}
476
477template <typename T>
478void BatchRelease1DArray(T*& data, ...) {
479 va_list arg_ptr;
480 va_start(arg_ptr, data);
481 Release1DArray(data);
482 T* arg_value = va_arg(arg_ptr, T*);
483 while (nullptr != arg_value) {
484 Release1DArray(arg_value);
485 arg_value = va_arg(arg_ptr, T*);
486 }
487 va_end(arg_ptr);
488}
489
490template <typename T>
491void BatchRelease2DArray(const int nrows, T**& data, ...) {
492 va_list arg_ptr;
493 va_start(arg_ptr, data);
494 Release2DArray(nrows, data);
495 T** arg_value = va_arg(arg_ptr, T**);
496 while (nullptr != arg_value) {
497 Release2DArray(nrows, arg_value);
498 arg_value = va_arg(arg_ptr, T**);
499 }
500 va_end(arg_ptr);
501}
502
503template <typename T>
504bool ValueInVector(const T val, const vector<T>& vec) {
505 if (vec.empty()) {
506 return false;
507 }
508 if (find(vec.begin(), vec.end(), val) == vec.end()) {
509 return false;
510 }
511 return true;
512}
513
514template <typename T>
515void RemoveValueInVector(const T val, vector<T>& vec) {
516 for (auto iter = vec.begin(); iter != vec.end();) {
517 if (*iter == val) {
518 iter = vec.erase(iter);
519 } else {
520 ++iter;
521 }
522 }
523}
524
525} /* utils_array */
526} /* namespace: ccgl */
527
528#endif /* CCGL_UTILS_ARRAY_H */
Basic definitions.
#define NOEXCEPT
A compatible reference to noexcept or throw() if not supported by the compiler.
Definition: basic.h:153
#define CVT_INT(param)
A reference to the postfix of executable file for RELWITHDEBINFO mode.
Definition: basic.h:325
Rudimentary RAII class of 2D Array which occupy successive memory.
Definition: utils_array.h:229
void Release1DArray(T *&data)
Release DT_Array1D data.
Definition: utils_array.h:460
bool Initialize1DArray(int row, T *&data, INI_T init_value)
Initialize DT_Array1D data.
Definition: utils_array.h:331
bool Initialize2DArray(int row, int col, T **&data, INI_T init_value)
Initialize DT_Array2D data.
Definition: utils_array.h:381
void Read2DArrayFromTxtFile(const char *filename, int &rows, T **&data)
Read 2D array from file The input file should follow the format: a 2D array sized rows * rows.
void RemoveValueInVector(T val, vector< T > &vec)
Remove value in vector container.
Definition: utils_array.h:515
void Output2DArrayToTxtFile(int rows, int cols, const float **data, const char *filename)
Write 2D array to a file.
void BatchRelease1DArray(T *&data,...)
Batch release of 1D array Variable arguments with the end of nullptr.
Definition: utils_array.h:478
bool ValueInVector(T val, const vector< T > &vec)
If value in vector container.
Definition: utils_array.h:504
void Read2DArrayFromString(const char *s, int &rows, T **&data)
Read 2D array from string The input string should follow the format: float value, total number is row...
void Output1DArrayToTxtFile(int n, const float *data, const char *filename)
Write 1D array to a file.
void BatchRelease2DArray(int nrows, T **&data,...)
Batch release of 2D array,.
Definition: utils_array.h:491
void Read1DArrayFromTxtFile(const char *filename, int &rows, T *&data)
Read 1D array from file The input file should follow the format: a 1D array sized rows * 1.
void Release2DArray(T **&data)
Release DT_Array2D data.
Definition: utils_array.h:468
Common Cross-platform Geographic Library (CCGL)