rcolyer.net
RC Lib  Version 202403231100
Data2D.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////
2 //
3 // RC Library, (c) 2011-2016, Ryan A. Colyer
4 // Distributed under the Boost Software License, v1.0. (LICENSE.txt)
5 //
6 /// \file Data2D.h
7 /// Provides a bounds-safe two-dimensional resizeable structure.
8 /////////////////////////////////////////////////////////////////////
9 
10 #ifndef RC_DATA2D_H
11 #define RC_DATA2D_H
12 
13 
14 #include "Data1D.h"
15 #include "Errors.h"
16 #include <stdlib.h>
17 
18 
19 namespace RC {
20  template <class T>
21  class Data2D;
22  template <class T>
23  inline std::ostream& operator<< (std::ostream &out, const Data2D<T>& d);
24 
25  /// A bounds-safe two-dimensional resizeable structure.
26  /** Note: Non-POD classes stored in Data2D containers must have a
27  * default constructor with default values or no arguments.
28  * @see Data1D
29  * @see Data3D
30  */
31  template <class T>
32  class Data2D {
33  protected:
34  /// @cond UNDOC
35  void Initialize(size_t new_d_size1, size_t new_d_size2) {
36  d_size1 = new_d_size1;
37  d_size2 = new_d_size2;
38 
39  data = Data1D< Data1D<T> >(d_size2);
40  for (size_t i=0; i<d_size2; i++) {
41  data[i] = Data1D<T>(d_size1);
42  }
43  }
44  /// @endcond
45 
46  public:
47 
48  /// Default constructor which initializes to size 0.
49  Data2D() {
50  Initialize(0, 0);
51  }
52 
53  /// Constructor which sets the initial sizes.
54  /** Efficiency note: The first dimension, set by d_size1, should be the
55  * one which is iterated over most frequently in innermost loops for
56  * caching gains.
57  * @param d_size1 The size of the first dimension.
58  * @param d_size2 The size of the second dimension.
59  */
60  explicit Data2D(size_t d_size1, size_t d_size2) {
61  Initialize(d_size1, d_size2);
62  }
63 
64 
65  /// Copy constructor that copies all elements.
66  /** @param copy A source Data2D from which elements should be copied.
67  */
68  inline Data2D(const Data2D<T>& copy)
69  : d_size1 (copy.d_size1),
70  d_size2 (copy.d_size2) {
71 
72  data = copy.data;
73  }
74 
75 #ifdef CPP11
76  /// Initializer list constructor, initializes with nested brackets.
77  inline Data2D(const std::initializer_list<Data1D<T>>& new_data)
78  : d_size1(0),
79  d_size2(new_data.size()),
80  data(new_data.size()) {
81  std::copy(new_data.begin(), new_data.end(), data.Raw());
82  if (data.size()) {
83  d_size1 = data[0].size();
84  }
85  }
86 #endif
87 
88  /// Deletes all contents upon destruction.
89  ~Data2D() {
90  Delete();
91  }
92 
93 
94  /// Delete all the elements and free all allocated memory.
95  inline void Delete() {
96  d_size1 = 0;
97  d_size2 = 0;
98  data.Delete();
99  cptrs.Delete();
100  }
101 
102 
103  /// Identical to Delete().
104  inline void Clear() {
105  Delete();
106  }
107 
108 
109  /// Reduces memory consumption to only that necessary for the current
110  /// size.
111  /** Efficiency note: This function may copy all elements if necessary
112  * for reallocating.
113  */
114  inline void Crop() {
115  data.Crop();
116 
117  for (size_t i=0; i<d_size2; i++) {
118  data[i].Crop();
119  }
120 
121  cptrs.Crop();
122  }
123 
124 
125  /** @return True if there are no elements / at least one size is 0.
126  */
127  inline bool IsEmpty() const {
128  return ( (d_size1 == 0) || (d_size2 == 0) );
129  }
130 
131 
132  /// Assignment operator which copies all contents from other.
133  /** @param other Data2D to copy from.
134  * @return This object.
135  */
136  inline Data2D& operator= (const Data2D& other) {
137  if (this != &other) {
138  d_size1 = other.d_size1;
139  d_size2 = other.d_size2;
140  data = other.data;
141  }
142 
143  return *this;
144  }
145 
146 
147  /// Copy data from any other object of a type with a compatible
148 
149  /// Return a bounds-checked random-access iterator starting at offset.
150  /** Note that the iterator is revokable, meaning use of it will throw an
151  * exception if this Data2D is deleted.
152  * @return A bounds-checked iterator.
153  * @see end()
154  */
156  return data.begin();
157  }
158  /// Const version of begin.
159  inline const RAIter< Data1D< Data1D<T> >, Data1D<T> > begin() const {
160  return data.begin();
161  }
162 
163 
164  /// Return a bounds-checked random-access iterator starting just past
165  /// the last element.
166  /** Note that the iterator is revokable, meaning use of it will throw an
167  * exception if this Data2D is deleted.
168  * @return A bounds-checked iterator.
169  * @see begin()
170  */
172  return data.end();
173  }
174  /// Const version end.
176  return data.end();
177  }
178 
179 
180  /// Bounds-checked access of a Data1D corresponding to the data at
181  /// index x in dimension 2.
182  /** Throws an ErrorMsgBounds if out of bounds. Usage note:
183  * Data2D<int> arr(size1, size2); int val = arr[x2][x1];
184  * @param x The index of dimension 2.
185  * @return A Data1D of all elements in dimension 1 at that index.
186  */
187  inline Data1D<T>& operator[] (size_t x) { return data[x]; }
188  /// Identical to Data2D::operator[]
189  inline Data1D<T>& operator() (size_t x) { return data[x]; }
190  /// Const version of Data2D::operator[]
191  inline const Data1D<T>& operator[] (size_t x) const { return data[x]; }
192  /// Const version of Data2D::operator[]
193  inline const Data1D<T>& operator() (size_t x) const { return data[x]; }
194  /// Bounds-checked access of an element.
195  /** Throws an ErrorMsgBounds if out of bounds. Note that for
196  * Data2D<int> arr; arr(x, y) is equivalent to arr[y][x].
197  * @param x The index of dimension 1
198  * @param y The index of dimension 2.
199  * @return A reference to the indexed element.
200  */
201  inline T& operator() (size_t x, size_t y) { return data[y][x]; }
202  /// Const version of Data2D::operator()(size_t x, size_t y)
203  inline const T& operator() (size_t x, size_t y) const {
204  return data[y][x];
205  }
206  /// Equivalent to Data2D::operator()(size_t x, size_t y)
207  inline T& At(size_t x, size_t y) { return data[y][x]; }
208  /// Const version of Data2D::operator()(size_t x, size_t y)
209  inline const T& At(size_t x, size_t y) const {
210  return data[y][x];
211  }
212 
213  /// Get the size of dimension 1.
214  inline size_t size1() const { return d_size1; }
215  /// Get the size of dimension 2.
216  inline size_t size2() const { return d_size2; }
217 
218  /// Returns sizeof(T).
219  inline size_t TypeSize() const { return sizeof(T); }
220 
221 
222  /// Sets all elements equal to 0.
223  /** @see Data1D::Zero() */
224  inline void Zero() {
225  for (size_t y=0; y<d_size2; y++) {
226  data[y].Zero();
227  }
228  }
229 
230 
231  /// Check if the indices x and y are in bounds.
232  /** @param x The index for dimension 1.
233  * @param y The index for dimension 2.
234  * @return True if in bounds.
235  */
236  inline bool Check(const size_t x, const size_t y) const {
237  if ( ! ((x < d_size1) && (y < d_size2)) ) {
238  return false;
239  }
240  else {
241  return true;
242  }
243  }
244 
245 
246  /// Throw an ErrorMsgBounds exception if either x or y is out
247  /// of bounds
248  /** @param x The index for dimension 1.
249  * @param y The index for dimension 2.
250  */
251  inline void Assert(const size_t x, const size_t y) const {
252  if ( ! Check(x, y) ) {
253  Throw_RC_Type(Bounds, "Out of bounds");
254  }
255  }
256 
257 
258  /// Resize the array, reallocating if necessary.
259  /** This may trigger a copy operation upon expansion. For efficiency, it
260  * never reallocates or copies while shrinking or expanding within a
261  * previous size range. Use Crop if necessary to shrink storage to the
262  * current size.
263  * @param resize_size1 The new size for dimension 1.
264  * @param resize_size2 The new size for dimension 2.
265  */
266  inline void Resize(const size_t resize_size1, const size_t resize_size2) {
267  data.Resize(resize_size2);
268  for (size_t i=0; i<resize_size2; i++) {
269  data[i].Resize(resize_size1);
270  }
271  d_size2 = resize_size2;
272  d_size1 = resize_size1;
273 
274  cptrs.Resize(0); // Invalidates
275  }
276 
277 
278  /// Access a raw unprotected 2-dimensional C-array for the enclosed data.
279  /** Warning: This convenience function bypasses the bounds protections
280  * provided by this class. Also the C-array becomes invalid if this
281  * object is resized, deleted, or cropped.
282  * @return C-style pointer to the contents.
283  */
284  inline T** Raw() {
285  if (cptrs.size() != d_size2) {
286  cptrs.Resize(d_size2);
287  for (size_t i=0; i<d_size2; i++) {
288  cptrs[i] = data[i].Raw();
289  }
290  }
291  return cptrs.Raw();
292  }
293 
294 
295  /// Access the underlying nested Data1D structure for this object.
296  /** Attempts should not be made to resize the underlying data accessed
297  * with this convenience function.
298  * @return The nested Data1D contained within.
299  */
301  return data;
302  }
303  /// Const version of RawData().
304  inline const Data1D< Data1D<T> >& RawData() const {
305  return data;
306  }
307 
308 
309 
310  /// Convert endianness of all elements if needed, for supported types.
311  inline void ToLilEndian() {
312  if (Endian::IsBig()) {
313  for (size_t y=0; y<d_size2; y++) {
314  for (size_t x=0; x<d_size1; x++) {
315  data[y][x] = Endian::ToLittle(data[y][x]);
316  }
317  }
318  }
319  }
320  /// Convert endianness of all elements if needed, for supported types.
321  inline void FromLilEndian() { ToLilEndian(); }
322 
323  /// Convert endianness of all elements if needed, for supported types.
324  inline void ToBigEndian() {
325  if (Endian::IsLittle()) {
326  for (size_t y=0; y<d_size2; y++) {
327  for (size_t x=0; x<d_size1; x++) {
328  data[y][x] = Endian::ToBig(data[y][x]);
329  }
330  }
331  }
332  }
333  /// Convert endianness of all elements if needed, for supported types.
334  inline void FromBigEndian() { ToBigEndian(); }
335 
336 
337  /// Efficiently swap all the contents of a and b.
338  template <class T2> friend void swap (Data2D<T2> &a, Data2D<T2> &b);
339 
340 
341  protected:
342  /// @cond PROTECTED
343 
344  size_t d_size1;
345  size_t d_size2;
346  Data1D< Data1D<T> > data;
347  Data1D< T* > cptrs;
348  /// @endcond
349  };
350 
351 
352  /// Efficiently swap all the contents of a and b.
353  template <class T2>
354  void swap (Data2D<T2> &a, Data2D<T2> &b) {
355  std::swap(a.d_size1, b.d_size1);
356  std::swap(a.d_size2, b.d_size2);
357  swap(a.data, b.data);
358  }
359 
360 
361  /// Outputs data to a stream as { { x_0_0, x_1_0, ...},
362  /// { x_0_1, x_1_1, ...}, ... }
363  /** Usage like: Data2D<RStr> data; std::cout << data << std::endl;
364  */
365  template <class T>
366  inline std::ostream& operator<< (std::ostream &out, const Data2D<T>& d) {
367  size_t i;
368 
369  if (d.size2() == 0) {
370  out << "{ { } }";
371  }
372  else {
373  out << "{ " << d[0];
374  for (i=1; i<d.size2(); i++) {
375  out << ", " << d[i];
376  }
377  out << " }";
378  }
379 
380  return out;
381  }
382 }
383 
384 
385 #endif // RC_DATA2D_H
386 
Provides a one-dimensional vector-like structure.
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:282
A bounds-safe one-dimensional vector-like structure.
Definition: Data1D.h:49
A bounds-safe two-dimensional resizeable structure.
Definition: Data2D.h:32
~Data2D()
Deletes all contents upon destruction.
Definition: Data2D.h:89
size_t TypeSize() const
Returns sizeof(T).
Definition: Data2D.h:219
void Delete()
Delete all the elements and free all allocated memory.
Definition: Data2D.h:95
T & At(size_t x, size_t y)
Equivalent to Data2D::operator()(size_t x, size_t y)
Definition: Data2D.h:207
RAIter< Data1D< Data1D< T > >, Data1D< T > > end()
Return a bounds-checked random-access iterator starting just past the last element.
Definition: Data2D.h:171
void Crop()
Reduces memory consumption to only that necessary for the current size.
Definition: Data2D.h:114
RAIter< Data1D< Data1D< T > >, Data1D< T > > begin()
Copy data from any other object of a type with a compatible.
Definition: Data2D.h:155
void FromLilEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data2D.h:321
Data2D()
Default constructor which initializes to size 0.
Definition: Data2D.h:49
void ToLilEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data2D.h:311
void FromBigEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data2D.h:334
void Resize(const size_t resize_size1, const size_t resize_size2)
Resize the array, reallocating if necessary.
Definition: Data2D.h:266
RAIter< Data1D< Data1D< T > >, Data1D< T > > end() const
Const version end.
Definition: Data2D.h:175
const T & At(size_t x, size_t y) const
Const version of Data2D::operator()(size_t x, size_t y)
Definition: Data2D.h:209
T ** Raw()
Access a raw unprotected 2-dimensional C-array for the enclosed data.
Definition: Data2D.h:284
bool IsEmpty() const
Definition: Data2D.h:127
size_t size1() const
Get the size of dimension 1.
Definition: Data2D.h:214
bool Check(const size_t x, const size_t y) const
Check if the indices x and y are in bounds.
Definition: Data2D.h:236
Data2D(const std::initializer_list< Data1D< T >> &new_data)
Initializer list constructor, initializes with nested brackets.
Definition: Data2D.h:77
void Clear()
Identical to Delete().
Definition: Data2D.h:104
friend void swap(Data2D< T2 > &a, Data2D< T2 > &b)
Efficiently swap all the contents of a and b.
Definition: Data2D.h:354
size_t size2() const
Get the size of dimension 2.
Definition: Data2D.h:216
void Assert(const size_t x, const size_t y) const
Throw an ErrorMsgBounds exception if either x or y is out of bounds.
Definition: Data2D.h:251
Data1D< T > & operator[](size_t x)
Bounds-checked access of a Data1D corresponding to the data at index x in dimension 2.
Definition: Data2D.h:187
Data2D & operator=(const Data2D &other)
Assignment operator which copies all contents from other.
Definition: Data2D.h:136
void Zero()
Sets all elements equal to 0.
Definition: Data2D.h:224
Data1D< T > & operator()(size_t x)
Identical to Data2D::operator[].
Definition: Data2D.h:189
Data2D(size_t d_size1, size_t d_size2)
Constructor which sets the initial sizes.
Definition: Data2D.h:60
Data1D< Data1D< T > > & RawData()
Access the underlying nested Data1D structure for this object.
Definition: Data2D.h:300
Data2D(const Data2D< T > &copy)
Copy constructor that copies all elements.
Definition: Data2D.h:68
void ToBigEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data2D.h:324
const Data1D< Data1D< T > > & RawData() const
Const version of RawData().
Definition: Data2D.h:304
const RAIter< Data1D< Data1D< T > >, Data1D< T > > begin() const
Const version of begin.
Definition: Data2D.h:159
static bool IsLittle()
True if this system is little-endian.
Definition: Types.h:335
static bool IsBig()
True if this system is big-endian.
Definition: Types.h:341
static T ToBig(const T &x)
Converts x to big-endian.
Definition: Types.h:319
static T ToLittle(const T &x)
Converts x to little-endian.
Definition: Types.h:302
A bounds-checked iterator for random-access containers that knows when its target was deleted.
Definition: Iter.h:27
Definition: APtr.h:25
void swap(Data2D< T2 > &a, Data2D< T2 > &b)
Efficiently swap all the contents of a and b.
Definition: Data2D.h:354
std::ostream & operator<<(std::ostream &out, APtr< T > obj)
A convenience stream output for displaying the enclosed object.
Definition: APtr.h:120
void swap(RC::Data1D< T > &a, RC::Data1D< T > &b)
Efficiently swap all the contents of a and b.
Definition: Data1D.h:1184
email address
— (c) 2015