libzed 1.9.11
A general-purpose library for quick and simple data manipulation.
 
Loading...
Searching...
No Matches
array.hpp
1#pragma once
2
3#include <functional>
4#include <initializer_list>
5#include <random>
6#include <stdexcept>
7#include <vector>
8
9#include "arrayLike.hpp"
10#include "compare.hpp"
11#include "sizable.hpp"
12#include "typeChecks.hpp"
13
14#ifdef __has_include
15#if __has_include(<cereal/cereal.hpp>)
16#include <cereal/archives/json.hpp>
17#include <cereal/archives/xml.hpp>
18#endif
19#endif
20
21// Define custom implementation for std::sort and std::shuffle if not available in this C++ version.
22#if __cplusplus < 201703L
23namespace std {
24
26template <typename T>
27class vec_iter : public std::vector<T>::iterator {};
28
30template <typename T>
31void sort(vec_iter<T> _begin, vec_iter<T> _end, std::function<bool(const T &, const T &)> _lambda) noexcept {
32 bool swapped = true;
33 while (swapped) {
34 swapped = false;
35 for (auto i = _begin; i != _end - 1; ++i) {
36 if (_lambda(*i, *(i + 1))) {
37 std::swap(*i, *(i + 1));
38 swapped = true;
39 }
40 }
41 }
42}
43
45template <class _RAIter, class _UGenerator>
46void shuffle(_RAIter _begin, _RAIter _end, _UGenerator &&g) {
47 for (_RAIter i = _end - 1; i > _begin; --i) {
48 std::uniform_int_distribution<std::size_t> d(0, i - _begin);
49 std::iter_swap(i, _begin + d(g));
50 }
51}
52
53} // namespace std
54#else
55// Use std::sort and std::shuffle if available
56#include <algorithm>
57#endif
58
59namespace z {
60namespace core {
74template <typename T>
75class array : public sizable, public arrayLike<const T &, T *> {
76protected:
78 std::vector<T> array_data;
79
84 inline void init(const T &arg1) {
85 add(arg1);
86 }
87
93 template <typename... Args>
94 inline void init(const T &arg1, const Args &...args) {
95 add(arg1);
96 init(args...);
97 }
98
111 virtual bool eq(const T &arg1, const T &arg2) const {
112 return equals(arg1, arg2);
113 }
114
127 virtual bool gt(const T &arg1, const T &arg2) const {
128 return greater(arg1, arg2);
129 }
130
143 virtual bool lt(const T &arg1, const T &arg2) const {
144 return lesser(arg1, arg2);
145 }
146
147public:
149 array() {}
150
153
155 array(const std::vector<T> &other);
156
169 template <typename... Args>
170 array(const T &arg1, const Args &...args);
171
177 array(const std::initializer_list<T> &other) : array_data(other) {}
178
180 virtual ~array() {}
181
182 inline void clear();
183
192 void increase(int newSize) noexcept {
193 array_data.reserve(newSize);
194 }
195
208 virtual int add(const T &object) {
209 array_data.push_back(object);
210
211 return (array_data.size() - 1);
212 }
213
224 void add(const array &other) noexcept {
225 for (int i = 0; i < other.size(); i++) {
227 }
228 }
229
242 inline int push(const T &object) noexcept {
243 return add(object);
244 }
245
256 inline void push(const array &other) noexcept {
257 add(other);
258 }
259
268 T pop() {
269 T element = at(length());
270 array_data.pop_back();
271 return element;
272 }
273
274 array &insert(const T &, int);
275
276 void append(const T &);
277
279 array &remove(int, int);
280
281 array &replace(int, int, const T &);
282 array &replace(int, int, const array<T> &);
283
297 array subset(int index, int count) const;
298
305
312
313 T &at(int);
315
328 const T &operator[](int index) const override {
329 return at(index);
330 }
331
344 T &operator[](int index) {
345 return at(index);
346 }
347
359 virtual int find(const T &object) const {
360 for (int i = 0; i < (int)array_data.size(); i++) {
361 if (eq(array_data.at(i), object)) {
362 return i;
363 }
364 }
365
366 return -1;
367 }
368
376 bool contains(const T &object) const noexcept {
377 return find(object) > -1;
378 }
379
385 void sort() noexcept {
386 sort(*this);
387 }
388
396 void sort(std::function<bool(const T &, const T &)> lambda) noexcept {
397 std::sort(array_data.begin(), array_data.end(), lambda);
398 }
399
408 auto new_array = *this;
409 new_array.sort();
410 return new_array;
411 }
412
421 array sorted(std::function<bool(const T &, const T &)> lambda) const noexcept {
422 auto new_array = *this;
423 new_array.sort(lambda);
424 return new_array;
425 }
426
433 virtual void shuffle() noexcept {
434 // Use std::shuffle if C++17
435 std::random_device device;
436 std::mt19937 generator(device());
437 std::shuffle(array_data.begin(), array_data.end(), generator);
438 }
439
449 auto new_array = *this;
451 return new_array;
452 }
453
460 virtual void reverse() noexcept {
461 const auto len = length();
462 for (int i = 0; i < (len / 2); ++i) {
463 std::swap(array_data[i], array_data[len - 1 - i]);
464 }
465 }
466
476 auto new_array = *this;
478 return new_array;
479 }
480
482 array &operator=(const std::initializer_list<T> &other);
483
484 bool operator==(const array &other) const;
485 bool operator>(const array &other) const;
486 bool operator<(const array &other) const;
487 inline bool operator>=(const array &other) const;
488 inline bool operator<=(const array &other) const;
489
499 virtual bool operator()(const T &arg1, const T &arg2) const;
500
509 bool isValid(int index) const;
510
520
531 template <typename U>
532 array<U> map(std::function<U(const T &)> lambda) const;
533
544 array filter(std::function<bool(const T &)> lambda) const;
545
556 T reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const;
557
567 T randomElement() const {
568 if (array_data.empty()) {
569 throw std::out_of_range("Array is empty");
570 }
571
572 std::random_device device;
573 std::mt19937 generator(device());
574 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
576 }
577
588 array randomElements(int count) const noexcept {
589 if (array_data.empty()) {
590 return array();
591 }
592
593 std::random_device device;
594 std::mt19937 generator(device());
595 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
596
597 const int numElements = std::min(count, length());
598
601 for (int i = 0; i < numElements; ++i) {
603 }
604
605 return randomArray;
606 }
607
616 T *begin() const noexcept override {
617 return array_data.empty() ? NULL : (T *)&array_data.front();
618 }
619
628 T *end() const noexcept override {
629 return begin() + array_data.size();
630 }
631
632#ifdef __has_include
633#if __has_include(<cereal/cereal.hpp>)
638 void save(cereal::JSONOutputArchive &ar) const {
639 ar.makeArray();
640 for (int i = 0; i < (int)array_data.size(); i++) {
641 ar(array_data[i]);
642 }
643 }
644
649 void save(cereal::XMLOutputArchive &ar) const {
650 for (int i = 0; i < (int)array_data.size(); i++) {
651 ar(cereal::make_nvp(std::to_string(i), array_data[i]));
652 }
653 }
654
659 template <typename archive>
660 void save(archive &ar) const {
661 ar((size_t)array_data.size());
662 for (int i = 0; i < (int)array_data.size(); i++) {
663 ar(array_data[i]);
664 }
665 }
666
671 void load(cereal::JSONInputArchive &ar) {
673 ar.loadSize(sz);
674 array_data.reserve(sz);
675
676 T data;
677 for (int i = 0; i < sz; i++) {
678 ar(data);
679 array_data.push_back(data);
680 }
681 }
682
687 void load(cereal::XMLInputArchive &ar) {
689 ar.loadSize(sz);
690 array_data.reserve(sz);
691
692 T data;
693 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
694 ar(data);
695 array_data.push_back(data);
696 }
697 }
698
703 template <class archive>
704 void load(archive &ar) {
705 clear();
707 ar(sz);
708 array_data.reserve(sz);
709
710 T data;
711 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
712 ar(data);
713 array_data.push_back(data);
714 }
715 }
716
717#endif
718#endif
719};
720
721template <typename T>
725
726template <typename T>
727array<T>::array(const std::vector<T> &other) {
729}
730
731template <typename T>
732template <typename... Args>
733array<T>::array(const T &arg1, const Args &...args) {
734 init(arg1, args...);
735}
736
748template <typename T>
751
752 return *this;
753}
754
766template <typename T>
767array<T> &array<T>::operator=(const std::initializer_list<T> &other) {
769 array_data.reserve(other.size());
770 for (auto &item : other) {
771 array_data.push_back(item);
772 }
773
774 return *this;
775}
776
786template <typename T>
788 if (array_data.size() != other.array_data.size()) {
789 return false;
790 }
791
792 for (int i = 0; i < (int)array_data.size(); i++) {
793 if (!eq(array_data.at(i), other.array_data.at(i))) {
794 return false;
795 }
796 }
797
798 return true;
799}
800
810template <typename T>
812 if (array_data.size() != other.array_data.size()) {
813 return (array_data.size() > other.array_data.size());
814 }
815
816 int gt_count = 0;
817
818 for (int i = 0; i < (int)array_data.size(); i++) {
819 if (gt(array_data.at(i), other.array_data.at(i))) {
820 gt_count++;
821 } else if (lt(array_data.at(i), other.array_data.at(i))) {
822 gt_count--;
823 }
824 }
825
826 return gt_count > 0;
827}
828
838template <typename T>
839bool array<T>::operator<(const array &other) const {
840 if (array_data.size() != other.array_data.size()) {
841 return (array_data.size() < other.array_data.size());
842 }
843
844 int gt_count = 0;
845
846 for (int i = 0; i < (int)array_data.size(); i++) {
847 if (gt(array_data.at(i), other.array_data.at(i))) {
848 gt_count++;
849 } else if (lt(array_data.at(i), other.array_data.at(i))) {
850 gt_count--;
851 }
852 }
853
854 return gt_count < 0;
855}
856
866template <typename T>
867inline bool array<T>::operator>=(const array &other) const {
868 return !operator<(other);
869}
870
880template <typename T>
881inline bool array<T>::operator<=(const array<T> &other) const {
882 return !operator>(other);
883}
884
886template <typename T>
887inline void array<T>::clear() {
889}
890
901template <typename T>
902array<T> &array<T>::insert(const T &object, int index) {
903 // if index is negative, insert from end of the array.
904 if (index < 0) {
905 index += array_data.size() + 1;
906 }
907
908 // keep within bounds of array.
909 if (index > (int)array_data.size()) {
910 index = array_data.size();
911 }
912 if (index < 0) {
913 index = 0;
914 }
915
916 array_data.insert(array_data.begin() + index, object);
917
918 return *this;
919}
920
933template <typename T>
934void array<T>::append(const T &object) {
935 array_data.push_back(object);
936}
937
945template <typename T>
947 if (index < 0) {
948 index += array_data.size() + 1;
949 }
950 if ((index >= array_data.size()) || (index < 0)) {
951 return *this;
952 }
953
954 array_data.erase(array_data.begin() + index);
955
956 return *this;
957}
958
967template <typename T>
968array<T> &array<T>::remove(int index, int count) {
969 if (!count) {
970 return *this;
971 }
972
973 if (index < 0) {
974 index += array_data.size() + 1;
975 }
976
977 int start, end;
978
979 if (count > 0) {
980 start = index;
981 end = index + count;
982 } else {
983 start = index + count + 1;
984 end = index + 1;
985 }
986
987 if ((end <= 0) || (start >= (int)array_data.size())) {
988 return *this;
989 }
990 if (start < 0) {
991 start = 0;
992 }
993 if (end > (int)array_data.size()) {
994 end = array_data.size();
995 }
996
997 array_data.erase(array_data.begin() + start, array_data.begin() + end);
998
999 return *this;
1000}
1001
1002template <typename T>
1004 size_t bytes = 0;
1005 for (auto &item : array_data) {
1006 size_t objBytes;
1008 bytes += objBytes;
1009 }
1010 return bytes;
1011}
1012
1013template <typename T>
1015 return array_data.size();
1016}
1017
1030template <typename T>
1031T &array<T>::at(int index) {
1032 return array_data.at(index);
1033}
1034
1047template <typename T>
1048const T &array<T>::at(int index) const {
1049 return array_data.at(index);
1050}
1051
1063template <typename T>
1064array<T> &array<T>::replace(int index, int count, const T &object) {
1065 if (!count) {
1066 return *this;
1067 }
1068
1069 if (index < 0) {
1070 index += array_data.size() + 1;
1071 }
1072
1073 int start, end;
1074
1075 if (count > 0) {
1076 start = index;
1077 end = index + count;
1078 } else {
1079 start = index + count + 1;
1080 end = index + 1;
1081 }
1082
1083 if ((end <= 0) || (start >= (int)array_data.size())) {
1084 return *this;
1085 }
1086 if (start < 0) {
1087 start = 0;
1088 }
1089 if (end > (int)array_data.size()) {
1090 end = array_data.size();
1091 }
1092
1093 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1094 array_data.insert(array_data.begin() + start, object);
1095
1096 return *this;
1097}
1098
1110template <typename T>
1111array<T> &array<T>::replace(int index, int count, const array<T> &other) {
1112 if (index < 0) {
1113 index += array_data.size();
1114 }
1115
1116 int start, end;
1117
1118 if (count >= 0) {
1119 start = index;
1120 end = index + count;
1121 } else {
1122 start = index + count + 1;
1123 end = index + 1;
1124 }
1125
1126 if ((end <= 0) || (start >= (int)array_data.size())) {
1127 return *this;
1128 }
1129 if (start < 0) {
1130 start = 0;
1131 }
1132 if (end > (int)array_data.size()) {
1133 end = array_data.size();
1134 }
1135
1136 if (count) {
1137 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1138 }
1139 array_data.insert(array_data.begin() + start, other.array_data.begin(), other.array_data.end());
1140
1141 return *this;
1142}
1143
1144template <typename T>
1145array<T> array<T>::subset(int index, int count) const {
1147
1148 if (!count) {
1149 return *this;
1150 }
1151
1152 if (index < 0) {
1153 index += array_data.size() + 1;
1154 }
1155
1156 int start, end;
1157
1158 if (count > 0) {
1159 start = index;
1160 end = index + count;
1161 } else {
1162 start = index + count + 1;
1163 end = index + 1;
1164 }
1165
1166 if ((end <= 0) || (start >= (int)array_data.size())) {
1167 return *this;
1168 }
1169 if (start < 0) {
1170 start = 0;
1171 }
1172 if (end > (int)array_data.size()) {
1173 end = array_data.size();
1174 }
1175
1176 if (end - start > 0) {
1177 output.array_data.reserve(end - start);
1178 }
1179 for (int i = start; i < end; i++) {
1180 output.array_data.push_back(array_data[i]);
1181 }
1182
1183 return output;
1184}
1185
1186template <typename T>
1187bool array<T>::operator()(const T &arg1, const T &arg2) const {
1188 return greater(arg1, arg2);
1189}
1190
1191template <typename T>
1192bool array<T>::isValid(int index) const {
1193 if (index < 0) {
1194 index += array_data.size();
1195 }
1196 return (index < (int)array_data.size()) && (index >= 0);
1197}
1198
1199template <typename T>
1201 auto temp = at(index1);
1204 return *this;
1205}
1206
1207template <typename T>
1208template <typename U>
1209array<U> array<T>::map(std::function<U(const T &)> lambda) const {
1211 result.increase(array_data.size());
1212
1213 for (const auto &i : array_data) {
1214 result.add(lambda(i));
1215 }
1216
1217 return result;
1218}
1219
1220template <typename T>
1221array<T> array<T>::filter(std::function<bool(const T &)> lambda) const {
1222 array result;
1223 result.increase(array_data.size()); // Increase it to the max size for performance, but it will likely be smaller than this.
1224
1225 for (const auto &i : array_data) {
1226 if (lambda(i)) {
1227 result.add(i);
1228 }
1229 }
1230
1231 return result;
1232}
1233
1234template <typename T>
1235T array<T>::reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const {
1236 const auto len = array_data.size();
1237 if (len == 0) {
1238 return defaultValue;
1239 }
1240
1241 auto result = array_data[0];
1242 for (int i = 1; i < len; ++i) {
1243 result = lambda(result, array_data[i]);
1244 }
1245
1246 return result;
1247}
1248
1249} // namespace core
1250} // namespace z
1251
1252#define zarray z::core::array
An interface for all objects that can be both iterated over and directly indexed.
Definition arrayLike.hpp:13
A wrapper for std::vector.
Definition array.hpp:75
bool isValid(int index) const
Check if an index is within the bounds of the array.
Definition array.hpp:1192
void increase(int newSize) noexcept
Increase the space allocated for this array.
Definition array.hpp:192
int push(const T &object) noexcept
Add an object to the array.
Definition array.hpp:242
virtual bool eq(const T &arg1, const T &arg2) const
Check if two objects are equal.
Definition array.hpp:111
bool contains(const T &object) const noexcept
Check if a given object is in the array.
Definition array.hpp:376
bool operator>(const array &other) const
Array greater-than operator.
Definition array.hpp:811
array filter(std::function< bool(const T &)> lambda) const
Filters the array based on a predicate and returns a new array containing the elements that satisfy t...
Definition array.hpp:1221
void load(archive &ar)
Binary specialization of serialization input.
Definition array.hpp:704
array(const array &other)
Copy constructor.
Definition array.hpp:722
virtual void shuffle() noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:433
void save(cereal::JSONOutputArchive &ar) const
JSON specialization of serialization output.
Definition array.hpp:638
void sort(std::function< bool(const T &, const T &)> lambda) noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:396
array sorted() const noexcept
Sort the array based on default comparison operator.
Definition array.hpp:407
void init(const T &arg1)
Helper function for single object initialization.
Definition array.hpp:84
virtual int find(const T &object) const
Find the index of a given object in the array.
Definition array.hpp:359
void add(const array &other) noexcept
Add another array to this array.
Definition array.hpp:224
array sorted(std::function< bool(const T &, const T &)> lambda) const noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:421
std::vector< T > array_data
The data in the array.
Definition array.hpp:78
array & operator=(const std::initializer_list< T > &other)
Initializer list assignment operator.
Definition array.hpp:767
void load(cereal::XMLInputArchive &ar)
XML specialization of serialization input.
Definition array.hpp:687
void save(cereal::XMLOutputArchive &ar) const
XML specialization of serialization output.
Definition array.hpp:649
array(const T &arg1, const Args &...args)
List-initialized constructor.
Definition array.hpp:733
void sort() noexcept
Sort the array based on default comparison operator.
Definition array.hpp:385
bool operator<=(const array &other) const
Array less-than-or-equal operator.
Definition array.hpp:881
array & operator=(const array &other)
Array assignment operator.
Definition array.hpp:749
T & operator[](int index)
Function to get the object at the given index.
Definition array.hpp:344
size_t size() const noexcept override
Get the size of the array.
Definition array.hpp:1003
array()
Default constructor.
Definition array.hpp:149
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1014
array shuffled() const noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:448
array & insert(const T &, int)
Insert an object into the array.
Definition array.hpp:902
virtual bool operator()(const T &arg1, const T &arg2) const
Callable operator.
Definition array.hpp:1187
bool operator<(const array &other) const
Array less-than operator.
Definition array.hpp:839
array randomElements(int count) const noexcept
Get N random elements from the array.
Definition array.hpp:588
array reversed() const noexcept
Reverse the order of all elements in the array.
Definition array.hpp:475
T & at(int)
Function to get the object at the given index.
Definition array.hpp:1031
void init(const T &arg1, const Args &...args)
Helper function for brace-enclosed list initialization.
Definition array.hpp:94
T randomElement() const
Get a random element from the array.
Definition array.hpp:567
void push(const array &other) noexcept
Add another array to this array.
Definition array.hpp:256
array & replace(int, int, const T &)
Replace all objects in the given range with an object.
Definition array.hpp:1064
array(const std::vector< T > &other)
Copy from std::vector.
Definition array.hpp:727
void append(const T &)
Append an object to the end of the array.
Definition array.hpp:934
array & remove(int)
Remove an object from the array.
Definition array.hpp:946
virtual ~array()
Destructor.
Definition array.hpp:180
T reduce(const T &defaultValue, std::function< T(const T &, const T &)> lambda) const
Reduces the array to a single value by applying a binary operation cumulatively to the elements.
Definition array.hpp:1235
bool operator>=(const array &other) const
Array greater-than-or-equal operator.
Definition array.hpp:867
virtual void reverse() noexcept
Reverse the order of all elements in the array.
Definition array.hpp:460
void save(archive &ar) const
Binary specialization of serialization output.
Definition array.hpp:660
array & replace(int, int, const array< T > &)
Replace all objects in the given range with an array of objects.
Definition array.hpp:1111
virtual int add(const T &object)
Add an object to the array.
Definition array.hpp:208
virtual bool gt(const T &arg1, const T &arg2) const
Check if one object is greater than another.
Definition array.hpp:127
array(const std::initializer_list< T > &other)
Construct from a generic initializer list.
Definition array.hpp:177
array subset(int index, int count) const
Get a contiguous subset of the elements in the array.
Definition array.hpp:1145
void load(cereal::JSONInputArchive &ar)
JSON specialization of serialization input.
Definition array.hpp:671
array & remove(int, int)
Remove all elements in a subset of the array.
Definition array.hpp:968
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:616
virtual bool lt(const T &arg1, const T &arg2) const
Check if one object is less than another.
Definition array.hpp:143
T * end() const noexcept override
Get pointer to the end of the array.
Definition array.hpp:628
bool operator==(const array &other) const
Check whether two arrays' contents are the same.
Definition array.hpp:787
array< U > map(std::function< U(const T &)> lambda) const
Applies a transformation function to each element of the array and returns a new array with the resul...
Definition array.hpp:1209
array & swap(int index1, int index2)
Swap two elements in an array.
Definition array.hpp:1200
void clear()
Clear the data in the array.
Definition array.hpp:887
T pop()
Remove the last element from this array.
Definition array.hpp:268
An arbitrary generator for producing sequential results on-the-fly.
Definition generator.hpp:85
An interface for getting an object's size.
Definition sizable.hpp:13
std::enable_if< std::is_base_of< z::core::sizable, T >::value >::type size(const T &object, size_t &bytes) noexcept
Get the size of a sizable object.
Definition sizable.hpp:34