Evo C++ Library v0.5.1
array.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_array_h
9 #define INCL_evo_array_h
10 
11 #include "type.h"
12 #include "impl/iter.h"
13 
14 namespace evo {
17 
19 
20 // Internal implementation macros -- only used in this file
22 // Grows to add items, without initializing -- size_ must be updated after calling
23 #define EVO_IMPL_ARRAY_GROW_ADD(SIZE) { \
24  if (size_ > 0) { \
25  Size newsize = size_ + SIZE; \
26  T* const old_data = data_; \
27  data_ = (T*)::malloc((size_t)newsize*sizeof(T)); \
28  memcpy(data_, old_data, (size_t)size_*sizeof(T)); \
29  ::free(old_data); \
30  } else \
31  data_ = (T*)::malloc((size_t)SIZE*sizeof(T)); \
32 }
33 // Grows to insert items, without initializing -- updates size_
34 #define EVO_IMPL_ARRAY_GROW_INSERT(INDEX, SIZE) { \
35  assert( size_ > 0 ); \
36  Size newsize = size_ + SIZE; \
37  T* const old_data = data_; \
38  data_ = (T*)::malloc((size_t)newsize*sizeof(T)); \
39  if (INDEX > 0) { \
40  memcpy(data_, old_data, (size_t)INDEX*sizeof(T)); \
41  Size tail = size_ - INDEX; \
42  assert( tail > 0 ); \
43  memcpy(data_+INDEX+SIZE, old_data+INDEX, (size_t)tail*sizeof(T)); \
44  } else \
45  memcpy(data_+SIZE, old_data, (size_t)size_*sizeof(T)); \
46  ::free(old_data); \
47  size_ = newsize; \
48 }
49 
51 
184 template<class T,class TSize=SizeT>
185 class Array {
186 public:
189  typedef TSize Size;
190  typedef Size Key;
191  typedef T Value;
192  typedef T Item;
193 
194  // Iterator support types
196  typedef Key IterKey;
197  typedef T IterItem;
202 
204  Array() {
205  data_ = NULL;
206  size_ = 0;
207  }
208 
212  explicit Array(const ValEmpty& val) {
213  EVO_PARAM_UNUSED(val);
214  data_ = EVO_PEMPTY;
215  size_ = 0;
216  }
217 
221  Array(const ThisType& src) {
222  if (src.size_ > 0) {
223  data_ = (T*)::malloc((size_t)src.size_*sizeof(T));
224  DataInit<T>::init(data_, src.data_, src.size_);
225  } else
226  data_ = src.data_;
227  size_ = src.size_;
228  }
229 
234  Array(const T* data, Size size) {
235  if (size > 0) {
236  data_ = (T*)::malloc((size_t)size*sizeof(T));
237  DataInit<T>::init(data_, data, size);
238  } else if (data == NULL)
239  data_ = NULL;
240  else
241  data_ = EVO_PEMPTY;
242  size_ = size;
243  }
244 
246  ~Array() {
247  if (size_ > 0) {
249  ::free(data_);
250  }
251  }
252 
253 #if defined(EVO_CPP11)
254 
257  Array(std::initializer_list<T> init) : Array() {
258  assert( init.size() < IntegerT<Size>::MAX );
259  resize((Size)init.size());
260  uint i = 0;
261  for (const auto& item : init)
262  data_[i++] = item;
263  }
264 
268  Array(ThisType&& src) {
269  ::memcpy(this, &src, sizeof(ThisType));
270  ::memset(&src, 0, sizeof(ThisType));
271  }
272 
277  ThisType& operator=(ThisType&& src) {
278  resize(0);
279  ::memcpy(this, &src, sizeof(ThisType));
280  ::memset(&src, 0, sizeof(ThisType));
281  return *this;
282  }
283 #endif
284 
290  const ThisType& asconst() const {
291  return *this;
292  }
293 
294  // SET
295 
300  ThisType& operator=(const ThisType& src)
301  { return set(src); }
302 
312  ThisType& operator=(const ValNull&)
313  { return set(); }
314 
322  ThisType& operator=(const ValEmpty&)
323  { return setempty(); }
324 
330  ThisType& clear() {
331  if (size_ > 0) {
333  ::free(data_);
334  data_ = EVO_PEMPTY;
335  size_ = 0;
336  }
337  return *this;
338  }
339 
343  ThisType& set() {
344  if (size_ > 0) {
346  ::free(data_);
347  size_ = 0;
348  }
349  data_ = NULL;
350  return *this;
351  }
352 
357  ThisType& set(const ThisType& src) {
358  if (this != &src) {
359  if (src.size_ > 0) {
360  if (size_ == src.size_) {
361  // Same positive size
363  DataInit<T>::init(data_, src.data_, src.size_);
364  } else {
365  // New positive size
366  if (size_ > 0) {
368  ::free(data_);
369  }
370  size_ = src.size_;
371  data_ = (T*)::malloc((size_t)src.size_*sizeof(T));
372  DataInit<T>::init(data_, src.data_, src.size_);
373  }
374  } else {
375  // Null/Empty
376  if (size_ > 0) {
378  ::free(data_);
379  size_ = 0;
380  }
381  data_ = (src.data_ == NULL ? NULL : EVO_PEMPTY);
382  }
383  }
384  return *this;
385  }
386 
392  ThisType& set(const T* data, Size size) {
393  if (size == size_) {
394  if (size_ > 0)
396  if (size > 0)
397  DataInit<T>::init(data_, data, size);
398  else if (data == NULL)
399  data_ = NULL;
400  else
401  data_ = EVO_PEMPTY;
402  } else {
403  if (size_ > 0) {
405  ::free(data_);
406  }
407  if (size > 0) {
408  data_ = (T*)::malloc((size_t)size*sizeof(T));
409  DataInit<T>::init(data_, data, size);
410  } else if (data == NULL)
411  data_ = NULL;
412  else
413  data_ = EVO_PEMPTY;
414  size_ = size;
415  }
416  return *this;
417  }
418 
422  ThisType& setempty() {
423  if (size_ > 0) {
425  ::free(data_);
426  size_ = 0;
427  }
428  data_ = EVO_PEMPTY;
429  return *this;
430  }
431 
432  // INFO
433 
439  bool null() const
440  { return (data_ == NULL); }
441 
447  bool empty() const
448  { return (size_ == 0); }
449 
453  Size size() const
454  { return size_; }
455 
461  bool shared() const
462  { return false; }
463 
469  const T* data() const
470  { return data_; }
471 
478  const T& operator[](Key index) const
479  { assert( index < size_ ); return data_[index]; }
480 
487  const T& item(Key index) const
488  { assert( index < size_ ); return data_[index]; }
489 
496  const T& ring(Key index) const
497  { return data_[index % size_]; }
498 
502  const T* first() const
503  { return (size_ > 0 ? data_ : NULL); }
504 
508  const T* last() const
509  { return (size_ > 0 ? data_+size_-1 : NULL); }
510 
518  Key iend(Size offset=0) const
519  { return (offset < size_ ? size_-1-offset : END); }
520 
525  ulong hash(ulong seed=0) const
526  { return DataHash<T>::hash(data_, size_, seed); }
527 
528  // COMPARE
529 
534  int compare(const ThisType& data) const {
535  int result;
536  if (this == &data)
537  result = 0;
538  else if (data_ == NULL)
539  result = (data.data_ == NULL ? 0 : -1);
540  else if (data.data_ == NULL)
541  result = 1;
542  else
543  result = DataCompare<T>::compare(data_, size_, data.data_, data.size_);
544  return result;
545  }
546 
551  bool operator==(const ThisType& data) const {
552  bool result;
553  if (this == &data)
554  result = true;
555  else if (data_ == NULL)
556  result = (data.data_ == NULL);
557  else if (data.data_ == NULL || size_ != data.size_)
558  result = false;
559  else
560  result = DataEqual<T>::equal(data_, data.data_, data.size_);
561  return result;
562  }
563 
568  bool operator!=(const ThisType& data) const {
569  bool result;
570  if (this == &data)
571  result = false;
572  else if (data_ == NULL)
573  result = (data.data_ != NULL);
574  else if (data.data_ == NULL || size_ != data.size_)
575  result = true;
576  else
577  result = !DataEqual<T>::equal(data_, data.data_, data.size_);
578  return result;
579  }
580 
587  bool starts(const T& item) const
588  { return (size_ > 0 && data_[0] == item); }
589 
597  bool starts(const T* items, Size size) const
598  { return (size_ >= size && DataEqual<T>::equal(data_, items, size)); }
599 
606  bool ends(const T& item) const
607  { return (size_ > 0 && data_[size_-1] == item); }
608 
616  bool ends(const T* items, Size size) const
617  { return (size_ >= size && DataEqual<T>::equal(data_+(size_-size), items, size)); }
618 
619  // FIND
620 
627  Iter cbegin() const
628  { return Iter(*this); }
629 
637  Iter cend() const
638  { return Iter(); }
639 
647  IterM begin()
648  { return IterM(*this); }
649 
656  Iter begin() const
657  { return Iter(*this); }
658 
666  IterM end()
667  { return IterM(); }
668 
676  Iter end() const
677  { return Iter(); }
678 
679  // INFO_SET
680 
686  T* data()
687  { return data_; }
688 
695  T& operator[](Key index)
696  { assert( index < size_ ); return data_[index]; }
697 
704  T& item(Key index)
705  { assert( index < size_ ); return data_[index]; }
706 
713  T& ring(Key index)
714  { return data_[index % size_]; }
715 
719  T* first()
720  { return (size_ > 0 ? data_ : NULL); }
721 
725  T* last()
726  { return (size_ > 0 ? data_+size_-1 : NULL); }
727 
733  ThisType& unshare()
734  { return *this; }
735 
743  ThisType& resize(Size size) {
744  if (size == 0) {
745  // Null/Empty
746  if (size_ > 0) {
748  ::free(data_);
749  data_ = EVO_PEMPTY;
750  size_ = 0;
751  }
752  } else if (size_ != size) {
753  // New positive size
754  assert( size > 0 );
755  if (size_ > 0) {
756  // Preserve existing items
757  T* const old_data = data_;
758  const Size save_size = (size_ < size ? size_ : size);
759  data_ = (T*)::malloc((size_t)size*sizeof(T));
760  memcpy(data_, old_data, (size_t)save_size*sizeof(T));
761  DataInit<T>::init_tail_safe(data_, save_size, size);
762 
763  size_ -= save_size;
764  if (size_ > 0)
765  DataInit<T>::uninit(old_data+save_size, size_);
766  ::free(old_data);
767  } else {
768  // New array
769  data_ = (T*)::malloc((size_t)size*sizeof(T));
771  }
772  size_ = size;
773  }
774  return *this;
775  }
776 
785  ThisType& resize2(Size size) {
786  if (size > 0) {
787  Size size2 = (size >= 256 ? 256 : 1);
788  while (size2 < size)
789  size2 *= 2;
790  size = size2;
791  }
792  resize(size);
793  return *this;
794  }
795 
796  // ADD
797 
802  ThisType& addnew(Size size=1) {
803  if (size > 0) {
804  EVO_IMPL_ARRAY_GROW_ADD(size);
806  size_ += size;
807  }
808  return *this;
809  }
810 
815  ThisType& add(const Item& item) {
816  EVO_IMPL_ARRAY_GROW_ADD(1);
817  DataInit<T>::init(data_+size_, &item, 1);
818  ++size_;
819  return *this;
820  }
821 
822  // INSERT
823 
829  Size insertnew(Key index, Size size=1) {
830  if (size > 0) {
831  if (index < size_) {
832  EVO_IMPL_ARRAY_GROW_INSERT(index, size);
833  } else {
834  index = size_;
835  EVO_IMPL_ARRAY_GROW_ADD(size);
836  size_ += size;
837  }
839  }
840  return index;
841  }
842 
848  Size insert(Key index, const Item& item) {
849  if (index < size_) {
850  EVO_IMPL_ARRAY_GROW_INSERT(index, 1);
851  } else {
852  index = size_;
853  EVO_IMPL_ARRAY_GROW_ADD(1);
854  ++size_;
855  }
856  DataInit<T>::init(data_+index, &item, 1);
857  return index;
858  }
859 
860  // REMOVE
861 
867  Size remove(Key index, Size size=1) {
868  if (index < size_ && size > 0) {
869  Size tempsize = size_ - index;
870  if (size > tempsize)
871  size = tempsize;
872  if (size < size_) {
873  // Preserve existing items
874  tempsize = size_ - size;
875  T* const old_data = data_;
876  data_ = (T*)::malloc((size_t)tempsize*sizeof(T));
877  if (index > 0)
878  memcpy(data_, old_data, (size_t)index*sizeof(T));
879  Size tail = size_ - index - size;
880  if (tail > 0)
881  memcpy(data_+index, old_data+index+size, (size_t)tail*sizeof(T));
882 
883  DataInit<T>::uninit(old_data+index, size);
884  ::free(old_data);
885  size_ = tempsize;
886  } else {
887  // Remove all
888  size = size_;
890  ::free(data_);
891  data_ = EVO_PEMPTY;
892  size_ = 0;
893  }
894  } else
895  size = 0;
896  return size;
897  }
898 
899  // FILL
900 
908  ThisType& fill(const T& item, Key index=0, Size size=ALL) {
909  if (index == END)
910  index = size_;
911  if (size == ALL)
912  size = (index < size_ ? size_ - index : 0);
913  if (size > 0) {
914  const Size newsize = index + size;
915  if (newsize > size_)
916  advResize(newsize);
917  DataFill<T>::fill(data_+index, size, item);
918  }
919  return *this;
920  }
921 
922  // MOVE / SWAP
923 
929  void swap(ThisType& array)
930  { EVO_IMPL_CONTAINER_SWAP(this, &array, ThisType); }
931 
932  // ADVANCED
933 
942  const T& advRing(Key index) const {
943  assert( is_pow2(size_) );
944  return data_[index & (size_ - 1)];
945  }
946 
954  T& advRing(Key index) {
955  assert( is_pow2(size_) );
956  return data_[index & (size_ - 1)];
957  }
958 
971  ThisType& advResize(Size size) {
972  if (size == 0) {
973  // Null/Empty
974  if (size_ > 0) {
976  ::free(data_);
977  data_ = EVO_PEMPTY;
978  size_ = 0;
979  }
980  } else if (size_ != size) {
981  // New positive size
982  assert( size > 0 );
983  if (size_ > 0) {
984  // Preserve existing items
985  T* const old_data = data_;
986  const Size save_size = (size_ < size ? size_ : size);
987  data_ = (T*)::malloc((size_t)size*sizeof(T));
988  memcpy(data_, old_data, (size_t)save_size*sizeof(T));
989  DataInit<T>::init_tail_fast(data_, save_size, size);
990 
991  size_ -= save_size;
992  if (size_ > 0)
993  DataInit<T>::uninit(old_data+save_size, size_);
994  ::free(old_data);
995  } else {
996  // New array
997  data_ = (T*)::malloc((size_t)size*sizeof(T));
998  DataInit<T>::init(data_, size);
999  }
1000  size_ = size;
1001  }
1002  return *this;
1003  }
1004 
1005  // INTERNAL
1006 
1007  // Iterator support methods
1009  void iterInitMutable()
1010  { }
1011  const IterItem* iterFirst(IterKey& key) const
1012  { key = 0; return data_; }
1013  const IterItem* iterNext(IterKey& key) const {
1014  const IterItem* result = NULL;
1015  if (key != END) {
1016  if (++key < size_)
1017  result = &(data_[key]);
1018  else
1019  key = END;
1020  }
1021  return result;
1022  }
1023  const IterItem* iterNext(Size count, IterKey& key) const {
1024  const T* result = NULL;
1025  if (key != END) {
1026  if ( (key+=count) < size_ )
1027  result = &(data_[key]);
1028  else
1029  key = END;
1030  }
1031  return result;
1032  }
1033  const IterItem* iterLast(IterKey& key) const {
1034  const IterItem* result = NULL;
1035  if (size_ > 0) {
1036  key = size_ - 1;
1037  result = &(data_[key]);
1038  } else
1039  key = END;
1040  return result;
1041  }
1042  const IterItem* iterPrev(IterKey& key) const {
1043  const IterItem* result = NULL;
1044  if (key != END) {
1045  if (key > 0)
1046  result = &(data_[--key]);
1047  else
1048  key = END;
1049  }
1050  return result;
1051  }
1052  const IterItem* iterPrev(Size count, IterKey& key) const {
1053  const IterItem* result = NULL;
1054  if (key != END) {
1055  if (key > 0 && count <= key)
1056  result = &(data_[(key-=count)]);
1057  else
1058  key = END;
1059  }
1060  return result;
1061  }
1062  Size iterCount() const
1063  { return size_; }
1064  const IterItem* iterSet(IterKey key) const {
1065  const IterItem* result = NULL;
1066  if (key < size_)
1067  result = &(data_[key]);
1068  return result;
1069  }
1072 protected:
1073  T* data_;
1074  Size size_;
1075 };
1076 
1078 
1079 // Remove implementation macros
1080 #undef EVO_IMPL_ARRAY_GROW_ADD
1081 #undef EVO_IMPL_ARRAY_GROW_INSERT
1082 
1084 
1085 }
1086 #endif
Iter cend() const
Get iterator at end (const).
Definition: array.h:637
T & operator[](Key index)
Get item at position (mutable).
Definition: array.h:695
Size size_
Definition: array.h:1074
IteratorRa< ThisType > IterM
Iterator (mutable) - IteratorRa.
Definition: array.h:201
static void init_tail_safe(Item *data, ulong oldSize, ulong newSize)
Initialize new tail data (default constructor).
Definition: container.h:252
Array(std::initializer_list< T > init)
Sequence constructor (C++11).
Definition: array.h:257
bool empty() const
Get whether empty.
Definition: array.h:447
bool ends(const T &item) const
Check if ends with given item.
Definition: array.h:606
IterM begin()
Get iterator at first item (mutable).
Definition: array.h:647
Iter begin() const
Get iterator at first item (const).
Definition: array.h:656
ThisType & operator=(ThisType &&src)
Move assignment operator (C++11).
Definition: array.h:277
Size size() const
Get size.
Definition: array.h:453
IterM end()
Get iterator at end.
Definition: array.h:666
ValEmpty
Special empty value type, pass as vEMPTY.
Definition: sys.h:1101
IteratorRa< ThisType >::Const Iter
Iterator (const) - IteratorRa.
Definition: array.h:200
void swap(ThisType &array)
Swap with another array.
Definition: array.h:929
ulong hash(ulong seed=0) const
Get data hash value for whole array.
Definition: array.h:525
ThisType & resize2(Size size)
Resize as power of 2 while preserving existing data (modifier).
Definition: array.h:785
#define EVO_CONTAINER_TYPE
Identify current class/struct as an EvoContainer.
Definition: meta.h:482
const T * last() const
Get last item (const).
Definition: array.h:508
T Item
Item type (same as Value)
Definition: array.h:192
bool ends(const T *items, Size size) const
Check if ends with given items.
Definition: array.h:616
T * first()
Get first item (mutable).
Definition: array.h:719
Random access iterator.
Definition: iter.h:904
ValNull
Unique null value type and value (vNULL).
Definition: sys.h:1096
T & advRing(Key index)
Advanced: Get ring-buffer item at position (mutable).
Definition: array.h:954
ThisType & operator=(const ValEmpty &)
Assignment operator to set as empty but not null.
Definition: array.h:322
int compare(const ThisType &data) const
Comparison.
Definition: array.h:534
bool operator!=(const ThisType &data) const
Inequality operator.
Definition: array.h:568
ThisType & unshare()
Make data unique – no-op.
Definition: array.h:733
const T & operator[](Key index) const
Get item at position (const).
Definition: array.h:478
bool operator==(const ThisType &data) const
Equality operator.
Definition: array.h:551
static void init_tail_fast(Item *data, ulong oldSize, ulong newSize)
Initialize new tail data (default constructor).
Definition: container.h:270
Basic integer type.
Definition: type.h:980
Array(const ValEmpty &val)
Constructor sets as empty but not null.
Definition: array.h:212
#define EVO_PEMPTY
Special pointer value for empty but not NULL (used in containers).
Definition: type.h:1858
Size Key
Key type (item index)
Definition: array.h:190
const T * data() const
Get data pointer (const).
Definition: array.h:469
Data equality helper.
Definition: container.h:712
bool shared() const
Get whether shared (false).
Definition: array.h:461
Evo implementation detail: Container iterators.
ThisType & resize(Size size)
Resize while preserving existing data (modifier).
Definition: array.h:743
const T & ring(Key index) const
Get ring-buffer item at position (const).
Definition: array.h:496
ThisType & operator=(const ThisType &src)
Assignment operator.
Definition: array.h:300
Key iend(Size offset=0) const
Get index from last item using offset.
Definition: array.h:518
static const EndT END
Special integer value for indicating end of items or no item.
Definition: type.h:1846
ThisType & clear()
Clear by removing all items.
Definition: array.h:330
const T & item(Key index) const
Get item at position (const).
Definition: array.h:487
static const EndT ALL
Special integer value for indicating all items or all remaining items.
Definition: type.h:1839
T & item(Key index)
Get item at position (mutable).
Definition: array.h:704
bool is_pow2(T num)
Get whether a number is a power of 2.
Definition: type.h:1967
Array< T, TSize > ThisType
This array type.
Definition: array.h:188
T * data_
Definition: array.h:1073
Iter end() const
Get iterator at end.
Definition: array.h:676
static ulong hash(const T *data, ulong size, ulong seed=0)
Compute hash value from data.
Definition: container.h:899
Evo C++ Library namespace.
Definition: alg.h:11
static bool equal(const T *data1, const T *data2, ulong size)
Compare array data for equality.
Definition: container.h:721
ThisType & setempty()
Set as empty but not null.
Definition: array.h:422
T Value
Value type (same as Item)
Definition: array.h:191
ThisType & advResize(Size size)
Advanced: Resize while preserving existing data, POD items not initialized (modifier).
Definition: array.h:971
Array()
Default constructor sets as null.
Definition: array.h:204
Iter cbegin() const
Get iterator at first item (const).
Definition: array.h:627
const T * first() const
Get first item (const).
Definition: array.h:502
T * last()
Get last item (mutable).
Definition: array.h:725
static void uninit(Item *data, ulong size)
Uninitialize data (destructor).
Definition: container.h:311
static int compare(const T *data1, ulong size1, const T *data2, ulong size2)
Compare data.
Definition: container.h:769
const ThisType & asconst() const
Explicitly use a const reference to this.
Definition: array.h:290
static void init(Item *data, ulong size=1)
Initialize data using default constructor.
Definition: container.h:198
ThisType & add(const Item &item)
Append new item.
Definition: array.h:815
TSize Size
List size integer type.
Definition: array.h:189
static void fill(T *dest, ulong size, const T &value)
Fill with copies of given item.
Definition: container.h:621
bool starts(const T &item) const
Check if starts with given item.
Definition: array.h:587
Array(const T *data, Size size)
Copy constructor.
Definition: array.h:234
ThisType & operator=(const ValNull &)
Assignment operator to set as null and empty.
Definition: array.h:312
static void init_safe(Item *data, ulong size=1)
Initialize data using default constructor.
Definition: container.h:159
Array(const ThisType &src)
Copy constructor.
Definition: array.h:221
Dynamic array container with similar interface to List.
Definition: array.h:185
Size insertnew(Key index, Size size=1)
Insert new items.
Definition: array.h:829
bool null() const
Get whether null.
Definition: array.h:439
Array(ThisType &&src)
Move constructor (C++11).
Definition: array.h:268
T * data()
Get data pointer (mutable).
Definition: array.h:686
bool starts(const T *items, Size size) const
Check if starts with given items.
Definition: array.h:597
ThisType & addnew(Size size=1)
Append new items.
Definition: array.h:802
ThisType & fill(const T &item, Key index=0, Size size=ALL)
Fill using item (modifier).
Definition: array.h:908
const T & advRing(Key index) const
Advanced: Get ring-buffer item at position (const).
Definition: array.h:942
Size insert(Key index, const Item &item)
Insert new item.
Definition: array.h:848
#define EVO_PARAM_UNUSED(NAME)
Mark function parameter as unused to suppress "unreferenced parameter" compiler warnings on it...
Definition: sys.h:427
~Array()
Destructor to free used memory.
Definition: array.h:246
Evo basic types and traits.
T & ring(Key index)
Get ring-buffer item at position (mutable).
Definition: array.h:713