rcolyer.net
RC Lib  Version 202403231100
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  return *this;
425  }
426 
427  // If out of bounds, but copying no elements, just blank the array.
428  // Otherwise, throw exception.
429  if ( ! other.Check(pos) ) {
430  if (num_elem == 0) {
431  d_size = 0;
432  offset = 0;
433  return *this;
434  }
435  else {
436  other.Assert(pos);
437  }
438  }
439 
440  size_t real_num_elem = num_elem;
441  if (num_elem > (other.size()-pos)) {
442  real_num_elem = other.size() - pos;
443  }
444 
445  if (d_alloc < real_num_elem) {
446  DelArray();
447 
448  AllocArray(real_num_elem);
449  }
450  d_size = real_num_elem;
451  offset = 0;
452 
453  std::copy(other.Raw()+pos, other.Raw()+pos+real_num_elem, data);
454 
455  rev_ptr = this;
456  rev_ptr.AutoRevoke();
457 
458  return *this;
459  }
460 
461 
462  /// Overwrite a range of data using all data from any compatible type,
463  /// expanding if necessary.
464  /** @param pos The offset in this Data1D to begin overwriting.
465  * @param other The compatible Data1D to copy from.
466  */
467  template <class T2>
468  inline void CopyAt (const size_t pos, const Data1D<T2>& other) {
469  if (pos > d_size) {
470  OutOfBounds();
471  }
472 
473  size_t other_size = other.size(); // cache for self-copy
474  size_t copy_end = pos + other_size;
475  if (d_size < copy_end) {
476  Resize(copy_end);
477  }
478 
479  std::copy(other.Raw(), other.Raw() + other_size, data + pos);
480  }
481 
482 
483  /// Overwrite a range of data from any compatible type, expanding if
484  /// necessary.
485  /** @param pos The offset in this Data1D to begin overwriting.
486  * @param other The compatible Data1D to copy from.
487  * @param other_start The offset in the other Data1D to begin copying
488  * from.
489  * @param amnt The quantity of data to copy (automatically
490  * bounds-capped, defaults to all).
491  */
492  template <class T2>
493  inline void CopyAt (const size_t pos, const Data1D<T2>& other,
494  const size_t other_start, const size_t amnt=npos) {
495  if (pos > d_size) {
496  OutOfBounds();
497  }
498 
499  other.Assert(other_start);
500 
501  size_t real_amnt = amnt;
502  size_t to_end = other.size() - other_start;
503 
504  if ( real_amnt > to_end) {
505  real_amnt = to_end;
506  }
507 
508  size_t copy_end = pos + real_amnt;
509  if (d_size < copy_end) {
510  Resize(copy_end);
511  }
512 
513  T2* s_first = other.Raw() + other_start;
514  T2* s_last = other.Raw() + other_start + real_amnt;
515  T* d_first = data + pos;
516  if (reinterpret_cast<void*>(d_first) >
517  reinterpret_cast<void*>(s_last) ||
518  reinterpret_cast<void*>(d_first) <=
519  reinterpret_cast<void*>(s_first)) {
520  std::copy(s_first, s_last, d_first);
521  }
522  else {
523  T* d_last = data + pos + real_amnt;
524  std::copy_backward(s_first, s_last, d_last);
525  }
526  }
527 
528 
529  /// Copy data from any location in this Data1D to another location,
530  /// handling overlap automatically.
531  /** @param dest The offset in this Data1D to begin overwriting.
532  * @param source The offset in this Data1D to copy from.
533  * @param amnt The quantity of data to copy (automatically
534  * bounds-capped, defaults to all).
535  */
536  inline void CopyData (const size_t dest, const size_t source,
537  const size_t amnt=npos) {
538  CopyAt(dest, *this, source, amnt);
539  }
540 
541 
542  /// Assignment operator which copies all contents from other, respecting
543  /// offsets.
544  /** @param other Data1D to copy from, from offset (default 0) to size.
545  * @return This object.
546  */
547  inline Data1D& operator= (const Data1D& other) {
548  return (*this).CopyFrom(other);
549  }
550 
551 
552 #ifdef CPP11
553  /// Assignment operator which copies all contents from other, respecting
554  /// offsets.
555  /** @param other Data1D to copy from, from offset (default 0) to size.
556  * @return This object.
557  */
558  inline Data1D& operator= (Data1D&& other) {
559  Delete();
560  swap(*this, other);
561  return *this;
562  }
563 #endif
564 
565 
566  /// Returns a new array with all the elements of this array assigned to
567  /// type T2.
568  /** @see CopyFrom
569  */
570  template<class T2>
571  inline Data1D<T2> Cast() {
572  Data1D<T2> retval;
573  return retval.CopyFrom(*this);
574  }
575 
576 #ifdef CPP11
577  /// Returns a new array with all the elements of this array converted
578  /// to another type by converter.
579  template<class Conv>
580  inline auto CastWith(Conv converter) -> Data1D<decltype(converter(*data))> {
581  Data1D<decltype(converter(*data))> retval(d_size);
582  for (size_t i=0; i<d_size; i++) {
583  retval[i] = converter(data[i]);
584  }
585  return retval;
586  }
587 #endif // CPP11
588 
589  /// Returns a new array with the raw data of this Data1D reinterpreted
590  /// as type T2.
591  /** Warning, this carries the same risks and caveats as C-type casting
592  * the raw data before assignment, and has undefined behavior for
593  * non-POD types in an ambiguous state. If the data sizes do not fit
594  * to an integral size of the returned type then there will be extra
595  * undefined bytes at the end of the returned data.
596  * @see Put
597  * @see Get
598  */
599  template<class T2>
600  inline Data1D<T2> Reinterpret() const {
601  size_t bytesize = d_size * sizeof(T);
602  size_t newsize = bytesize / sizeof(T2) +
603  (((bytesize % sizeof(T2))>0)?1:0);
604  Data1D<T2> retval(newsize);
605  unsigned char *srcptr = reinterpret_cast<unsigned char*>(data);
606  unsigned char *destptr = reinterpret_cast<unsigned char*>(retval.Raw());
607  std::copy(srcptr, srcptr+bytesize, destptr);
608  return retval;
609  }
610 
611 
612  /// Copy data from any other object of a type with a compatible
613 
614  /// Return a bounds-checked random-access iterator starting at offset.
615  /** Note that the iterator is revokable, meaning use of it will throw an
616  * exception if this Data1D is deleted.
617  * @return A bounds-checked iterator.
618  * @see end()
619  */
620  inline RAIter<Data1D<T>,T> begin() {
621  return RAIter<Data1D<T>,T> (rev_ptr, 0);
622  }
623  /// Const version of begin.
624  inline const RAIter<Data1D<T>,T> begin() const {
625  return RAIter<Data1D<T>,T> (rev_ptr, 0);
626  }
627 
628 
629  /// Return a bounds-checked random-access iterator starting just past
630  /// the last element.
631  /** Note that the iterator is revokable, meaning use of it will throw an
632  * exception if this Data1D is deleted.
633  * @return A bounds-checked iterator.
634  * @see begin()
635  */
636  inline RAIter<Data1D<T>,T> end() {
637  return RAIter<Data1D<T>,T> (rev_ptr, d_size);
638  }
639  /// Const version end.
640  inline const RAIter<Data1D<T>,T> end() const {
641  return RAIter<Data1D<T>,T> (rev_ptr, d_size);
642  }
643 
644 
645  /// Bounds-checked access of the element at index x from the offset
646  /// (default 0).
647  /** Throws an ErrorMsgBounds exception if x is out of bounds.
648  * @param x Index to access, where 0 is the element at offset.
649  * @return Reference to the element at index x.
650  */
651  inline T& operator[] (size_t x) { Assert(x); return data[x]; }
652  /// Identical to Data1D::operator[]
653  inline T& operator() (size_t x) { Assert(x); return data[x]; }
654  /// Const version of Data1D::operator[]
655  inline const T& operator[] (size_t x) const { Assert(x); return data[x]; }
656  /// Const version of Data1D::operator[]
657  inline const T& operator() (size_t x) const { Assert(x); return data[x]; }
658  /// Identical to Data1D::operator[]
659  inline T& At(size_t x) { Assert(x); return data[x]; }
660  /// Const version of Data1D::operator[]
661  inline const T& At(size_t x) const { Assert(x); return data[x]; }
662 
663 
664  /// Provides the last element.
665  /** @return A reference to the last element.
666  */
667  inline T& Last() { Assert(d_size-1); return data[d_size-1]; }
668  /// Const version of last()
669  inline const T& Last() const { Assert(d_size-1); return data[d_size-1]; }
670 
671 
672  /// Sets all elements equal to 0.
673  /** Note: Types for Data1D do not need to have a defined assignment
674  * operator which can receive a 0 unless this function is called
675  * for that Data1D instance.
676  */
677  inline void Zero() {
678  size_t i;
679 
680  for (i=0; i<d_size; i++) {
681  data[i] = 0;
682  }
683  }
684 
685  /// Like Zero() but operating only between index start and end, inclusive.
686  /** If end is unspecified, defaults to the end of the data. If either is
687  * out of bounds, ErrorMsgBounds is thrown.
688  */
689  inline void ZeroRange(const size_t start, const size_t end=npos) {
690  Assert(start);
691  if (end == 0 || end < start) {
692  OutOfBounds();
693  }
694  size_t realend = end;
695  if (realend == size_t(-1)) {
696  realend = d_size-1;
697  }
698  Assert(end);
699 
700  for (size_t i=start; i<=end; i++) {
701  data[i] = 0;
702  }
703  }
704 
705 
706  /// Sorts the elements according to T::operator< in N*log2(N) time.
707  inline void Sort() {
708  std::sort(data, data + d_size);
709  }
710 
711  /// Sorts the elements according to the binary comparitor comp.
712  /** comp should return true if less, and should not modify the elements
713  * passed.
714  */
715  template <class Comparator>
716  inline void Sort(Comparator comp) {
717  std::sort(data, data + d_size, comp);
718  }
719 
720 
721  /// Randomizes the order of all the elements.
722  /** Performs a Mersenne Twister random shuffle of the elements,
723  * microsecond time-seeded on the first call.
724  */
725  inline void Shuffle() {
726 #ifdef CPP11
727  std::shuffle(data, data + d_size, RND_Gen());
728 #else
729  std::random_shuffle(data, data + d_size, RND_Get_Range);
730 #endif
731  }
732 #ifdef unix
733  /// Randomizes the order of all the elements using /dev/urandom.
734  /** Uses /dev/urandom, available on many unix implementations, to perform
735  * a shuffle which is reseeded with environmental randomness.
736  */
737  inline void URandShuffle() {
738 #ifdef CPP11
739  std::shuffle(data, data + d_size, URand_Gen());
740 #else
741  std::random_shuffle(data, data + d_size, URand_Get_Range);
742 #endif
743  }
744 #endif
745 
746 
747  /// Removes ownership of the contained data from the Data1D object.
748  /** Note, the array returned becomes the responsibility of the calling
749  * function, and should be delete[]'d externally! The pointer
750  * returned is as if the offset were set to 0 first. This Data1D
751  * is empty after calling this.
752  */
753  inline T* Extract() {
754  T* retval = alloc_data;
755  alloc_data = NULL;
756  data = NULL;
757  d_size = 0;
758  d_alloc = 0;
759  offset = 0;
760  return retval;
761  }
762 
763 
764  /// Reduces memory consumption to only that necessary for size() elements.
765  /** After calling, offset is 0 and points to the element indexed as 0
766  * before calling. Efficiency note: This function may copy all elements
767  * if necessary for reallocating.
768  */
769  inline void Crop() {
770  T *tmp;
771 
772  if ((offset == 0) && (d_alloc <= d_size)) {
773  return;
774  }
775 
776  d_alloc = d_size;
777 
778  if (d_alloc == 0) {
779  Delete();
780  return;
781  }
782 
783  tmp = new T[d_alloc];
784 
785 #ifdef CPP11
786  std::move(data, data + d_size, tmp);
787 #else
788  std::copy(data, data + d_size, tmp);
789 #endif
790 
791  DelArray();
792 
793  alloc_data = tmp;
794  offset = 0;
795  data = alloc_data;
796  do_delete = true;
797  }
798 
799 
800  /// Identical to Delete().
801  inline void Clear() {
802  Delete();
803  }
804 
805 
806  /// Add an element to the end, expanding if necessary.
807  /** Efficiency note: Expands by doubling for linear efficiency.
808  * @param newT The new element to append to the end.
809  * @see Reserve
810  */
811  inline void Append(const T& newT) {
812  size_t growto;
813  size_t offset_size = d_size + offset;
814 
815  if (d_alloc <= offset_size) {
816  growto = d_size << 1;
817  if (growto <= d_size) {
818  growto = d_size + 1;
819  }
820  Reserve(growto);
821  }
822 
823  data[d_size++] = newT;
824  }
825 
826 
827  /// Append data from any type with a compatible assignment operator.
828  /** @param other The compatible Data1D from which data should be copied.
829  */
830  template <class T2>
831  inline void AppendFrom (const Data1D<T2>& other) {
832  size_t last_d_size = d_size;
833  size_t other_size = other.size();
834 
835  Resize(d_size + other_size);
836 
837  std::copy(other.Raw(), other.Raw() + other_size, data + last_d_size);
838  }
839 
840 
841  /// Appends all elements in other to the end, expanding if necessary.
842  /** @param other The Data1D to append to the end.
843  */
844  inline void Append(const Data1D& other) {
845  AppendFrom(other);
846  }
847 
848 
849  /// Assign newT to index pos, expanding if necessary to reach that index.
850  /** @param pos The index to which newT should be assigned.
851  * @param newT The new element to assign.
852  */
853  inline void ExpandSet(size_t pos, const T& newT) {
854  if (!Check(pos)) {
855  Resize(pos+1);
856  }
857  data[pos] = newT;
858  }
859 
860 
861  /// Inserts newT at position pos, shifting the other elements.
862  /** Efficiency note: For random positions, on average O(N).
863  * @param pos The index at which newT should be inserted.
864  * @param newT The new element to insert.
865  */
866  inline void Insert(size_t pos, const T& newT) {
867  Assert(pos);
868 
869  Resize(d_size + 1);
870 
871  std::copy_backward(data+pos, data+size(), data+size()+1);
872  data[pos] = newT;
873  }
874 
875 
876  /// Removes the element at pos from the array, shrinking the size.
877  /** Efficiency note: For random positions, on average O(N).
878  * @param pos The index at which an element should be removed.
879  */
880  inline void Remove(size_t pos) {
881  Assert(pos);
882  if (Check(pos+1)) {
883 #ifdef CPP11
884  std::move(data+pos+1, data+size(), data+pos);
885 #else
886  std::copy(data+pos+1, data+size(), data+pos);
887 #endif
888  }
889  Resize(d_size - 1);
890  }
891 
892 
893  /// Add an element to the end, expanding if necessary.
894  /** Efficiency note: Expands by doubling for linear efficiency.
895  * @param newT The new element to append to the end.
896  * @return A reference to this Data1D.
897  * @see Reserve
898  */
899  inline Data1D<T>& operator+= (const T& newT) {
900  Append(newT);
901  return (*this);
902  }
903 
904 
905  /// Appends all elements in other to the end, expanding if necessary.
906  /** @param other The Data1D to append to the end.
907  * @return A reference to this Data1D.
908  */
909  inline Data1D<T>& operator+= (const Data1D& other) {
910  Append(other);
911  return (*this);
912  }
913 
914 
915  /// Create a new array from this Data1D concatenated with other after it.
916  inline Data1D<T> operator+ (const Data1D& other) const {
917  Data1D<T> retval(size()+other.size());
918  retval.CopyAt(0, *this);
919  retval.CopyAt(size(), other);
920  return retval;
921  }
922 
923 
924  /// Convert endianness of all elements if needed, for supported types.
925  inline void ToLilEndian() {
926  if (Endian::IsBig()) {
927  for (size_t i=0; i<d_size; i++) {
928  data[i] = Endian::ToLittle(data[i]);
929  }
930  }
931  }
932  /// Convert endianness of all elements if needed, for supported types.
933  inline void FromLilEndian() { ToLilEndian(); }
934 
935  /// Convert endianness of all elements if needed, for supported types.
936  inline void ToBigEndian() {
937  if (Endian::IsLittle()) {
938  for (size_t i=0; i<d_size; i++) {
939  data[i] = Endian::ToBig(data[i]);
940  }
941  }
942  }
943  /// Convert endianness of all elements if needed, for supported types.
944  inline void FromBigEndian() { ToBigEndian(); }
945 
946 
947  /// Comparison operator for all elements.
948  /** Also returns false if they are differently sized. Works for
949  * AnyValidType with operator== defined with T.
950  * @param other The Data1D to compare all elements with.
951  * @return True if all elements are equal.
952  */
953  template<class AnyValidType>
954  inline bool operator== (const Data1D<AnyValidType>& other) const {
955  size_t i;
956 
957  if (d_size != other.d_size) {
958  return false;
959  }
960 
961  if (data == other.data) {
962  return true; // No need to compare equivalent memory.
963  }
964 
965  for (i=0; i<d_size; i++) {
966  if ( ! (data[i] == other.data[i]) ) {
967  return false;
968  }
969  }
970 
971  return true;
972  }
973 
974 
975  /// Returns true if the first different element for this is less than for
976  /// other.
977  /** If they are differently sized and identical through the common length,
978  * then the shorter one is considered less. Works for AnyValidType with
979  * defined operator< in both directions with T.
980  * @param other The Data1D to compare all elements with.
981  * @return True if the first non-equal element for this is less than for
982  * other.
983  */
984  template<class AnyValidType>
985  inline bool operator< (const Data1D<AnyValidType>& other) const {
986  size_t i, minsize;
987  bool left_smaller;
988 
989  if (d_size < other.d_size) {
990  minsize = d_size;
991  left_smaller = true;
992  }
993  else {
994  if (data == other.data && d_size == other.d_size) {
995  return false; // No need to compare equivalent memory.
996  }
997  minsize = other.d_size;
998  left_smaller = false;
999  }
1000 
1001 
1002  for (i=0; i<minsize; i++) {
1003  if (data[i] < other.data[i]) {
1004  return true;
1005  }
1006  else if (other.data[i] < data[i]) {
1007  return false;
1008  }
1009  }
1010 
1011 
1012  return left_smaller;
1013  }
1014 
1016 
1017 
1018  /// Direct raw data extraction of type T2 at index.
1019  /** Bounds are checked. But if the raw data at the index is invalid
1020  * for an assignment operation of type T2 (e.g., non-POD in ambiguous
1021  * state), then behavior is undefined.
1022  * @param store_at The reference to which data is written.
1023  * @param index_T The index from which the data is extracted.
1024  */
1025  template<class T2>
1026  inline void Get(T2& store_at, size_t index_T) const {
1027  size_t end_index = index_T + sizeof(T2) / sizeof(T) +
1028  (((sizeof(T2)%sizeof(T)) != 0) ? 1 : 0);
1029  if (end_index>0) { end_index--; }
1030  Assert(index_T); Assert(end_index);
1031  store_at = *reinterpret_cast<T2*>(data+index_T);
1032  }
1033  /// Identical to the Get which receives store_at, but this returns the
1034  /// extracted value.
1035  template<class T2>
1036  inline T2 Get(size_t index_T=0) const {
1037  T2 retval;
1038  Get(retval, index_T);
1039  return retval;
1040  }
1041  /// Fills the array store_at to its current size with raw assigned
1042  /// data of type T2 from this Data1D.
1043  /** Usage example: Data1D<u64> x(1); Data1D<u8> y(8); x.Get(y,0);
1044  * y.Get(x,0);
1045  * If store_at has size 0, it resizes and grabs all available data.
1046  */
1047  template<class T2>
1048  inline void Get(Data1D<T2>& store_at, size_t index_T=0) const {
1049  if (store_at.size() == 0) {
1050  store_at.Resize(((size()-index_T)*sizeof(T))/sizeof(T2));
1051  }
1052  size_t T2_fullsize = sizeof(T2)*store_at.size();
1053  size_t end_index = index_T + T2_fullsize / sizeof(T) +
1054  (((T2_fullsize%sizeof(T)) != 0) ? 1 : 0);
1055  if (end_index>0) { end_index--; }
1056  Assert(index_T); Assert(end_index);
1057  T2* T2_data_ptr = reinterpret_cast<T2*>(data+index_T);
1058  std::copy(T2_data_ptr, T2_data_ptr + store_at.size(), store_at.Raw());
1059  }
1060 
1061  /// Direct raw data insertion of type T2 at index.
1062  /** Bounds are checked. But if the raw data at the index is invalid
1063  * for an assignment operation of type T2 (e.g., not-POD in ambiguous
1064  * state), then behavior is undefined.
1065  * @param read_from The reference from which data is read.
1066  * @param index_T The index at which data is placed.
1067  * @return *this
1068  */
1069  template<class T2>
1070  inline Data1D<T>& Put(const T2& read_from, size_t index_T) {
1071  size_t end_index = index_T + sizeof(T2) / sizeof(T) +
1072  (((sizeof(T2)%sizeof(T)) != 0) ? 1 : 0);
1073  if (end_index>0) { end_index--; }
1074  Assert(index_T); Assert(end_index);
1075  *reinterpret_cast<T2*>(data+index_T) = read_from;
1076  return *this;
1077  }
1078  /// Like Get for a T2 type, but places sequential packed data.
1079  /** Copies the full array read_from with raw assigned data of type T2,
1080  * to this Data1D starting at index, resizing as needed to include all
1081  * of read_from.
1082  * Usage example: Data1D<u64> x(1); Data1D<u8> y(8); x.Put(y,0);
1083  * y.Put(x,0);
1084  * @return *this
1085  */
1086  template<class T2>
1087  inline Data1D<T>& Put(const Data1D<T2>& read_from, size_t index_T=0) {
1088  size_t T2_fullsize = sizeof(T2)*read_from.size();
1089  size_t T1_sizeneeded = index_T + T2_fullsize / sizeof(T) +
1090  (((T2_fullsize%sizeof(T)) != 0) ? 1 : 0);
1091  if (d_size < T1_sizeneeded) {
1092  Resize(T1_sizeneeded);
1093  }
1094  T2* T2_data_ptr = reinterpret_cast<T2*>(data+index_T);
1095  std::copy(read_from.Raw(), read_from.Raw()+read_from.size(), T2_data_ptr);
1096  return *this;
1097  }
1098 
1099 
1100  /// Efficiently swap all the contents of a and b.
1101  template <class T2> friend void swap (Data1D<T2> &a, Data1D<T2> &b);
1102 
1103  /// The largest possible value of size_t.
1104  static const size_t npos = size_t(-1);
1105  };
1106 
1107 
1108  /// Outputs all chars to a stream without terminating at null.
1109  /** Usage like: Data1D<char> data; std::cout << data << std::endl;
1110  */
1111  inline std::ostream& operator<< (std::ostream &out, const Data1D<char>& d) {
1112  size_t i;
1113  for (i=0; i<d.size(); i++) {
1114  out << d[i];
1115  }
1116  return out;
1117  }
1118 
1119  /// Outputs data to a stream as { 61, 62, ... }
1120  /** Usage like: Data1D<u8> data; std::cout << data << std::endl;
1121  */
1122  inline std::ostream& operator<< (std::ostream &out, const Data1D<u8>& d) {
1123  size_t i;
1124 
1125  if (d.size() == 0) {
1126  out << "{ }";
1127  }
1128  else {
1129  out << "{ " << u16(d[0]);
1130  for (i=1; i<d.size(); i++) {
1131  out << ", " << u16(d[i]);
1132  }
1133  out << " }";
1134  }
1135 
1136  return out;
1137  }
1138 
1139  /// Outputs data to a stream as { 61, -42, ... }
1140  /** Usage like: Data1D<i8> data; std::cout << data << std::endl;
1141  */
1142  inline std::ostream& operator<< (std::ostream &out, const Data1D<i8>& d) {
1143  size_t i;
1144 
1145  if (d.size() == 0) {
1146  out << "{ }";
1147  }
1148  else {
1149  out << "{ " << i16(d[0]);
1150  for (i=1; i<d.size(); i++) {
1151  out << ", " << i16(d[i]);
1152  }
1153  out << " }";
1154  }
1155 
1156  return out;
1157  }
1158 
1159 
1160  /// Outputs data to a stream as { elem0, elem1, ... }
1161  /** Usage like: Data1D<RStr> data; std::cout << data << std::endl;
1162  */
1163  template <class T>
1164  inline std::ostream& operator<< (std::ostream &out, const Data1D<T>& d) {
1165  size_t i;
1166 
1167  if (d.size() == 0) {
1168  out << "{ }";
1169  }
1170  else {
1171  out << "{ " << d[0];
1172  for (i=1; i<d.size(); i++) {
1173  out << ", " << d[i];
1174  }
1175  out << " }";
1176  }
1177 
1178  return out;
1179  }
1180 
1181 
1182  /// Efficiently swap all the contents of a and b.
1183  template <class T>
1185  std::swap(a.do_delete, b.do_delete);
1186  std::swap(a.d_size, b.d_size);
1187  std::swap(a.d_alloc, b.d_alloc);
1188  std::swap(a.offset, b.offset);
1189  std::swap(a.data, b.data);
1190  std::swap(a.alloc_data, b.alloc_data);
1191  }
1192 
1193 #ifdef CPP11
1194  /// Convenience generator for safely converting C-style arrays.
1195  template<class T, size_t N> auto MakeData1D(T (&arr)[N]) -> RC::Data1D<T> {
1196  return RC::Data1D<T>(N,arr);
1197  }
1198 #endif
1199 
1200 }
1201 
1202 
1203 
1204 #endif // RC_DATA1D_H
1205 
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:282
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:600
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:493
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:811
T * Extract()
Removes ownership of the contained data from the Data1D object.
Definition: Data1D.h:753
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:689
T & At(size_t x)
Identical to Data1D::operator[].
Definition: Data1D.h:659
void ToBigEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:936
T & operator()(size_t x)
Identical to Data1D::operator[].
Definition: Data1D.h:653
void Append(const Data1D &other)
Appends all elements in other to the end, expanding if necessary.
Definition: Data1D.h:844
void Clear()
Identical to Delete().
Definition: Data1D.h:801
void Crop()
Reduces memory consumption to only that necessary for size() elements.
Definition: Data1D.h:769
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:669
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:916
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:954
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:468
void URandShuffle()
Randomizes the order of all the elements using /dev/urandom.
Definition: Data1D.h:737
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:1048
RAIter< Data1D< T >, T > end()
Return a bounds-checked random-access iterator starting just past the last element.
Definition: Data1D.h:636
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:677
Data1D< T > & Put(const T2 &read_from, size_t index_T)
Direct raw data insertion of type T2 at index.
Definition: Data1D.h:1070
void AppendFrom(const Data1D< T2 > &other)
Append data from any type with a compatible assignment operator.
Definition: Data1D.h:831
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:707
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:866
Data1D< T2 > Cast()
Returns a new array with all the elements of this array assigned to type T2.
Definition: Data1D.h:571
void Shuffle()
Randomizes the order of all the elements.
Definition: Data1D.h:725
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:1087
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:580
~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:640
T & operator[](size_t x)
Bounds-checked access of the element at index x from the offset (default 0).
Definition: Data1D.h:651
static const size_t npos
The largest possible value of size_t.
Definition: Data1D.h:1104
Data1D & operator=(const Data1D &other)
Assignment operator which copies all contents from other, respecting offsets.
Definition: Data1D.h:547
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:624
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:667
void ExpandSet(size_t pos, const T &newT)
Assign newT to index pos, expanding if necessary to reach that index.
Definition: Data1D.h:853
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:716
Data1D< T > & operator+=(const T &newT)
Add an element to the end, expanding if necessary.
Definition: Data1D.h:899
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:933
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:1036
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:661
void Remove(size_t pos)
Removes the element at pos from the array, shrinking the size.
Definition: Data1D.h:880
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:944
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:536
void ToLilEndian()
Convert endianness of all elements if needed, for supported types.
Definition: Data1D.h:925
bool operator<(const Data1D< AnyValidType > &other) const
Returns true if the first different element for this is less than for other.
Definition: Data1D.h:985
RAIter< Data1D< T >, T > begin()
Copy data from any other object of a type with a compatible.
Definition: Data1D.h:620
void Get(T2 &store_at, size_t index_T) const
Direct raw data extraction of type T2 at index.
Definition: Data1D.h:1026
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:594
u64 RND_Get_Range(u64 range)
Uses RND as a RandomNumberGenerator, e.g. for random_shuffle.
Definition: RND.h:542
void swap(RC::Data1D< T > &a, RC::Data1D< T > &b)
Efficiently swap all the contents of a and b.
Definition: Data1D.h:1184
u64 URand_Get_Range(u64 range)
Uses URand as a RandomNumberGenerator, e.g. for random_shuffle.
Definition: RND.h:580
URand & URand_Gen()
This returns a singleton of URand .
Definition: RND.h:597
auto MakeData1D(T(&arr)[N]) -> RC::Data1D< T >
Convenience generator for safely converting C-style arrays.
Definition: Data1D.h:1195
email address
— (c) 2015