libzed 1.9.9
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#endif
55
56namespace z {
57namespace core {
71template <typename T>
72class array : public sizable, public arrayLike<const T &, T *> {
73protected:
75 std::vector<T> array_data;
76
81 inline void init(const T &arg1) {
82 add(arg1);
83 }
84
90 template <typename... Args>
91 inline void init(const T &arg1, const Args &...args) {
92 add(arg1);
93 init(args...);
94 }
95
108 virtual bool eq(const T &arg1, const T &arg2) const {
109 return equals(arg1, arg2);
110 }
111
124 virtual bool gt(const T &arg1, const T &arg2) const {
125 return greater(arg1, arg2);
126 }
127
140 virtual bool lt(const T &arg1, const T &arg2) const {
141 return lesser(arg1, arg2);
142 }
143
144public:
146 array() {}
147
150
152 array(const std::vector<T> &other);
153
166 template <typename... Args>
167 array(const T &arg1, const Args &...args);
168
174 array(const std::initializer_list<T> &other) : array_data(other) {}
175
177 virtual ~array() {}
178
179 inline void clear();
180
189 void increase(int newSize) noexcept {
190 array_data.reserve(newSize);
191 }
192
205 virtual int add(const T &object) {
206 array_data.push_back(object);
207
208 return (array_data.size() - 1);
209 }
210
221 void add(const array &other) noexcept {
222 for (int i = 0; i < other.size(); i++) {
224 }
225 }
226
239 inline int push(const T &object) noexcept {
240 return add(object);
241 }
242
253 inline void push(const array &other) noexcept {
254 add(other);
255 }
256
265 T pop() {
266 T element = at(length());
267 array_data.pop_back();
268 return element;
269 }
270
271 array &insert(const T &, int);
272
273 void append(const T &);
274
276 array &remove(int, int);
277
278 array &replace(int, int, const T &);
279 array &replace(int, int, const array<T> &);
280
294 array subset(int index, int count) const;
295
302
309
310 T &at(int);
312
325 const T &operator[](int index) const override {
326 return at(index);
327 }
328
341 T &operator[](int index) {
342 return at(index);
343 }
344
356 virtual int find(const T &object) const {
357 for (int i = 0; i < (int)array_data.size(); i++) {
358 if (eq(array_data.at(i), object)) {
359 return i;
360 }
361 }
362
363 return -1;
364 }
365
373 bool contains(const T &object) const noexcept {
374 return find(object) > -1;
375 }
376
382 void sort() noexcept {
383 sort(*this);
384 }
385
393 void sort(std::function<bool(const T &, const T &)> lambda) noexcept {
394 std::sort(array_data.begin(), array_data.end(), lambda);
395 }
396
405 auto new_array = *this;
406 new_array.sort();
407 return new_array;
408 }
409
418 array sorted(std::function<bool(const T &, const T &)> lambda) const noexcept {
419 auto new_array = *this;
420 new_array.sort(lambda);
421 return new_array;
422 }
423
430 virtual void shuffle() noexcept {
431 // Use std::shuffle if C++17
432 std::random_device device;
433 std::mt19937 generator(device());
434 std::shuffle(array_data.begin(), array_data.end(), generator);
435 }
436
446 auto new_array = *this;
448 return new_array;
449 }
450
457 virtual void reverse() noexcept {
458 const auto len = length();
459 for (int i = 0; i < (len / 2); ++i) {
460 std::swap(array_data[i], array_data[len - 1 - i]);
461 }
462 }
463
473 auto new_array = *this;
475 return new_array;
476 }
477
479 array &operator=(const std::initializer_list<T> &other);
480
481 bool operator==(const array &other) const;
482 bool operator>(const array &other) const;
483 bool operator<(const array &other) const;
484 inline bool operator>=(const array &other) const;
485 inline bool operator<=(const array &other) const;
486
496 virtual bool operator()(const T &arg1, const T &arg2) const;
497
506 bool isValid(int index) const;
507
517
528 template <typename U>
529 array<U> map(std::function<U(const T &)> lambda) const;
530
541 array filter(std::function<bool(const T &)> lambda) const;
542
553 T reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const;
554
564 T randomElement() const {
565 if (array_data.empty()) {
566 throw std::out_of_range("Array is empty");
567 }
568
569 std::random_device device;
570 std::mt19937 generator(device());
571 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
573 }
574
585 array randomElements(int count) const noexcept {
586 if (array_data.empty()) {
587 return array();
588 }
589
590 std::random_device device;
591 std::mt19937 generator(device());
592 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
593
594 const int numElements = std::min(count, length());
595
598 for (int i = 0; i < numElements; ++i) {
600 }
601
602 return randomArray;
603 }
604
613 T *begin() const noexcept override {
614 return array_data.empty() ? NULL : (T *)&array_data.front();
615 }
616
625 T *end() const noexcept override {
626 return begin() + array_data.size();
627 }
628
629#ifdef __has_include
630#if __has_include(<cereal/cereal.hpp>)
635 void save(cereal::JSONOutputArchive &ar) const {
636 ar.makeArray();
637 for (int i = 0; i < (int)array_data.size(); i++) {
638 ar(array_data[i]);
639 }
640 }
641
646 void save(cereal::XMLOutputArchive &ar) const {
647 for (int i = 0; i < (int)array_data.size(); i++) {
648 ar(cereal::make_nvp(std::to_string(i), array_data[i]));
649 }
650 }
651
656 template <typename archive>
657 void save(archive &ar) const {
658 ar((size_t)array_data.size());
659 for (int i = 0; i < (int)array_data.size(); i++) {
660 ar(array_data[i]);
661 }
662 }
663
668 void load(cereal::JSONInputArchive &ar) {
670 ar.loadSize(sz);
671 array_data.reserve(sz);
672
673 T data;
674 for (int i = 0; i < sz; i++) {
675 ar(data);
676 array_data.push_back(data);
677 }
678 }
679
684 void load(cereal::XMLInputArchive &ar) {
686 ar.loadSize(sz);
687 array_data.reserve(sz);
688
689 T data;
690 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
691 ar(data);
692 array_data.push_back(data);
693 }
694 }
695
700 template <class archive>
701 void load(archive &ar) {
702 clear();
704 ar(sz);
705 array_data.reserve(sz);
706
707 T data;
708 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
709 ar(data);
710 array_data.push_back(data);
711 }
712 }
713
714#endif
715#endif
716};
717
718template <typename T>
722
723template <typename T>
724array<T>::array(const std::vector<T> &other) {
726}
727
728template <typename T>
729template <typename... Args>
730array<T>::array(const T &arg1, const Args &...args) {
731 init(arg1, args...);
732}
733
745template <typename T>
748
749 return *this;
750}
751
763template <typename T>
764array<T> &array<T>::operator=(const std::initializer_list<T> &other) {
766 array_data.reserve(other.size());
767 for (auto &item : other) {
768 array_data.push_back(item);
769 }
770
771 return *this;
772}
773
783template <typename T>
785 if (array_data.size() != other.array_data.size()) {
786 return false;
787 }
788
789 for (int i = 0; i < (int)array_data.size(); i++) {
790 if (!eq(array_data.at(i), other.array_data.at(i))) {
791 return false;
792 }
793 }
794
795 return true;
796}
797
807template <typename T>
809 if (array_data.size() != other.array_data.size()) {
810 return (array_data.size() > other.array_data.size());
811 }
812
813 int gt_count = 0;
814
815 for (int i = 0; i < (int)array_data.size(); i++) {
816 if (gt(array_data.at(i), other.array_data.at(i))) {
817 gt_count++;
818 } else if (lt(array_data.at(i), other.array_data.at(i))) {
819 gt_count--;
820 }
821 }
822
823 return gt_count > 0;
824}
825
835template <typename T>
836bool array<T>::operator<(const array &other) const {
837 if (array_data.size() != other.array_data.size()) {
838 return (array_data.size() < other.array_data.size());
839 }
840
841 int gt_count = 0;
842
843 for (int i = 0; i < (int)array_data.size(); i++) {
844 if (gt(array_data.at(i), other.array_data.at(i))) {
845 gt_count++;
846 } else if (lt(array_data.at(i), other.array_data.at(i))) {
847 gt_count--;
848 }
849 }
850
851 return gt_count < 0;
852}
853
863template <typename T>
864inline bool array<T>::operator>=(const array &other) const {
865 return !operator<(other);
866}
867
877template <typename T>
878inline bool array<T>::operator<=(const array<T> &other) const {
879 return !operator>(other);
880}
881
883template <typename T>
884inline void array<T>::clear() {
886}
887
898template <typename T>
899array<T> &array<T>::insert(const T &object, int index) {
900 // if index is negative, insert from end of the array.
901 if (index < 0) {
902 index += array_data.size() + 1;
903 }
904
905 // keep within bounds of array.
906 if (index > (int)array_data.size()) {
907 index = array_data.size();
908 }
909 if (index < 0) {
910 index = 0;
911 }
912
913 array_data.insert(array_data.begin() + index, object);
914
915 return *this;
916}
917
930template <typename T>
931void array<T>::append(const T &object) {
932 array_data.push_back(object);
933}
934
942template <typename T>
944 if (index < 0) {
945 index += array_data.size() + 1;
946 }
947 if ((index >= array_data.size()) || (index < 0)) {
948 return *this;
949 }
950
951 array_data.erase(array_data.begin() + index);
952
953 return *this;
954}
955
964template <typename T>
965array<T> &array<T>::remove(int index, int count) {
966 if (!count) {
967 return *this;
968 }
969
970 if (index < 0) {
971 index += array_data.size() + 1;
972 }
973
974 int start, end;
975
976 if (count > 0) {
977 start = index;
978 end = index + count;
979 } else {
980 start = index + count + 1;
981 end = index + 1;
982 }
983
984 if ((end <= 0) || (start >= (int)array_data.size())) {
985 return *this;
986 }
987 if (start < 0) {
988 start = 0;
989 }
990 if (end > (int)array_data.size()) {
991 end = array_data.size();
992 }
993
994 array_data.erase(array_data.begin() + start, array_data.begin() + end);
995
996 return *this;
997}
998
999template <typename T>
1001 size_t bytes = 0;
1002 for (auto &item : array_data) {
1003 size_t objBytes;
1005 bytes += objBytes;
1006 }
1007 return bytes;
1008}
1009
1010template <typename T>
1012 return array_data.size();
1013}
1014
1027template <typename T>
1028T &array<T>::at(int index) {
1029 return array_data.at(index);
1030}
1031
1044template <typename T>
1045const T &array<T>::at(int index) const {
1046 return array_data.at(index);
1047}
1048
1060template <typename T>
1061array<T> &array<T>::replace(int index, int count, const T &object) {
1062 if (!count) {
1063 return *this;
1064 }
1065
1066 if (index < 0) {
1067 index += array_data.size() + 1;
1068 }
1069
1070 int start, end;
1071
1072 if (count > 0) {
1073 start = index;
1074 end = index + count;
1075 } else {
1076 start = index + count + 1;
1077 end = index + 1;
1078 }
1079
1080 if ((end <= 0) || (start >= (int)array_data.size())) {
1081 return *this;
1082 }
1083 if (start < 0) {
1084 start = 0;
1085 }
1086 if (end > (int)array_data.size()) {
1087 end = array_data.size();
1088 }
1089
1090 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1091 array_data.insert(array_data.begin() + start, object);
1092
1093 return *this;
1094}
1095
1107template <typename T>
1108array<T> &array<T>::replace(int index, int count, const array<T> &other) {
1109 if (index < 0) {
1110 index += array_data.size();
1111 }
1112
1113 int start, end;
1114
1115 if (count >= 0) {
1116 start = index;
1117 end = index + count;
1118 } else {
1119 start = index + count + 1;
1120 end = index + 1;
1121 }
1122
1123 if ((end <= 0) || (start >= (int)array_data.size())) {
1124 return *this;
1125 }
1126 if (start < 0) {
1127 start = 0;
1128 }
1129 if (end > (int)array_data.size()) {
1130 end = array_data.size();
1131 }
1132
1133 if (count) {
1134 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1135 }
1136 array_data.insert(array_data.begin() + start, other.array_data.begin(), other.array_data.end());
1137
1138 return *this;
1139}
1140
1141template <typename T>
1142array<T> array<T>::subset(int index, int count) const {
1144
1145 if (!count) {
1146 return *this;
1147 }
1148
1149 if (index < 0) {
1150 index += array_data.size() + 1;
1151 }
1152
1153 int start, end;
1154
1155 if (count > 0) {
1156 start = index;
1157 end = index + count;
1158 } else {
1159 start = index + count + 1;
1160 end = index + 1;
1161 }
1162
1163 if ((end <= 0) || (start >= (int)array_data.size())) {
1164 return *this;
1165 }
1166 if (start < 0) {
1167 start = 0;
1168 }
1169 if (end > (int)array_data.size()) {
1170 end = array_data.size();
1171 }
1172
1173 if (end - start > 0) {
1174 output.array_data.reserve(end - start);
1175 }
1176 for (int i = start; i < end; i++) {
1177 output.array_data.push_back(array_data[i]);
1178 }
1179
1180 return output;
1181}
1182
1183template <typename T>
1184bool array<T>::operator()(const T &arg1, const T &arg2) const {
1185 return greater(arg1, arg2);
1186}
1187
1188template <typename T>
1189bool array<T>::isValid(int index) const {
1190 if (index < 0) {
1191 index += array_data.size();
1192 }
1193 return (index < (int)array_data.size()) && (index >= 0);
1194}
1195
1196template <typename T>
1198 auto temp = at(index1);
1201 return *this;
1202}
1203
1204template <typename T>
1205template <typename U>
1206array<U> array<T>::map(std::function<U(const T &)> lambda) const {
1208 result.increase(array_data.size());
1209
1210 for (const auto &i : array_data) {
1211 result.add(lambda(i));
1212 }
1213
1214 return result;
1215}
1216
1217template <typename T>
1218array<T> array<T>::filter(std::function<bool(const T &)> lambda) const {
1219 array result;
1220 result.increase(array_data.size()); // Increase it to the max size for performance, but it will likely be smaller than this.
1221
1222 for (const auto &i : array_data) {
1223 if (lambda(i)) {
1224 result.add(i);
1225 }
1226 }
1227
1228 return result;
1229}
1230
1231template <typename T>
1232T array<T>::reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const {
1233 const auto len = array_data.size();
1234 if (len == 0) {
1235 return defaultValue;
1236 }
1237
1238 auto result = array_data[0];
1239 for (int i = 1; i < len; ++i) {
1240 result = lambda(result, array_data[i]);
1241 }
1242
1243 return result;
1244}
1245
1246} // namespace core
1247} // namespace z
1248
1249#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:72
bool isValid(int index) const
Check if an index is within the bounds of the array.
Definition array.hpp:1189
void increase(int newSize) noexcept
Increase the space allocated for this array.
Definition array.hpp:189
int push(const T &object) noexcept
Add an object to the array.
Definition array.hpp:239
virtual bool eq(const T &arg1, const T &arg2) const
Check if two objects are equal.
Definition array.hpp:108
bool contains(const T &object) const noexcept
Check if a given object is in the array.
Definition array.hpp:373
bool operator>(const array &other) const
Array greater-than operator.
Definition array.hpp:808
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:1218
void load(archive &ar)
Binary specialization of serialization input.
Definition array.hpp:701
array(const array &other)
Copy constructor.
Definition array.hpp:719
virtual void shuffle() noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:430
void save(cereal::JSONOutputArchive &ar) const
JSON specialization of serialization output.
Definition array.hpp:635
void sort(std::function< bool(const T &, const T &)> lambda) noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:393
array sorted() const noexcept
Sort the array based on default comparison operator.
Definition array.hpp:404
void init(const T &arg1)
Helper function for single object initialization.
Definition array.hpp:81
virtual int find(const T &object) const
Find the index of a given object in the array.
Definition array.hpp:356
void add(const array &other) noexcept
Add another array to this array.
Definition array.hpp:221
array sorted(std::function< bool(const T &, const T &)> lambda) const noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:418
std::vector< T > array_data
The data in the array.
Definition array.hpp:75
array & operator=(const std::initializer_list< T > &other)
Initializer list assignment operator.
Definition array.hpp:764
void load(cereal::XMLInputArchive &ar)
XML specialization of serialization input.
Definition array.hpp:684
void save(cereal::XMLOutputArchive &ar) const
XML specialization of serialization output.
Definition array.hpp:646
array(const T &arg1, const Args &...args)
List-initialized constructor.
Definition array.hpp:730
void sort() noexcept
Sort the array based on default comparison operator.
Definition array.hpp:382
bool operator<=(const array &other) const
Array less-than-or-equal operator.
Definition array.hpp:878
array & operator=(const array &other)
Array assignment operator.
Definition array.hpp:746
T & operator[](int index)
Function to get the object at the given index.
Definition array.hpp:341
size_t size() const noexcept override
Get the size of the array.
Definition array.hpp:1000
array()
Default constructor.
Definition array.hpp:146
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1011
array shuffled() const noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:445
array & insert(const T &, int)
Insert an object into the array.
Definition array.hpp:899
virtual bool operator()(const T &arg1, const T &arg2) const
Callable operator.
Definition array.hpp:1184
bool operator<(const array &other) const
Array less-than operator.
Definition array.hpp:836
array randomElements(int count) const noexcept
Get N random elements from the array.
Definition array.hpp:585
array reversed() const noexcept
Reverse the order of all elements in the array.
Definition array.hpp:472
T & at(int)
Function to get the object at the given index.
Definition array.hpp:1028
void init(const T &arg1, const Args &...args)
Helper function for brace-enclosed list initialization.
Definition array.hpp:91
T randomElement() const
Get a random element from the array.
Definition array.hpp:564
void push(const array &other) noexcept
Add another array to this array.
Definition array.hpp:253
array & replace(int, int, const T &)
Replace all objects in the given range with an object.
Definition array.hpp:1061
array(const std::vector< T > &other)
Copy from std::vector.
Definition array.hpp:724
void append(const T &)
Append an object to the end of the array.
Definition array.hpp:931
array & remove(int)
Remove an object from the array.
Definition array.hpp:943
virtual ~array()
Destructor.
Definition array.hpp:177
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:1232
bool operator>=(const array &other) const
Array greater-than-or-equal operator.
Definition array.hpp:864
virtual void reverse() noexcept
Reverse the order of all elements in the array.
Definition array.hpp:457
void save(archive &ar) const
Binary specialization of serialization output.
Definition array.hpp:657
array & replace(int, int, const array< T > &)
Replace all objects in the given range with an array of objects.
Definition array.hpp:1108
virtual int add(const T &object)
Add an object to the array.
Definition array.hpp:205
virtual bool gt(const T &arg1, const T &arg2) const
Check if one object is greater than another.
Definition array.hpp:124
array(const std::initializer_list< T > &other)
Construct from a generic initializer list.
Definition array.hpp:174
array subset(int index, int count) const
Get a contiguous subset of the elements in the array.
Definition array.hpp:1142
void load(cereal::JSONInputArchive &ar)
JSON specialization of serialization input.
Definition array.hpp:668
array & remove(int, int)
Remove all elements in a subset of the array.
Definition array.hpp:965
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:613
virtual bool lt(const T &arg1, const T &arg2) const
Check if one object is less than another.
Definition array.hpp:140
T * end() const noexcept override
Get pointer to the end of the array.
Definition array.hpp:625
bool operator==(const array &other) const
Check whether two arrays' contents are the same.
Definition array.hpp:784
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:1206
array & swap(int index1, int index2)
Swap two elements in an array.
Definition array.hpp:1197
void clear()
Clear the data in the array.
Definition array.hpp:884
T pop()
Remove the last element from this array.
Definition array.hpp:265
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