libzed 1.11.4
A general-purpose library for quick and simple data manipulation.
 
Loading...
Searching...
No Matches
array.hpp
1#pragma once
2
3#include <algorithm>
4#include <functional>
5#include <initializer_list>
6#include <random>
7#include <stdexcept>
8#include <vector>
9
10#include "arrayLike.hpp"
11#include "compare.hpp"
12#include "sizable.hpp"
13#include "typeChecks.hpp"
14
15#ifdef __has_include
16#if __has_include(<cereal/cereal.hpp>)
17#include <cereal/archives/json.hpp>
18#include <cereal/archives/xml.hpp>
19#endif
20#endif
21
22namespace z {
23namespace core {
37template <typename T>
38class array : public sizable, public arrayLike<const T &, T *> {
39protected:
41 std::vector<T> array_data;
42
47 inline void init(const T &arg1) {
48 add(arg1);
49 }
50
56 template <typename... Args>
57 inline void init(const T &arg1, const Args &...args) {
58 add(arg1);
59 init(args...);
60 }
61
74 virtual bool eq(const T &arg1, const T &arg2) const {
75 return equals(arg1, arg2);
76 }
77
90 virtual bool gt(const T &arg1, const T &arg2) const {
91 return greater(arg1, arg2);
92 }
93
106 virtual bool lt(const T &arg1, const T &arg2) const {
107 return lesser(arg1, arg2);
108 }
109
110public:
112 array() {}
113
116
118 array(const std::vector<T> &other);
119
132 template <typename... Args>
133 array(const T &arg1, const Args &...args);
134
140 array(const std::initializer_list<T> &other) : array_data(other) {}
141
143 virtual ~array() {}
144
145 inline void clear();
146
155 void increase(int newSize) noexcept {
156 array_data.reserve(newSize);
157 }
158
171 virtual int add(const T &object) {
172 array_data.push_back(object);
173
174 return (array_data.size() - 1);
175 }
176
187 void add(const array &other) noexcept {
188 for (int i = 0; i < other.size(); i++) {
190 }
191 }
192
205 inline int push(const T &object) noexcept {
206 return add(object);
207 }
208
219 inline void push(const array &other) noexcept {
220 add(other);
221 }
222
231 T pop() {
232 if (!length()) {
233 throw std::out_of_range("No more elements in array.");
234 }
235
236 T element = at(length() - 1);
237 array_data.pop_back();
238 return element;
239 }
240
241 array &insert(const T &, int);
242
243 void append(const T &);
244
246 array &remove(int, int);
247
248 array &replace(int, int, const T &);
249 array &replace(int, int, const array<T> &);
250
264 array subset(int index, int count) const;
265
272
279
280 T &at(int);
282
295 const T &operator[](int index) const override {
296 return at(index);
297 }
298
311 T &operator[](int index) {
312 return at(index);
313 }
314
326 virtual int find(const T &object) const {
327 for (int i = 0; i < (int)array_data.size(); i++) {
328 if (eq(array_data.at(i), object)) {
329 return i;
330 }
331 }
332
333 return -1;
334 }
335
343 bool contains(const T &object) const noexcept {
344 return find(object) > -1;
345 }
346
352 void sort() noexcept {
353 sort(*this);
354 }
355
363 void sort(std::function<bool(const T &, const T &)> lambda) noexcept {
364 std::sort(array_data.begin(), array_data.end(), lambda);
365 }
366
375 auto new_array = *this;
376 new_array.sort();
377 return new_array;
378 }
379
388 array sorted(std::function<bool(const T &, const T &)> lambda) const noexcept {
389 auto new_array = *this;
390 new_array.sort(lambda);
391 return new_array;
392 }
393
400 virtual void shuffle() noexcept {
401 std::random_device device;
402 std::mt19937 generator(device());
403 std::shuffle(array_data.begin(), array_data.end(), generator);
404 }
405
415 auto new_array = *this;
417 return new_array;
418 }
419
426 virtual void reverse() noexcept {
427 const auto len = length();
428 for (int i = 0; i < (len / 2); ++i) {
429 std::swap(array_data[i], array_data[len - 1 - i]);
430 }
431 }
432
442 auto new_array = *this;
444 return new_array;
445 }
446
448 array &operator=(const std::initializer_list<T> &other);
449
450 bool operator==(const array &other) const;
451 bool operator>(const array &other) const;
452 bool operator<(const array &other) const;
453 inline bool operator!=(const array &other) const;
454 inline bool operator>=(const array &other) const;
455 inline bool operator<=(const array &other) const;
456
466 virtual bool operator()(const T &arg1, const T &arg2) const;
467
476 bool isValid(int index) const;
477
487
498 template <typename U>
499 array<U> map(std::function<U(const T &)> lambda) const;
500
511 array filter(std::function<bool(const T &)> lambda) const;
512
523 T reduce(std::function<T(const T &, const T &)> lambda, const T &defaultValue = {}) const;
524
530 template <typename U>
531 inline array<U> operator|(std::function<U(T)> lambda) noexcept {
532 return map<U>(lambda);
533 }
534
540 template <typename U>
541 inline array<U> operator|(U (*lambda)(T)) noexcept {
542 return map<U>(lambda);
543 }
544
550 inline array operator&&(std::function<T(const T &)> lambda) noexcept {
551 return filter(lambda);
552 }
553
565 inline T operator>>(std::function<T(const T &, const T &)> lambda) {
566 return reduce(lambda);
567 }
568
578 T randomElement() const {
579 if (array_data.empty()) {
580 throw std::out_of_range("Array is empty");
581 }
582
583 std::random_device device;
584 std::mt19937 generator(device());
585 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
587 }
588
599 array randomElements(int count) const noexcept {
600 if (array_data.empty()) {
601 return array();
602 }
603
604 std::random_device device;
605 std::mt19937 generator(device());
606 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
607
608 const int numElements = std::min(count, length());
609
612 for (int i = 0; i < numElements; ++i) {
614 }
615
616 return randomArray;
617 }
618
627 T *begin() const noexcept override {
628 return array_data.empty() ? NULL : (T *)&array_data.front();
629 }
630
639 T *end() const noexcept override {
640 return begin() + array_data.size();
641 }
642
643#ifdef __has_include
644#if __has_include(<cereal/cereal.hpp>)
649 void save(cereal::JSONOutputArchive &ar) const {
650 ar.makeArray();
651 for (int i = 0; i < (int)array_data.size(); i++) {
652 ar(array_data[i]);
653 }
654 }
655
660 void save(cereal::XMLOutputArchive &ar) const {
661 for (int i = 0; i < (int)array_data.size(); i++) {
662 ar(cereal::make_nvp(std::to_string(i), array_data[i]));
663 }
664 }
665
670 template <typename archive>
671 void save(archive &ar) const {
672 ar((size_t)array_data.size());
673 for (int i = 0; i < (int)array_data.size(); i++) {
674 ar(array_data[i]);
675 }
676 }
677
682 void load(cereal::JSONInputArchive &ar) {
684 ar.loadSize(sz);
685 array_data.reserve(sz);
686
687 T data;
688 for (int i = 0; i < sz; i++) {
689 ar(data);
690 array_data.push_back(data);
691 }
692 }
693
698 void load(cereal::XMLInputArchive &ar) {
700 ar.loadSize(sz);
701 array_data.reserve(sz);
702
703 T data;
704 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
705 ar(data);
706 array_data.push_back(data);
707 }
708 }
709
714 template <class archive>
715 void load(archive &ar) {
716 clear();
718 ar(sz);
719 array_data.reserve(sz);
720
721 T data;
722 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
723 ar(data);
724 array_data.push_back(data);
725 }
726 }
727
728#endif
729#endif
730};
731
732template <typename T>
736
737template <typename T>
738array<T>::array(const std::vector<T> &other) {
740}
741
742template <typename T>
743template <typename... Args>
744array<T>::array(const T &arg1, const Args &...args) {
745 init(arg1, args...);
746}
747
759template <typename T>
762
763 return *this;
764}
765
777template <typename T>
778array<T> &array<T>::operator=(const std::initializer_list<T> &other) {
780 array_data.reserve(other.size());
781 for (auto &item : other) {
782 array_data.push_back(item);
783 }
784
785 return *this;
786}
787
797template <typename T>
799 if (array_data.size() != other.array_data.size()) {
800 return false;
801 }
802
803 for (int i = 0; i < (int)array_data.size(); i++) {
804 if (!eq(array_data.at(i), other.array_data.at(i))) {
805 return false;
806 }
807 }
808
809 return true;
810}
811
821template <typename T>
823 if (array_data.size() != other.array_data.size()) {
824 return (array_data.size() > other.array_data.size());
825 }
826
827 int gt_count = 0;
828
829 for (int i = 0; i < (int)array_data.size(); i++) {
830 if (gt(array_data.at(i), other.array_data.at(i))) {
831 gt_count++;
832 } else if (lt(array_data.at(i), other.array_data.at(i))) {
833 gt_count--;
834 }
835 }
836
837 return gt_count > 0;
838}
839
849template <typename T>
850bool array<T>::operator<(const array &other) const {
851 if (array_data.size() != other.array_data.size()) {
852 return (array_data.size() < other.array_data.size());
853 }
854
855 int gt_count = 0;
856
857 for (int i = 0; i < (int)array_data.size(); i++) {
858 if (gt(array_data.at(i), other.array_data.at(i))) {
859 gt_count++;
860 } else if (lt(array_data.at(i), other.array_data.at(i))) {
861 gt_count--;
862 }
863 }
864
865 return gt_count < 0;
866}
867
877template <typename T>
878inline bool array<T>::operator!=(const array &other) const {
879 return !operator==(other);
880}
881
891template <typename T>
892inline bool array<T>::operator>=(const array &other) const {
893 return !operator<(other);
894}
895
905template <typename T>
906inline bool array<T>::operator<=(const array<T> &other) const {
907 return !operator>(other);
908}
909
911template <typename T>
912inline void array<T>::clear() {
914}
915
928template <typename T>
929array<T> &array<T>::insert(const T &object, int index) {
930 // if index is negative, insert from end of the array.
931 if (index < 0) {
932 index += array_data.size() + 1;
933 }
934
935 // keep within bounds of array.
936 if (index > (int)array_data.size()) {
937 index = array_data.size();
938 }
939 if (index < 0) {
940 index = 0;
941 }
942
943 array_data.insert(array_data.begin() + index, object);
944
945 return *this;
946}
947
960template <typename T>
961void array<T>::append(const T &object) {
962 array_data.push_back(object);
963}
964
972template <typename T>
974 if (index < 0) {
975 index += array_data.size() + 1;
976 }
977 if ((index >= array_data.size()) || (index < 0)) {
978 return *this;
979 }
980
981 array_data.erase(array_data.begin() + index);
982
983 return *this;
984}
985
994template <typename T>
995array<T> &array<T>::remove(int index, int count) {
996 if (!count) {
997 return *this;
998 }
999
1000 if (index < 0) {
1001 index += array_data.size() + 1;
1002 }
1003
1004 int start, end;
1005
1006 if (count > 0) {
1007 start = index;
1008 end = index + count;
1009 } else {
1010 start = index + count + 1;
1011 end = index + 1;
1012 }
1013
1014 if ((end <= 0) || (start >= (int)array_data.size())) {
1015 return *this;
1016 }
1017 if (start < 0) {
1018 start = 0;
1019 }
1020 if (end > (int)array_data.size()) {
1021 end = array_data.size();
1022 }
1023
1024 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1025
1026 return *this;
1027}
1028
1029template <typename T>
1031 size_t bytes = 0;
1032 for (auto &item : array_data) {
1033 size_t objBytes;
1035 bytes += objBytes;
1036 }
1037 return bytes;
1038}
1039
1040template <typename T>
1042 return array_data.size();
1043}
1044
1057template <typename T>
1058T &array<T>::at(int index) {
1059 return array_data.at(index);
1060}
1061
1074template <typename T>
1075const T &array<T>::at(int index) const {
1076 return array_data.at(index);
1077}
1078
1090template <typename T>
1091array<T> &array<T>::replace(int index, int count, const T &object) {
1092 if (!count) {
1093 return *this;
1094 }
1095
1096 if (index < 0) {
1097 index += array_data.size() + 1;
1098 }
1099
1100 int start, end;
1101
1102 if (count > 0) {
1103 start = index;
1104 end = index + count;
1105 } else {
1106 start = index + count + 1;
1107 end = index + 1;
1108 }
1109
1110 if ((end <= 0) || (start >= (int)array_data.size())) {
1111 return *this;
1112 }
1113 if (start < 0) {
1114 start = 0;
1115 }
1116 if (end > (int)array_data.size()) {
1117 end = array_data.size();
1118 }
1119
1120 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1121 array_data.insert(array_data.begin() + start, object);
1122
1123 return *this;
1124}
1125
1137template <typename T>
1138array<T> &array<T>::replace(int index, int count, const array<T> &other) {
1139 if (index < 0) {
1140 index += array_data.size();
1141 }
1142
1143 int start, end;
1144
1145 if (count >= 0) {
1146 start = index;
1147 end = index + count;
1148 } else {
1149 start = index + count + 1;
1150 end = index + 1;
1151 }
1152
1153 if ((end <= 0) || (start >= (int)array_data.size())) {
1154 return *this;
1155 }
1156 if (start < 0) {
1157 start = 0;
1158 }
1159 if (end > (int)array_data.size()) {
1160 end = array_data.size();
1161 }
1162
1163 if (count) {
1164 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1165 }
1166 array_data.insert(array_data.begin() + start, other.array_data.begin(), other.array_data.end());
1167
1168 return *this;
1169}
1170
1171template <typename T>
1172array<T> array<T>::subset(int index, int count) const {
1174
1175 if (!count) {
1176 return *this;
1177 }
1178
1179 if (index < 0) {
1180 index += array_data.size() + 1;
1181 }
1182
1183 int start, end;
1184
1185 if (count > 0) {
1186 start = index;
1187 end = index + count;
1188 } else {
1189 start = index + count + 1;
1190 end = index + 1;
1191 }
1192
1193 if ((end <= 0) || (start >= (int)array_data.size())) {
1194 return *this;
1195 }
1196 if (start < 0) {
1197 start = 0;
1198 }
1199 if (end > (int)array_data.size()) {
1200 end = array_data.size();
1201 }
1202
1203 if (end - start > 0) {
1204 output.array_data.reserve(end - start);
1205 }
1206 for (int i = start; i < end; i++) {
1207 output.array_data.push_back(array_data[i]);
1208 }
1209
1210 return output;
1211}
1212
1213template <typename T>
1214bool array<T>::operator()(const T &arg1, const T &arg2) const {
1215 return greater(arg1, arg2);
1216}
1217
1218template <typename T>
1219bool array<T>::isValid(int index) const {
1220 if (index < 0) {
1221 index += array_data.size();
1222 }
1223 return (index < (int)array_data.size()) && (index >= 0);
1224}
1225
1226template <typename T>
1228 auto temp = at(index1);
1231 return *this;
1232}
1233
1234template <typename T>
1235template <typename U>
1236array<U> array<T>::map(std::function<U(const T &)> lambda) const {
1238 result.increase(array_data.size());
1239
1240 for (const auto &i : array_data) {
1241 result.add(lambda(i));
1242 }
1243
1244 return result;
1245}
1246
1247template <typename T>
1248array<T> array<T>::filter(std::function<bool(const T &)> lambda) const {
1249 array result;
1250 result.increase(array_data.size()); // Increase it to the max size for performance, but it will likely be smaller than this.
1251
1252 for (const auto &i : array_data) {
1253 if (lambda(i)) {
1254 result.add(i);
1255 }
1256 }
1257
1258 return result;
1259}
1260
1261template <typename T>
1262T array<T>::reduce(std::function<T(const T &, const T &)> lambda, const T &defaultValue) const {
1263 const auto len = array_data.size();
1264 if (len == 0) {
1265 return defaultValue;
1266 }
1267
1268 auto result = array_data[0];
1269 for (int i = 1; i < len; ++i) {
1270 result = lambda(result, array_data[i]);
1271 }
1272
1273 return result;
1274}
1275
1276} // namespace core
1277} // namespace z
1278
1279#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:38
bool isValid(int index) const
Check if an index is within the bounds of the array.
Definition array.hpp:1219
void increase(int newSize) noexcept
Increase the space allocated for this array.
Definition array.hpp:155
int push(const T &object) noexcept
Add an object to the array.
Definition array.hpp:205
virtual bool eq(const T &arg1, const T &arg2) const
Check if two objects are equal.
Definition array.hpp:74
bool contains(const T &object) const noexcept
Check if a given object is in the array.
Definition array.hpp:343
bool operator>(const array &other) const
Array greater-than operator.
Definition array.hpp:822
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:1248
array(const array &other)
Copy constructor.
Definition array.hpp:733
virtual void shuffle() noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:400
void sort(std::function< bool(const T &, const T &)> lambda) noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:363
array< U > operator|(U(*lambda)(T)) noexcept
Definition array.hpp:541
array sorted() const noexcept
Sort the array based on default comparison operator.
Definition array.hpp:374
void init(const T &arg1)
Helper function for single object initialization.
Definition array.hpp:47
virtual int find(const T &object) const
Find the index of a given object in the array.
Definition array.hpp:326
void add(const array &other) noexcept
Add another array to this array.
Definition array.hpp:187
array sorted(std::function< bool(const T &, const T &)> lambda) const noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:388
std::vector< T > array_data
The data in the array.
Definition array.hpp:41
array & operator=(const std::initializer_list< T > &other)
Initializer list assignment operator.
Definition array.hpp:778
array(const T &arg1, const Args &...args)
List-initialized constructor.
Definition array.hpp:744
void sort() noexcept
Sort the array based on default comparison operator.
Definition array.hpp:352
bool operator<=(const array &other) const
Array less-than-or-equal operator.
Definition array.hpp:906
array & operator=(const array &other)
Array assignment operator.
Definition array.hpp:760
bool operator!=(const array &other) const
Check whether two arrays' contents are different.
Definition array.hpp:878
T & operator[](int index)
Function to get the object at the given index.
Definition array.hpp:311
size_t size() const noexcept override
Get the size of the array.
Definition array.hpp:1030
array()
Default constructor.
Definition array.hpp:112
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1041
array shuffled() const noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:414
array & insert(const T &, int)
Insert an object into the array.
Definition array.hpp:929
virtual bool operator()(const T &arg1, const T &arg2) const
Callable operator.
Definition array.hpp:1214
bool operator<(const array &other) const
Array less-than operator.
Definition array.hpp:850
array randomElements(int count) const noexcept
Get N random elements from the array.
Definition array.hpp:599
array reversed() const noexcept
Reverse the order of all elements in the array.
Definition array.hpp:441
T & at(int)
Function to get the object at the given index.
Definition array.hpp:1058
void init(const T &arg1, const Args &...args)
Helper function for brace-enclosed list initialization.
Definition array.hpp:57
T randomElement() const
Get a random element from the array.
Definition array.hpp:578
void push(const array &other) noexcept
Add another array to this array.
Definition array.hpp:219
T operator>>(std::function< T(const T &, const T &)> lambda)
Reduces the array to a single value by applying a binary operation cumulatively to the elements.
Definition array.hpp:565
array & replace(int, int, const T &)
Replace all objects in the given range with an object.
Definition array.hpp:1091
array(const std::vector< T > &other)
Copy from std::vector.
Definition array.hpp:738
void append(const T &)
Append an object to the end of the array.
Definition array.hpp:961
array & remove(int)
Remove an object from the array.
Definition array.hpp:973
virtual ~array()
Destructor.
Definition array.hpp:143
bool operator>=(const array &other) const
Array greater-than-or-equal operator.
Definition array.hpp:892
virtual void reverse() noexcept
Reverse the order of all elements in the array.
Definition array.hpp:426
array & replace(int, int, const array< T > &)
Replace all objects in the given range with an array of objects.
Definition array.hpp:1138
virtual int add(const T &object)
Add an object to the array.
Definition array.hpp:171
array operator&&(std::function< T(const T &)> lambda) noexcept
Definition array.hpp:550
virtual bool gt(const T &arg1, const T &arg2) const
Check if one object is greater than another.
Definition array.hpp:90
array< U > operator|(std::function< U(T)> lambda) noexcept
Definition array.hpp:531
array(const std::initializer_list< T > &other)
Construct from a generic initializer list.
Definition array.hpp:140
array subset(int index, int count) const
Get a contiguous subset of the elements in the array.
Definition array.hpp:1172
T reduce(std::function< T(const T &, const T &)> lambda, const T &defaultValue={}) const
Reduces the array to a single value by applying a binary operation cumulatively to the elements.
Definition array.hpp:1262
array & remove(int, int)
Remove all elements in a subset of the array.
Definition array.hpp:995
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:627
virtual bool lt(const T &arg1, const T &arg2) const
Check if one object is less than another.
Definition array.hpp:106
T * end() const noexcept override
Get pointer to the end of the array.
Definition array.hpp:639
bool operator==(const array &other) const
Check whether two arrays' contents are the same.
Definition array.hpp:798
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:1236
array & swap(int index1, int index2)
Swap two elements in an array.
Definition array.hpp:1227
void clear()
Clear the data in the array.
Definition array.hpp:912
T pop()
Remove the last element from this array.
Definition array.hpp:231
An arbitrary generator for producing sequential results on-the-fly.
Definition generator.hpp:71
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:31