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