rcolyer.net
RC Lib  Version 202503311402
Data1D.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 Data1D.h
7 /// Provides a one-dimensional vector-like structure.
8 /////////////////////////////////////////////////////////////////////
9 
10 #ifndef RC_DATA1D_H
11 #define RC_DATA1D_H
12 
13 #include "RCconfig.h"
14 #include "Errors.h"
15 #include "Iter.h"
16 #include "Macros.h"
17 #include "Types.h"
18 #include <algorithm>
19 #include <stdlib.h>
20 #include <iostream>
21 #ifdef CPP11
22 #include <type_traits>
23 #endif
24 
25 
26 namespace RC {
27  /// @cond EXTERNAL
28  extern u64 RND_Get_Range(u64);
29  extern u64 URand_Get_Range(u64);
30  class RND;
31  extern RND& RND_Gen();
32  class URand;
33  extern URand& URand_Gen();
34  /// @endcond
35 
36  /// A bounds-safe one-dimensional vector-like structure.
37  /** It provides efficient resizing and offsets, as well as convenience
38  * functions for assignments and comparisons. It also provides
39  * bounds-safe iterators.
40  * Note: Non-POD classes stored in Data1D containers must have a
41  * default constructor with default values or no arguments, which is
42  * necessary for efficient resizing. This requirement also permits
43  * safe use of offsets and temporary shrinking, because all allocated
44  * space contains defined data with properly constructed objects.
45  * @see Data2D
46  * @see Data3D
47  */
48  template <class T>
49  class Data1D {
50  protected:
51  /// @cond PROTECTED
52 
53  RevPtr< Data1D<T> > rev_ptr;
54 
55  size_t d_alloc;
56  T *alloc_data;
57 
58  size_t offset;
59  size_t d_size;
60  T *data;
61  bool do_delete;
62 
63  inline void DelArray() {
64  if ((alloc_data != NULL) && (do_delete)) {
65  delete[] (alloc_data);
66  }
67  alloc_data = NULL;
68  data = NULL;
69  }
70 
71  inline void AllocArray(const size_t newsize) {
72  try {
73  alloc_data = new T[newsize];
74  }
75  catch (std::bad_alloc &) {
76  Throw_RC_Type(Memory, "Allocation error");
77  }
78  data = alloc_data + offset;
79  d_alloc = newsize;
80  do_delete = true;
81  }
82 
83  void Initialize(size_t new_d_size) {
84  offset = 0;
85  d_size = new_d_size;
86 
87  if (d_size > 0) {
88  AllocArray(d_size);
89  }
90  else {
91  d_alloc = 0;
92  alloc_data = NULL;
93  data = NULL;
94  }
95 
96  rev_ptr = this;
97  rev_ptr.AutoRevoke();
98  }
99 
100  /// @endcond
101  public:
102 
103  // Default constructor, which initializes to zero elements.
104  inline Data1D() {
105  Initialize(0);
106  }
107 
108  /// Constructor which sets the initial size to d_size.
109  /** @param d_size The initial number of elements.
110  */
111  explicit inline Data1D(size_t d_size) {
112  Initialize(d_size);
113  }
114 
115  /// Copy constructor that copies all elements.
116  /** @param copy A source Data1D from which elements should be copied.
117  */
118  inline Data1D(const Data1D<T>& copy)
119  : offset (0),
120  d_size (copy.d_size) {
121  AllocArray(d_size);
122  std::copy(copy.data, copy.data + copy.d_size, data);
123 
124  rev_ptr = this;
125  rev_ptr.AutoRevoke();
126  }
127 
128 #ifdef CPP11
129  /// Initializer list constructor, for initializing with bracketed data.
130  /** @param new_data An initialization list of the form {elem1, elem2, ...}.
131  */
132  inline Data1D(const std::initializer_list<T>& new_data)
133  : offset(0),
134  d_size(new_data.size()) {
135  AllocArray(d_size);
136  std::copy(new_data.begin(), new_data.end(), data);
137 
138  rev_ptr = this;
139  rev_ptr.AutoRevoke();
140  }
141 
142 
143  /// Move constructor that reassigns all the data to this Data1D.
144  /** @param other A source Data1D from which elements should be moved.
145  */
146  inline Data1D(Data1D<T>&& other)
147  : rev_ptr(other.rev_ptr)
148  , d_alloc(other.d_alloc)
149  , alloc_data(other.alloc_data)
150  , offset(other.offset)
151  , d_size(other.d_size)
152  , data(other.data)
153  , do_delete(other.do_delete) {
154 
155  rev_ptr.AutoRevoke();
156  other.rev_ptr.AutoRevoke(false);
157  other.d_alloc = 0;
158  other.alloc_data = NULL;
159  other.do_delete = false;
160  other.offset = 0;
161  other.d_size = 0;
162  other.data = NULL;
163  }
164 #endif // CPP11
165 
166  /// Efficiently wraps in-place C-pointer data in a bounds-safe container.
167  /** Note: If auto_delete=true, new_data must have been acquired with
168  * new[]. delete[] is used internally, so behavior may vary if it was
169  * acquired with new, malloc, or others.
170  * @param d_size The initial number of elements.
171  * @param new_data C-pointer data to wrap.
172  * @param auto_delete Should the Data1D delete new_data upon destruction?
173  */
174  inline Data1D(size_t d_size, T* new_data, bool auto_delete = false)
175  : d_alloc (d_size),
176  alloc_data (new_data),
177  offset (0),
178  d_size (d_size),
179  data (new_data),
180  do_delete (auto_delete) {
181 
182  rev_ptr = this;
183  rev_ptr.AutoRevoke();
184  }
185 
186 
187  /// Delete all the elements and free all allocated memory.
188  inline void Delete() {
189  d_size = 0;
190  d_alloc = 0;
191  offset = 0;
192  DelArray();
193  }
194 
195 
196  /// Deletes all contents upon destruction.
197  /** Note: For wrapped pointers, if auto_delete was false no deletion
198  * of the original data occurs.
199  */
200  inline ~Data1D() {
201  Delete();
202  }
203 
204 
205 
206  /// Returns true if there are no elements / the size is 0.
207  inline bool IsEmpty() const {
208  return (d_size == 0);
209  }
210 
211 
212  /// Returns the first index at or after start_at for which the data
213  /// equals elem.
214  /** @param elem The element to compare to each entry in this Data1D
215  * @param start_at The first index to begin comparing at.
216  * @return The index of the item found, or npos if no matching
217  * data is found.
218  */
219  template<class T2>
220  inline size_t Find(const T2& elem, size_t start_at=0) const {
221  for (size_t i=start_at; i<d_size; i++) {
222  if (data[i] == elem) {
223  return i;
224  }
225  }
226  return npos;
227  }
228 
229  /// Returns true if at least one entry equals elem.
230  template<class T2>
231  inline bool Contains(const T2& elem) const {
232  return (Find(elem) != npos);
233  }
234 
235 
236  /// Check if index x is in bounds.
237  /** @param x The index to check.
238  * @return True if in bounds.
239  */
240  inline bool Check(const size_t x) const {
241  if (x < d_size) {
242  return true;
243  }
244  else {
245  return false;
246  }
247  }
248 
249 
250  protected:
251  /// @cond PROTECTED
252  inline void OutOfBounds() const {
253  Throw_RC_Type(Bounds, "Out of bounds");
254  }
255  /// @endcond
256  public:
257 
258 
259  /// Throws an ErrorMsgBounds exception if x is out of bounds.
260  /** @param x The index to check.
261  */
262  inline void Assert(const size_t x) const {
263  if ( ! Check(x) ) {
264  OutOfBounds();
265  }
266  }
267 
268  /// Reserve storage without resizing the array.
269  /** @param reserve_size The number of elements worth of storage to reserve.
270  **/
271  inline void Reserve(const size_t reserve_size) {
272  T *tmp;
273  size_t reserve_offset = reserve_size + offset;
274 
275  if (reserve_offset <= d_alloc) {
276  return;
277  }
278 
279  tmp = new T[reserve_offset];
280 #ifdef CPP11
281  std::move(alloc_data, alloc_data + d_alloc, tmp);
282 #else
283  std::copy(alloc_data, alloc_data + d_alloc, tmp);
284 #endif
285  d_alloc = reserve_offset;
286 
287  DelArray();
288 
289  alloc_data = tmp;
290  data = alloc_data + offset;
291  do_delete = true;
292  }
293 
294 
295  /// Resize the array, reallocating if necessary.
296  /** This may trigger a copy operation upon expansion. For efficiency it
297  * never reallocates or copies while shrinking or expanding within a
298  * previous size range. Use Crop if necessary to shrink storage to the
299  * current size.
300  * @param resize_size The new number of elements.
301  */
302  inline void Resize(const size_t resize_size) {
303  Reserve(resize_size);
304  d_size = resize_size;
305  }
306 
307 
308  /// Set a new offset position for index 0.
309  /** This also adjusts the size to reach the same last element.
310  * @param new_offset The new absolute offset from the 0th allocated
311  * element.
312  * @see SetRange
313  */
314  inline void SetOffset(const size_t new_offset) {
315  if (new_offset > d_alloc) {
316  OutOfBounds();
317  }
318 
319  if ( (d_size + offset) > new_offset ) {
320  d_size += offset - new_offset;
321  }
322  else {
323  d_size = 0;
324  }
325 
326  offset = new_offset;
327  data = alloc_data + offset;
328  }
329 
330 
331  /// Set a new offset and data size, resizing if necessary.
332  /** @param new_offset The new absolute offset from the 0th allocated
333  * element.
334  * @param new_size The new number of elements.
335  * @see SetOffset
336  * @see Resize
337  */
338  inline void SetRange(const size_t new_offset, const size_t new_size) {
339  if (new_offset > d_alloc) {
340  OutOfBounds();
341  }
342  offset = new_offset;
343  data = alloc_data + offset;
344 
345  Resize(new_size);
346  }
347 
348 
349  /// Access a raw unprotected C-pointer to the enclosed data.
350  /** Warning: This convenience function bypasses the bounds protections
351  * provided by this class. The returned pointer is likely to become
352  * invalid after any of the operations on this object which change the
353  * size.
354  * @return C-style pointer to the contents at the offset (0 by default).
355  */
356  inline T* Raw() const { return data; }
357 
358  /// Returns the current number of elements.
359  inline size_t size() const { return d_size; }
360  /// Returns the size of this Data1D's type.
361  inline size_t TypeSize() const { return sizeof(T); }
362  /// Returns the current size in bytes.
363  inline size_t ByteSize() const { return d_size*sizeof(T); }
364  /// Returns the number of elements for which space is reserved.
365  inline size_t reserved() const { return d_alloc; }
366  /// Returns the current allocated storage in bytes.
367  inline size_t ByteReserved() const { return d_alloc*sizeof(T); }
368  /// Returns the current offset for index 0.
369  /** @see SetOffset
370  * @see SetRange
371  **/
372  inline size_t GetOffset() const { return offset; }
373 
374 
375  /// Creates a duplicate copy of the contents, with up to amnt elements
376  /// from pos.
377  inline Data1D Copy (const size_t pos=0, const size_t amnt=npos) const {
378  Data1D<T> dup;
379  dup.CopyFrom(*this, pos, amnt);
380  return dup;
381  }
382 
383 
384  /// Copy data from any type with a compatible assignment operator.
385  /** @param other The compatible Data1D from which data should be copied.
386  * @return A reference to this Data1D.
387  */
388  template <class T2>
389  inline Data1D& CopyFrom (const Data1D<T2>& other) {
390  if (reinterpret_cast<void*>(data) ==
391  reinterpret_cast<void*>(other.Raw())) {
392  return *this;
393  }
394 
395  if (d_alloc < other.size()) {
396  DelArray();
397 
398  AllocArray(other.size());
399  }
400  d_size = other.size();
401  offset = 0;
402 
403  std::copy(other.Raw(), other.Raw() + other.size(), data);
404 
405  rev_ptr = this;
406  rev_ptr.AutoRevoke();
407 
408  return *this;
409  }
410 
411 
412  /// assignment operator.
413  /** Note, to copy data around in the same Data1D, use CopyData.
414  * @param other The compatible Data1D from which data should be copied.
415  * @param pos The offset in other to start copying from.
416  * @param num_elem The number of elements to copy.
417  * @return A reference to this Data1D.
418  */
419  template <class T2>
420  inline Data1D& CopyFrom (const Data1D<T2>& other,
421  size_t pos, size_t num_elem=npos) {
422  if (reinterpret_cast<void*>(data) ==
423  reinterpret_cast<void*>(other.Raw())) {
424  if (pos == 0 && num_elem > d_size) {
425  return *this;
426  }
427  else {
428  Throw_RC_Type(Bounds, "CopyFrom on a subset of the same underlying "
429  "data is invalid. Use CopyData.");
430  }
431  }
432 
433  // If out of bounds, but copying no elements, just blank the array.
434  // Otherwise, throw exception.
435  if ( ! other.Check(pos) ) {
436  if (num_elem == 0) {
437  d_size = 0;
438  offset = 0;
439  return *this;
440  }
441  else {
442  other.Assert(pos);
443  }
444  }
445 
446  size_t real_num_elem = num_elem;
447  if (num_elem > (other.size()-pos)) {
448  real_num_elem = other.size() - pos;
449  }
450 
451  if (d_alloc < real_num_elem) {
452  DelArray();
453 
454  AllocArray(real_num_elem);
455  }
456  d_size = real_num_elem;
457  offset = 0;
458 
459  std::copy(other.Raw()+pos, other.Raw()+pos+real_num_elem, data);
460 
461  rev_ptr = this;
462  rev_ptr.AutoRevoke();
463 
464  return *this;
465  }
466 
467 
468  /// Overwrite a range of data using all data from any compatible type,
469  /// expanding if necessary.
470  /** @param pos The offset in this Data1D to begin overwriting.
471  * @param other The compatible Data1D to copy from.
472  */
473  template <class T2>
474  inline void CopyAt (const size_t pos, const Data1D<T2>& other) {
475  if (pos > d_size) {
476  OutOfBounds();
477  }
478 
479  size_t other_size = other.size(); // cache for self-copy
480  size_t copy_end = pos + other_size;
481  if (d_size < copy_end) {
482  Resize(copy_end);
483  }
484 
485  std::copy(other.Raw(), other.Raw() + other_size, data + pos);
486  }
487 
488 
489  /// Overwrite a range of data from any compatible type, expanding if
490  /// necessary.
491  /** @param pos The offset in this Data1D to begin overwriting.
492  * @param other The compatible Data1D to copy from.
493  * @param other_start The offset in the other Data1D to begin copying
494  * from.
495  * @param amnt The quantity of data to copy (automatically
496  * bounds-capped, defaults to all).
497  */
498  template <class T2>
499  inline void CopyAt (const size_t pos, const Data1D<T2>& other,
500  const size_t other_start, const size_t amnt=npos) {
501  if (pos > d_size) {
502  OutOfBounds();
503  }
504 
505  other.Assert(other_start);
506 
507  size_t real_amnt = amnt;
508  size_t to_end = other.size() - other_start;
509 
510  if ( real_amnt > to_end) {
511  real_amnt = to_end;
512  }
513 
514  size_t copy_end = pos + real_amnt;
515  if (d_size < copy_end) {
516  Resize(copy_end);
517  }
518 
519  T2* s_first = other.Raw() + other_start;
520  T2* s_last = other.Raw() + other_start + real_amnt;
521  T* d_first = data + pos;
522  if (reinterpret_cast<void*>(d_first) >
523  reinterpret_cast<void*>(s_last) ||
524  reinterpret_cast<void*>(d_first) <=
525  reinterpret_cast<void*>(s_first)) {
526  std::copy(s_first, s_last, d_first);
527  }
528  else {
529  T* d_last = data + pos + real_amnt;
530  std::copy_backward(s_first, s_last, d_last);
531  }
532  }
533 
534 
535  /// Copy data from any location in this Data1D to another location,
536  /// handling overlap automatically.
537  /** @param dest The offset in this Data1D to begin overwriting.
538  * @param source The offset in this Data1D to copy from.
539  * @param amnt The quantity of data to copy (automatically
540  * bounds-capped, defaults to all).
541  */
542  inline void CopyData (const size_t dest, const size_t source,
543  const size_t amnt=npos) {
544  CopyAt(dest, *this, source, amnt);
545  }
546 
547 
548  /// Assignment operator which copies all contents from other, respecting
549  /// offsets.
550  /** @param other Data1D to copy from, from offset (default 0) to size.
551  * @return This object.
552  */
553  inline Data1D& operator= (const Data1D& other) {
554  return (*this).CopyFrom(other);
555  }
556 
557 
558 #ifdef CPP11
559  /// Assignment operator which copies all contents from other, respecting
560  /// offsets.
561  /** @param other Data1D to copy from, from offset (default 0) to size.
562  * @return This object.
563  */
564  inline Data1D& operator= (Data1D&& other) {
565  Delete();
566  swap(*this, other);
567  return *this;
568  }
569 #endif
570 
571 
572  /// Returns a new array with all the elements of this array assigned to
573  /// type T2.
574  /** @see CopyFrom
575  */
576  template<class T2>
577  inline Data1D<T2> Cast() {
578  Data1D<T2> retval;
579  return retval.CopyFrom(*this);
580  }
581 
582 #ifdef CPP11
583  /// Returns a new array with all the elements of this array converted
584  /// to another type by converter.
585  template<class Conv>
586  inline auto CastWith(Conv converter) -> Data1D<decltype(converter(*data))> {
587  Data1D<decltype(converter(*data))> retval(d_size);
588  for (size_t i=0; i<d_size; i++) {
589  retval[i] = converter(data[i]);
590  }
591  return retval;
592  }
593 #endif // CPP11
594 
595  /// Returns a new array with the raw data of this Data1D reinterpreted
596  /// as type T2.
597  /** Warning, this carries the same risks and caveats as C-type casting
598  * the raw data before assignment, and has undefined behavior for
599  * non-POD types in an ambiguous state. If the data sizes do not fit
600  * to an integral size of the returned type then there will be extra
601  * undefined bytes at the end of the returned data.
602  * @see Put
603  * @see Get
604  */
605  template<class T2>
606  inline Data1D<T2> Reinterpret() const {
607  size_t bytesize = d_size * sizeof(T);
608  size_t newsize = bytesize / sizeof(T2) +
609  (((bytesize % sizeof(T2))>0)?1:0);
610  Data1D<T2> retval(newsize);
611  unsigned char *srcptr = reinterpret_cast<unsigned char*>(data);
612  unsigned char *destptr = reinterpret_cast<unsigned char*>(retval.Raw());
613  std::copy(srcptr, srcptr+bytesize, destptr);
614  return retval;
615  }
616 
617 
618  /// Copy data from any other object of a type with a compatible
619 
620  /// Return a bounds-checked random-access iterator starting at offset.
621  /** Note that the iterator is revokable, meaning use of it will throw an
622  * exception if this Data1D is deleted.
623  * @return A bounds-checked iterator.
624  * @see end()
625  */
626  inline RAIter<Data1D<T>,T> begin() {
627  return RAIter<Data1D<T>,T> (rev_ptr, 0);
628  }
629  /// Const version of begin.
630  inline const RAIter<Data1D<T>,T> begin() const {
631  return RAIter<Data1D<T>,T> (rev_ptr, 0);
632  }
633 
634 
635  /// Return a bounds-checked random-access iterator starting just past
636  /// the last element.
637  /** Note that the iterator is revokable, meaning use of it will throw an
638  * exception if this Data1D is deleted.
639  * @return A bounds-checked iterator.
640  * @see begin()
641  */
642  inline RAIter<Data1D<T>,T> end() {
643  return RAIter<Data1D<T>,T> (rev_ptr, d_size);
644  }
645  /// Const version end.
646  inline const RAIter<Data1D<T>,T> end() const {
647  return RAIter<Data1D<T>,T> (rev_ptr, d_size);
648  }
649 
650 
651  /// Bounds-checked access of the element at index x from the offset
652  /// (default 0).
653  /** Throws an ErrorMsgBounds exception if x is out of bounds.
654  * @param x Index to access, where 0 is the element at offset.
655  * @return Reference to the element at index x.
656  */
657  inline T& operator[] (size_t x) { Assert(x); return data[x]; }
658  /// Identical to Data1D::operator[]
659  inline T& operator() (size_t x) { Assert(x); return data[x]; }
660  /// Const version of Data1D::operator[]
661  inline const T& operator[] (size_t x) const { Assert(x); return data[x]; }
662  /// Const version of Data1D::operator[]
663  inline const T& operator() (size_t x) const { Assert(x); return data[x]; }
664  /// Identical to Data1D::operator[]
665  inline T& At(size_t x) { Assert(x); return data[x]; }
666  /// Const version of Data1D::operator[]
667  inline const T& At(size_t x) const { Assert(x); return data[x]; }
668 
669 
670  /// Provides the last element.
671  /** @return A reference to the last element.
672  */
673  inline T& Last() { Assert(d_size-1); return data[d_size-1]; }
674  /// Const version of last()
675  inline const T& Last() const { Assert(d_size-1); return data[d_size-1]; }
676 
677 
678  /// Sets all elements equal to 0.
679  /** Note: Types for Data1D do not need to have a defined assignment
680  * operator which can receive a 0 unless this function is called
681  * for that Data1D instance.
682  */
683  inline void Zero() {
684  size_t i;
685 
686  for (i=0; i<d_size; i++) {
687  data[i] = 0;
688  }
689  }
690 
691  /// Like Zero() but operating only between index start and end, inclusive.
692  /** If end is unspecified, defaults to the end of the data. If either is
693  * out of bounds, ErrorMsgBounds is thrown.
694  */
695  inline void ZeroRange(const size_t start, const size_t end=npos) {
696  Assert(start);
697  if (end == 0 || end < start) {
698  OutOfBounds();
699  }
700  size_t realend = end;
701  if (realend == size_t(-1)) {
702  realend = d_size-1;
703  }
704  Assert(end);
705 
706  for (size_t i=start; i<=end; i++) {
707  data[i] = 0;
708  }
709  }
710 
711 
712  /// Sorts the elements according to T::operator< in N*log2(N) time.
713  inline void Sort() {
714  std::sort(data, data + d_size);
715  }
716 
717  /// Sorts the elements according to the binary comparitor comp.
718  /** comp should return true if less, and should not modify the elements
719  * passed.
720  */
721  template <class Comparator>
722  inline void Sort(Comparator comp) {
723  std::sort(data, data + d_size, comp);
724  }
725 
726 
727  /// Randomizes the order of all the elements.
728  /** Performs a Mersenne Twister random shuffle of the elements,
729  * microsecond time-seeded on the first call.
730  */
731  inline void Shuffle() {
732 #ifdef CPP11
733  std::shuffle(data, data + d_size, RND_Gen());
734 #else
735  std::random_shuffle(data, data + d_size, RND_Get_Range);
736 #endif
737  }
738 #ifdef unix
739  /// Randomizes the order of all the elements using /dev/urandom.
740  /** Uses /dev/urandom, available on many unix implementations, to perform
741  * a shuffle which is reseeded with environmental randomness.
742  */
743  inline void URandShuffle() {
744 #ifdef CPP11
745  std::shuffle(data, data + d_size, URand_Gen());
746 #else
747  std::random_shuffle(data, data + d_size, URand_Get_Range);
748 #endif
749  }
750 #endif
751 
752 
753  /// Removes ownership of the contained data from the Data1D object.
754  /** Note, the array returned becomes the responsibility of the calling
755  * function, and should be delete[]'d externally! The pointer
756  * returned is as if the offset were set to 0 first. This Data1D
757  * is empty after calling this.
758  */
759  inline T* Extract() {
760  T* retval = alloc_data;
761  alloc_data = NULL;
762  data = NULL;
763  d_size = 0;
764  d_alloc = 0;
765  offset = 0;
766  return retval;
767  }
768 
769 
770  /// Reduces memory consumption to only that necessary for size() elements.
771  /** After calling, offset is 0 and points to the element indexed as 0
772  * before calling. Efficiency note: This function may copy all elements
773  * if necessary for reallocating.
774  */
775  inline void Crop() {
776  T *tmp;
777 
778  if ((offset == 0) && (d_alloc <= d_size)) {
779  return;
780  }
781 
782  d_alloc = d_size;
783 
784  if (d_alloc == 0) {
785  Delete();
786  return;
787  }
788 
789  tmp = new T[d_alloc];
790 
791 #ifdef CPP11
792  std::move(data, data + d_size, tmp);
793 #else
794  std::copy(data, data + d_size, tmp);
795 #endif
796 
797  DelArray();
798 
799  alloc_data = tmp;
800  offset = 0;
801  data = alloc_data;
802  do_delete = true;
803  }
804 
805 
806  /// Identical to Delete().
807  inline void Clear() {
808  Delete();
809  }
810 
811 
812  /// Add an element to the end, expanding if necessary.
813  /** Efficiency note: Expands by doubling for linear efficiency.
814  * @param newT The new element to append to the end.
815  * @see Reserve
816  */
817  inline void Append(const T& newT) {
818  size_t growto;
819  size_t offset_size = d_size + offset;
820 
821  if (d_alloc <= offset_size) {
822  growto = d_size << 1;
823  if (growto <= d_size) {
824  growto = d_size + 1;
825  }
826  Reserve(growto);
827  }
828 
829  data[d_size++] = newT;
830  }
831 
832 
833  /// Append data from any type with a compatible assignment operator.
834  /** @param other The compatible Data1D from which data should be copied.
835  */
836  template <class T2>
837  inline void AppendFrom (const Data1D<T2>& other) {
838  size_t last_d_size = d_size;
839  size_t other_size = other.size();
840 
841  Resize(d_size + other_size);
842 
843  std::copy(other.Raw(), other.Raw() + other_size, data + last_d_size);
844  }
845 
846 
847  /// Appends all elements in other to the end, expanding if necessary.
848  /** @param other The Data1D to append to the end.
849  */
850  inline void Append(const Data1D& other) {
851  AppendFrom(other);
852  }
853 
854 
855  /// Assign newT to index pos, expanding if necessary to reach that index.
856  /** @param pos The index to which newT should be assigned.
857  * @param newT The new element to assign.
858  */
859  inline void ExpandSet(size_t pos, const T& newT) {
860  if (!Check(pos)) {
861  Resize(pos+1);
862  }
863  data[pos] = newT;
864  }
865 
866 
867  /// Inserts newT at position pos, shifting the other elements.
868  /** Efficiency note: For random positions, on average O(N).
869  * @param pos The index at which newT should be inserted.
870  * @param newT The new element to insert.
871  */
872  inline void Insert(size_t pos, const T& newT) {
873  Assert(pos);
874 
875  Resize(d_size + 1);
876 
877  std::copy_backward(data+pos, data+size(), data+size()+1);
878  data[pos] = newT;
879  }
880 
881 
882  /// Removes the element at pos from the array, shrinking the size.
883  /** Efficiency note: For random positions, on average O(N).
884  * @param pos The index at which an element should be removed.
885  */
886  inline void Remove(size_t pos) {
887  Assert(pos);
888  if (Check(pos+1)) {
889 #ifdef CPP11
890  std::move(data+pos+1, data+size(), data+pos);
891 #else
892  std::copy(data+pos+1, data+size(), data+pos);
893 #endif
894  }
895  Resize(d_size - 1);
896  }
897 
898 
899  /// Add an element to the end, expanding if necessary.
900  /** Efficiency note: Expands by doubling for linear efficiency.
901  * @param newT The new element to append to the end.
902  * @return A reference to this Data1D.
903  * @see Reserve
904  */
905  inline Data1D<T>& operator+= (const T& newT) {
906  Append(newT);
907  return (*this);
908  }
909 
910 
911  /// Appends all elements in other to the end, expanding if necessary.
912  /** @param other The Data1D to append to the end.
913  * @return A reference to this Data1D.
914  */
915  inline Data1D<T>& operator+= (const Data1D& other) {
916  Append(other);
917  return (*this);
918  }
919 
920 
921  /// Create a new array from this Data1D concatenated with other after it.
922  inline Data1D<T> operator+ (const Data1D& other) const {
923  Data1D<T> retval(size()+other.size());
924  retval.CopyAt(0, *this);
925  retval.CopyAt(size(), other);
926  return retval;
927  }
928 
929 
930  /// Convert endianness of all elements if needed, for supported types.
931  inline void ToLilEndian() {
932  if (Endian::IsBig()) {
933  for (size_t i=0; i<d_size; i++) {
934  data[i] = Endian::ToLittle(data[i]);
935  }
936  }
937  }
938  /// Convert endianness of all elements if needed, for supported types.
939  inline void FromLilEndian() { ToLilEndian(); }
940 
941  /// Convert endianness of all elements if needed, for supported types.
942  inline void ToBigEndian() {
943  if (Endian::IsLittle()) {
944  for (size_t i=0; i<d_size; i++) {
945  data[i] = Endian::ToBig(data[i]);
946  }
947  }
948  }
949  /// Convert endianness of all elements if needed, for supported types.
950  inline void FromBigEndian() { ToBigEndian(); }
951 
952 
953  /// Comparison operator for all elements.
954  /** Also returns false if they are differently sized. Works for
955  * AnyValidType with operator== defined with T.
956  * @param other The Data1D to compare all elements with.
957  * @return True if all elements are equal.
958  */
959  template<class AnyValidType>
960  inline bool operator== (const Data1D<AnyValidType>& other) const {
961  size_t i;
962 
963  if (d_size != other.d_size) {
964  return false;
965  }
966 
967  if (data == other.data) {
968  return true; // No need to compare equivalent memory.
969  }
970 
971  for (i=0; i<d_size; i++) {
972  if ( ! (data[i] == other.data[i]) ) {
973  return false;
974  }
975  }
976 
977  return true;
978  }
979 
980 
981  /// Returns true if the first different element for this is less than for
982  /// other.
983  /** If they are differently sized and identical through the common length,
984  * then the shorter one is considered less. Works for AnyValidType with
985  * defined operator< in both directions with T.
986  * @param other The Data1D to compare all elements with.
987  * @return True if the first non-equal element for this is less than for
988  * other.
989  */
990  template<class AnyValidType>
991  inline bool operator< (const Data1D<AnyValidType>& other) const {
992  size_t i, minsize;
993  bool left_smaller;
994 
995  if (d_size < other.d_size) {
996  minsize = d_size;
997  left_smaller = true;
998  }
999  else {
1000  if (data == other.data && d_size == other.d_size) {
1001  return false; // No need to compare equivalent memory.
1002  }
1003  minsize = other.d_size;
1004  left_smaller = false;
1005  }
1006 
1007 
1008  for (i=0; i<minsize; i++) {
1009  if (data[i] < other.data[i]) {
1010  return true;
1011  }
1012  else if (other.data[i] < data[i]) {
1013  return false;
1014  }
1015  }
1016 
1017 
1018  return left_smaller;
1019  }
1020 
1022 
1023 
1024  /// Direct raw data extraction of type T2 at index.
1025  /** Bounds are checked. But if the raw data at the index is invalid
1026  * for an assignment operation of type T2 (e.g., non-POD in ambiguous
1027  * state), then behavior is undefined.
1028  * @param store_at The reference to which data is written.
1029  * @param index_T The index from which the data is extracted.
1030  */
1031  template<class T2>
1032  inline void Get(T2& store_at, size_t index_T) const {
1033  size_t end_index = index_T + sizeof(T2) / sizeof(T) +
1034  (((sizeof(T2)%sizeof(T)) != 0) ? 1 : 0);
1035  if (end_index>0) { end_index--; }
1036  Assert(index_T); Assert(end_index);
1037  store_at = *reinterpret_cast<T2*>(data+index_T);
1038  }
1039  /// Identical to the Get which receives store_at, but this returns the
1040  /// extracted value.
1041  template<class T2>
1042  inline T2 Get(size_t index_T=0) const {
1043  T2 retval;
1044  Get(retval, index_T);
1045  return retval;
1046  }
1047  /// Fills the array store_at to its current size with raw assigned
1048  /// data of type T2 from this Data1D.
1049  /** Usage example: Data1D<u64> x(1); Data1D<u8> y(8); x.Get(y,0);
1050  * y.Get(x,0);
1051  * If store_at has size 0, it resizes and grabs all available data.
1052  */
1053  template<class T2>
1054  inline void Get(Data1D<T2>& store_at, size_t index_T=0) const {
1055  if (store_at.size() == 0) {
1056  store_at.Resize(((size()-index_T)*sizeof(T))/sizeof(T2));
1057  }
1058  size_t T2_fullsize = sizeof(T2)*store_at.size();
1059  size_t end_index = index_T + T2_fullsize / sizeof(T) +
1060  (((T2_fullsize%sizeof(T)) != 0) ? 1 : 0);
1061  if (end_index>0) { end_index--; }
1062  Assert(index_T); Assert(end_index);
1063  T2* T2_data_ptr = reinterpret_cast<T2*>(data+index_T);
1064  std::copy(T2_data_ptr, T2_data_ptr + store_at.size(), store_at.Raw());
1065  }
1066 
1067  /// Direct raw data insertion of type T2 at index.
1068  /** Bounds are checked. But if the raw data at the index is invalid
1069  * for an assignment operation of type T2 (e.g., not-POD in ambiguous
1070  * state), then behavior is undefined.
1071  * @param read_from The reference from which data is read.
1072  * @param index_T The index at which data is placed.
1073  * @return *this
1074  */
1075  template<class T2>
1076  inline Data1D<T>& Put(const T2& read_from, size_t index_T) {
1077  size_t end_index = index_T + sizeof(T2) / sizeof(T) +
1078  (((sizeof(T2)%sizeof(T)) != 0) ? 1 : 0);
1079  if (end_index>0) { end_index--; }
1080  Assert(index_T); Assert(end_index);
1081  *reinterpret_cast<T2*>(data+index_T) = read_from;
1082  return *this;
1083  }
1084  /// Like Get for a T2 type, but places sequential packed data.
1085  /** Copies the full array read_from with raw assigned data of type T2,
1086  * to this Data1D starting at index, resizing as needed to include all
1087  * of read_from.
1088  * Usage example: Data1D<u64> x(1); Data1D<u8> y(8); x.Put(y,0);
1089  * y.Put(x,0);
1090  * @return *this
1091  */
1092  template<class T2>
1093  inline Data1D<T>& Put(const Data1D<T2>& read_from, size_t index_T=0) {
1094  size_t T2_fullsize = sizeof(T2)*read_from.size();
1095  size_t T1_sizeneeded = index_T + T2_fullsize / sizeof(T) +
1096  (((T2_fullsize%sizeof(T)) != 0) ? 1 : 0);
1097  if (d_size < T1_sizeneeded) {
1098  Resize(T1_sizeneeded);
1099  }
1100  T2* T2_data_ptr = reinterpret_cast<T2*>(data+index_T);
1101  std::copy(read_from.Raw(), read_from.Raw()+read_from.size(), T2_data_ptr);
1102  return *this;
1103  }
1104 
1105 
1106  /// Efficiently swap all the contents of a and b.
1107  template <class T2> friend void swap (Data1D<T2> &a, Data1D<T2> &b);
1108 
1109  /// The largest possible value of size_t.
1110  static const size_t npos = size_t(-1);
1111  };
1112 
1113 
1114  /// Outputs all chars to a stream without terminating at null.
1115  /** Usage like: Data1D<char> data; std::cout << data << std::endl;
1116  */
1117  inline std::ostream& operator<< (std::ostream &out, const Data1D<char>& d) {
1118  size_t i;
1119  for (i=0; i<d.size(); i++) {
1120  out << d[i];
1121  }
1122  return out;
1123  }
1124 
1125  /// Outputs data to a stream as { 61, 62, ... }
1126  /** Usage like: Data1D<u8> data; std::cout << data << std::endl;
1127  */
1128  inline std::ostream& operator<< (std::ostream &out, const Data1D<u8>& d) {
1129  size_t i;
1130 
1131  if (d.size() == 0) {
1132  out << "{ }";
1133  }
1134  else {
1135  out << "{ " << u16(d[0]);
1136  for (i=1; i<d.size(); i++) {
1137  out << ", " << u16(d[i]);
1138  }
1139  out << " }";
1140  }
1141 
1142  return out;
1143  }
1144 
1145  /// Outputs data to a stream as { 61, -42, ... }
1146  /** Usage like: Data1D<i8> data; std::cout << data << std::endl;
1147  */
1148  inline std::ostream& operator<< (std::ostream &out, const Data1D<i8>& d) {
1149  size_t i;
1150 
1151  if (d.size() == 0) {
1152  out << "{ }";
1153  }
1154  else {
1155  out << "{ " << i16(d[0]);
1156  for (i=1; i<d.size(); i++) {
1157  out << ", " << i16(d[i]);
1158  }
1159  out << " }";
1160  }
1161 
1162  return out;
1163  }
1164 
1165 
1166  /// Outputs data to a stream as { elem0, elem1, ... }
1167  /** Usage like: Data1D<RStr> data; std::cout << data << std::endl;
1168  */
1169  template <class T>
1170  inline std::ostream& operator<< (std::ostream &out, const Data1D<T>& d) {
1171  size_t i;
1172 
1173  if (d.size() == 0) {
1174  out << "{ }";
1175  }
1176  else {
1177  out << "{ " << d[0];
1178  for (i=1; i<d.size(); i++) {
1179  out << ", " << d[i];
1180  }
1181  out << " }";
1182  }
1183 
1184  return out;
1185  }
1186 
1187 
1188  /// Efficiently swap all the contents of a and b.
1189  template <class T>
1191  std::swap(a.do_delete, b.do_delete);
1192  std::swap(a.d_size, b.d_size);
1193  std::swap(a.d_alloc, b.d_alloc);
1194  std::swap(a.offset, b.offset);
1195  std::swap(a.data, b.data);
1196  std::swap(a.alloc_data, b.alloc_data);
1197  }
1198 
1199 #ifdef CPP11
1200  /// Convenience generator for safely converting C-style arrays.
1201  template<class T, size_t N> auto MakeData1D(T (&arr)[N]) -> RC::Data1D<T> {
1202  return RC::Data1D<T>(N,arr);
1203  }
1204 #endif
1205 
1206 }
1207 
1208 
1209 
1210 #endif // RC_DATA1D_H
1211 
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:335
Provides a bounds-checked iterator that knows when its target was deleted.
Provides a set of convenience macros for metaprogramming and debugging.
#define RC_DEFAULT_COMPARISON()
Given == and <, generates !=, >, <=, and >=.
Definition: Macros.h:246
The version information and configuration settings for RC Lib.
Provides typedefs and routines for working with primitives.
uint64_t u64
64-bit unsigned integer.
Definition: Types.h:31
uint16_t u16
16-bit unsigned integer.
Definition: Types.h:27
int16_t i16
16-bit signed integer.
Definition: Types.h:26
A bounds-safe one-dimensional vector-like structure.
Definition: Data1D.h:49
Data1D< T2 > Reinterpret() const
Returns a new array with the raw data of this Data1D reinterpreted as type T2.
Definition: Data1D.h:606
void CopyAt(const size_t pos, const Data1D< T2 > &other, const size_t other_start, const size_t amnt=npos)
Overwrite a range of data from any compatible type, expanding if necessary.
Definition: Data1D.h:499
friend void swap(Data1D< T2 > &a, Data1D< T2 > &b)
Efficiently swap all the contents of a and b.
void SetRange(const size_t new_offset, const size_t new_size)
Set a new offset and data size, resizing if necessary.
Definition: Data1D.h:338
void Append(const T &newT)
Add an element to the end, expanding if necessary.
Definition: Data1D.h:817
T * Extract()
Removes ownership of the contained data from the Data1D object.
Definition: Data1D.h:759
void ZeroRange(const size_t start, const size_t end=npos)
Like Zero() but operating only between index start and end, inclusive.
Definition: Data1D.h:695
T & At(size_t x)
Identical to Data1D::operator[].
Definition: Data1D.h:665
void ToBigEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:942
T & operator()(size_t x)
Identical to Data1D::operator[].
Definition: Data1D.h:659
void Append(const Data1D &other)
Appends all elements in other to the end, expanding if necessary.
Definition: Data1D.h:850
void Clear()
Identical to Delete().
Definition: Data1D.h:807
void Crop()
Reduces memory consumption to only that necessary for size() elements.
Definition: Data1D.h:775
bool Check(const size_t x) const
Check if index x is in bounds.
Definition: Data1D.h:240
const T & Last() const
Const version of last()
Definition: Data1D.h:675
Data1D(size_t d_size, T *new_data, bool auto_delete=false)
Efficiently wraps in-place C-pointer data in a bounds-safe container.
Definition: Data1D.h:174
size_t TypeSize() const
Returns the size of this Data1D's type.
Definition: Data1D.h:361
Data1D< T > operator+(const Data1D &other) const
Create a new array from this Data1D concatenated with other after it.
Definition: Data1D.h:922
size_t GetOffset() const
Returns the current offset for index 0.
Definition: Data1D.h:372
bool operator==(const Data1D< AnyValidType > &other) const
Comparison operator for all elements.
Definition: Data1D.h:960
void CopyAt(const size_t pos, const Data1D< T2 > &other)
Overwrite a range of data using all data from any compatible type, expanding if necessary.
Definition: Data1D.h:474
void URandShuffle()
Randomizes the order of all the elements using /dev/urandom.
Definition: Data1D.h:743
bool IsEmpty() const
Returns true if there are no elements / the size is 0.
Definition: Data1D.h:207
void Get(Data1D< T2 > &store_at, size_t index_T=0) const
Fills the array store_at to its current size with raw assigned data of type T2 from this Data1D.
Definition: Data1D.h:1054
RAIter< Data1D< T >, T > end()
Return a bounds-checked random-access iterator starting just past the last element.
Definition: Data1D.h:642
void Delete()
Delete all the elements and free all allocated memory.
Definition: Data1D.h:188
void Zero()
Sets all elements equal to 0.
Definition: Data1D.h:683
Data1D< T > & Put(const T2 &read_from, size_t index_T)
Direct raw data insertion of type T2 at index.
Definition: Data1D.h:1076
void AppendFrom(const Data1D< T2 > &other)
Append data from any type with a compatible assignment operator.
Definition: Data1D.h:837
Data1D Copy(const size_t pos=0, const size_t amnt=npos) const
Creates a duplicate copy of the contents, with up to amnt elements from pos.
Definition: Data1D.h:377
size_t ByteReserved() const
Returns the current allocated storage in bytes.
Definition: Data1D.h:367
void Sort()
Sorts the elements according to T::operator< in N*log2(N) time.
Definition: Data1D.h:713
size_t ByteSize() const
Returns the current size in bytes.
Definition: Data1D.h:363
void Insert(size_t pos, const T &newT)
Inserts newT at position pos, shifting the other elements.
Definition: Data1D.h:872
Data1D< T2 > Cast()
Returns a new array with all the elements of this array assigned to type T2.
Definition: Data1D.h:577
void Shuffle()
Randomizes the order of all the elements.
Definition: Data1D.h:731
Data1D< T > & Put(const Data1D< T2 > &read_from, size_t index_T=0)
Like Get for a T2 type, but places sequential packed data.
Definition: Data1D.h:1093
auto CastWith(Conv converter) -> Data1D< decltype(converter(*data))>
Returns a new array with all the elements of this array converted to another type by converter.
Definition: Data1D.h:586
~Data1D()
Deletes all contents upon destruction.
Definition: Data1D.h:200
T * Raw() const
Access a raw unprotected C-pointer to the enclosed data.
Definition: Data1D.h:356
const RAIter< Data1D< T >, T > end() const
Const version end.
Definition: Data1D.h:646
T & operator[](size_t x)
Bounds-checked access of the element at index x from the offset (default 0).
Definition: Data1D.h:657
static const size_t npos
The largest possible value of size_t.
Definition: Data1D.h:1110
Data1D & operator=(const Data1D &other)
Assignment operator which copies all contents from other, respecting offsets.
Definition: Data1D.h:553
Data1D & CopyFrom(const Data1D< T2 > &other, size_t pos, size_t num_elem=npos)
assignment operator.
Definition: Data1D.h:420
void Reserve(const size_t reserve_size)
Reserve storage without resizing the array.
Definition: Data1D.h:271
void SetOffset(const size_t new_offset)
Set a new offset position for index 0.
Definition: Data1D.h:314
Data1D(size_t d_size)
Constructor which sets the initial size to d_size.
Definition: Data1D.h:111
size_t size() const
Returns the current number of elements.
Definition: Data1D.h:359
const RAIter< Data1D< T >, T > begin() const
Const version of begin.
Definition: Data1D.h:630
void Assert(const size_t x) const
Throws an ErrorMsgBounds exception if x is out of bounds.
Definition: Data1D.h:262
T & Last()
Provides the last element.
Definition: Data1D.h:673
void ExpandSet(size_t pos, const T &newT)
Assign newT to index pos, expanding if necessary to reach that index.
Definition: Data1D.h:859
size_t Find(const T2 &elem, size_t start_at=0) const
Returns the first index at or after start_at for which the data equals elem.
Definition: Data1D.h:220
void Sort(Comparator comp)
Sorts the elements according to the binary comparitor comp.
Definition: Data1D.h:722
Data1D< T > & operator+=(const T &newT)
Add an element to the end, expanding if necessary.
Definition: Data1D.h:905
Data1D(Data1D< T > &&other)
Move constructor that reassigns all the data to this Data1D.
Definition: Data1D.h:146
void Resize(const size_t resize_size)
Resize the array, reallocating if necessary.
Definition: Data1D.h:302
Data1D(const Data1D< T > &copy)
Copy constructor that copies all elements.
Definition: Data1D.h:118
void FromLilEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:939
T2 Get(size_t index_T=0) const
Identical to the Get which receives store_at, but this returns the extracted value.
Definition: Data1D.h:1042
size_t reserved() const
Returns the number of elements for which space is reserved.
Definition: Data1D.h:365
const T & At(size_t x) const
Const version of Data1D::operator[].
Definition: Data1D.h:667
void Remove(size_t pos)
Removes the element at pos from the array, shrinking the size.
Definition: Data1D.h:886
bool Contains(const T2 &elem) const
Returns true if at least one entry equals elem.
Definition: Data1D.h:231
void FromBigEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:950
Data1D(const std::initializer_list< T > &new_data)
Initializer list constructor, for initializing with bracketed data.
Definition: Data1D.h:132
Data1D & CopyFrom(const Data1D< T2 > &other)
Copy data from any type with a compatible assignment operator.
Definition: Data1D.h:389
void CopyData(const size_t dest, const size_t source, const size_t amnt=npos)
Copy data from any location in this Data1D to another location, handling overlap automatically.
Definition: Data1D.h:542
void ToLilEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:931
bool operator<(const Data1D< AnyValidType > &other) const
Returns true if the first different element for this is less than for other.
Definition: Data1D.h:991
RAIter< Data1D< T >, T > begin()
Copy data from any other object of a type with a compatible.
Definition: Data1D.h:626
void Get(T2 &store_at, size_t index_T) const
Direct raw data extraction of type T2 at index.
Definition: Data1D.h:1032
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
A reference counting pointer that revokes (NULLs) all copies when one set to AutoRevoke(true) leaves ...
Definition: RevPtr.h:45
void AutoRevoke(bool new_auto_revoke=true)
Set this RevPtr to revoke the pointer upon deletion or leaving scope.
Definition: RevPtr.h:142
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
RND & RND_Gen()
This returns a singleton of RND .
Definition: RND.h:593
u64 RND_Get_Range(u64 range)
Uses RND as a RandomNumberGenerator, e.g. for random_shuffle.
Definition: RND.h:541
void swap(RC::Data1D< T > &a, RC::Data1D< T > &b)
Efficiently swap all the contents of a and b.
Definition: Data1D.h:1190
u64 URand_Get_Range(u64 range)
Uses URand as a RandomNumberGenerator, e.g. for random_shuffle.
Definition: RND.h:579
URand & URand_Gen()
This returns a singleton of URand .
Definition: RND.h:596
auto MakeData1D(T(&arr)[N]) -> RC::Data1D< T >
Convenience generator for safely converting C-style arrays.
Definition: Data1D.h:1201
email address
— (c) 2015