libzed 1.10.2
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 if (!length()) {
270 throw std::out_of_range("No more elements in array.");
271 }
272
273 T element = at(length() - 1);
274 array_data.pop_back();
275 return element;
276 }
277
278 array &insert(const T &, int);
279
280 void append(const T &);
281
283 array &remove(int, int);
284
285 array &replace(int, int, const T &);
286 array &replace(int, int, const array<T> &);
287
301 array subset(int index, int count) const;
302
309
316
317 T &at(int);
319
332 const T &operator[](int index) const override {
333 return at(index);
334 }
335
348 T &operator[](int index) {
349 return at(index);
350 }
351
363 virtual int find(const T &object) const {
364 for (int i = 0; i < (int)array_data.size(); i++) {
365 if (eq(array_data.at(i), object)) {
366 return i;
367 }
368 }
369
370 return -1;
371 }
372
380 bool contains(const T &object) const noexcept {
381 return find(object) > -1;
382 }
383
389 void sort() noexcept {
390 sort(*this);
391 }
392
400 void sort(std::function<bool(const T &, const T &)> lambda) noexcept {
401 std::sort(array_data.begin(), array_data.end(), lambda);
402 }
403
412 auto new_array = *this;
413 new_array.sort();
414 return new_array;
415 }
416
425 array sorted(std::function<bool(const T &, const T &)> lambda) const noexcept {
426 auto new_array = *this;
427 new_array.sort(lambda);
428 return new_array;
429 }
430
437 virtual void shuffle() noexcept {
438 // Use std::shuffle if C++17
439 std::random_device device;
440 std::mt19937 generator(device());
441 std::shuffle(array_data.begin(), array_data.end(), generator);
442 }
443
453 auto new_array = *this;
455 return new_array;
456 }
457
464 virtual void reverse() noexcept {
465 const auto len = length();
466 for (int i = 0; i < (len / 2); ++i) {
467 std::swap(array_data[i], array_data[len - 1 - i]);
468 }
469 }
470
480 auto new_array = *this;
482 return new_array;
483 }
484
486 array &operator=(const std::initializer_list<T> &other);
487
488 bool operator==(const array &other) const;
489 bool operator>(const array &other) const;
490 bool operator<(const array &other) const;
491 inline bool operator!=(const array &other) const;
492 inline bool operator>=(const array &other) const;
493 inline bool operator<=(const array &other) const;
494
504 virtual bool operator()(const T &arg1, const T &arg2) const;
505
514 bool isValid(int index) const;
515
525
536 template <typename U>
537 array<U> map(std::function<U(const T &)> lambda) const;
538
549 array filter(std::function<bool(const T &)> lambda) const;
550
561 T reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const;
562
572 T randomElement() const {
573 if (array_data.empty()) {
574 throw std::out_of_range("Array is empty");
575 }
576
577 std::random_device device;
578 std::mt19937 generator(device());
579 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
581 }
582
593 array randomElements(int count) const noexcept {
594 if (array_data.empty()) {
595 return array();
596 }
597
598 std::random_device device;
599 std::mt19937 generator(device());
600 std::uniform_int_distribution<int> distribution(0, array_data.size() - 1);
601
602 const int numElements = std::min(count, length());
603
606 for (int i = 0; i < numElements; ++i) {
608 }
609
610 return randomArray;
611 }
612
621 T *begin() const noexcept override {
622 return array_data.empty() ? NULL : (T *)&array_data.front();
623 }
624
633 T *end() const noexcept override {
634 return begin() + array_data.size();
635 }
636
637#ifdef __has_include
638#if __has_include(<cereal/cereal.hpp>)
643 void save(cereal::JSONOutputArchive &ar) const {
644 ar.makeArray();
645 for (int i = 0; i < (int)array_data.size(); i++) {
646 ar(array_data[i]);
647 }
648 }
649
654 void save(cereal::XMLOutputArchive &ar) const {
655 for (int i = 0; i < (int)array_data.size(); i++) {
656 ar(cereal::make_nvp(std::to_string(i), array_data[i]));
657 }
658 }
659
664 template <typename archive>
665 void save(archive &ar) const {
666 ar((size_t)array_data.size());
667 for (int i = 0; i < (int)array_data.size(); i++) {
668 ar(array_data[i]);
669 }
670 }
671
676 void load(cereal::JSONInputArchive &ar) {
678 ar.loadSize(sz);
679 array_data.reserve(sz);
680
681 T data;
682 for (int i = 0; i < sz; i++) {
683 ar(data);
684 array_data.push_back(data);
685 }
686 }
687
692 void load(cereal::XMLInputArchive &ar) {
694 ar.loadSize(sz);
695 array_data.reserve(sz);
696
697 T data;
698 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
699 ar(data);
700 array_data.push_back(data);
701 }
702 }
703
708 template <class archive>
709 void load(archive &ar) {
710 clear();
712 ar(sz);
713 array_data.reserve(sz);
714
715 T data;
716 for (CEREAL_SIZE_TYPE i = 0; i < sz; i++) {
717 ar(data);
718 array_data.push_back(data);
719 }
720 }
721
722#endif
723#endif
724};
725
726template <typename T>
730
731template <typename T>
732array<T>::array(const std::vector<T> &other) {
734}
735
736template <typename T>
737template <typename... Args>
738array<T>::array(const T &arg1, const Args &...args) {
739 init(arg1, args...);
740}
741
753template <typename T>
756
757 return *this;
758}
759
771template <typename T>
772array<T> &array<T>::operator=(const std::initializer_list<T> &other) {
774 array_data.reserve(other.size());
775 for (auto &item : other) {
776 array_data.push_back(item);
777 }
778
779 return *this;
780}
781
791template <typename T>
793 if (array_data.size() != other.array_data.size()) {
794 return false;
795 }
796
797 for (int i = 0; i < (int)array_data.size(); i++) {
798 if (!eq(array_data.at(i), other.array_data.at(i))) {
799 return false;
800 }
801 }
802
803 return true;
804}
805
815template <typename T>
817 if (array_data.size() != other.array_data.size()) {
818 return (array_data.size() > other.array_data.size());
819 }
820
821 int gt_count = 0;
822
823 for (int i = 0; i < (int)array_data.size(); i++) {
824 if (gt(array_data.at(i), other.array_data.at(i))) {
825 gt_count++;
826 } else if (lt(array_data.at(i), other.array_data.at(i))) {
827 gt_count--;
828 }
829 }
830
831 return gt_count > 0;
832}
833
843template <typename T>
844bool array<T>::operator<(const array &other) const {
845 if (array_data.size() != other.array_data.size()) {
846 return (array_data.size() < other.array_data.size());
847 }
848
849 int gt_count = 0;
850
851 for (int i = 0; i < (int)array_data.size(); i++) {
852 if (gt(array_data.at(i), other.array_data.at(i))) {
853 gt_count++;
854 } else if (lt(array_data.at(i), other.array_data.at(i))) {
855 gt_count--;
856 }
857 }
858
859 return gt_count < 0;
860}
861
871template <typename T>
872inline bool array<T>::operator!=(const array &other) const {
873 return !operator==(other);
874}
875
885template <typename T>
886inline bool array<T>::operator>=(const array &other) const {
887 return !operator<(other);
888}
889
899template <typename T>
900inline bool array<T>::operator<=(const array<T> &other) const {
901 return !operator>(other);
902}
903
905template <typename T>
906inline void array<T>::clear() {
908}
909
922template <typename T>
923array<T> &array<T>::insert(const T &object, int index) {
924 // if index is negative, insert from end of the array.
925 if (index < 0) {
926 index += array_data.size() + 1;
927 }
928
929 // keep within bounds of array.
930 if (index > (int)array_data.size()) {
931 index = array_data.size();
932 }
933 if (index < 0) {
934 index = 0;
935 }
936
937 array_data.insert(array_data.begin() + index, object);
938
939 return *this;
940}
941
954template <typename T>
955void array<T>::append(const T &object) {
956 array_data.push_back(object);
957}
958
966template <typename T>
968 if (index < 0) {
969 index += array_data.size() + 1;
970 }
971 if ((index >= array_data.size()) || (index < 0)) {
972 return *this;
973 }
974
975 array_data.erase(array_data.begin() + index);
976
977 return *this;
978}
979
988template <typename T>
989array<T> &array<T>::remove(int index, int count) {
990 if (!count) {
991 return *this;
992 }
993
994 if (index < 0) {
995 index += array_data.size() + 1;
996 }
997
998 int start, end;
999
1000 if (count > 0) {
1001 start = index;
1002 end = index + count;
1003 } else {
1004 start = index + count + 1;
1005 end = index + 1;
1006 }
1007
1008 if ((end <= 0) || (start >= (int)array_data.size())) {
1009 return *this;
1010 }
1011 if (start < 0) {
1012 start = 0;
1013 }
1014 if (end > (int)array_data.size()) {
1015 end = array_data.size();
1016 }
1017
1018 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1019
1020 return *this;
1021}
1022
1023template <typename T>
1025 size_t bytes = 0;
1026 for (auto &item : array_data) {
1027 size_t objBytes;
1029 bytes += objBytes;
1030 }
1031 return bytes;
1032}
1033
1034template <typename T>
1036 return array_data.size();
1037}
1038
1051template <typename T>
1052T &array<T>::at(int index) {
1053 return array_data.at(index);
1054}
1055
1068template <typename T>
1069const T &array<T>::at(int index) const {
1070 return array_data.at(index);
1071}
1072
1084template <typename T>
1085array<T> &array<T>::replace(int index, int count, const T &object) {
1086 if (!count) {
1087 return *this;
1088 }
1089
1090 if (index < 0) {
1091 index += array_data.size() + 1;
1092 }
1093
1094 int start, end;
1095
1096 if (count > 0) {
1097 start = index;
1098 end = index + count;
1099 } else {
1100 start = index + count + 1;
1101 end = index + 1;
1102 }
1103
1104 if ((end <= 0) || (start >= (int)array_data.size())) {
1105 return *this;
1106 }
1107 if (start < 0) {
1108 start = 0;
1109 }
1110 if (end > (int)array_data.size()) {
1111 end = array_data.size();
1112 }
1113
1114 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1115 array_data.insert(array_data.begin() + start, object);
1116
1117 return *this;
1118}
1119
1131template <typename T>
1132array<T> &array<T>::replace(int index, int count, const array<T> &other) {
1133 if (index < 0) {
1134 index += array_data.size();
1135 }
1136
1137 int start, end;
1138
1139 if (count >= 0) {
1140 start = index;
1141 end = index + count;
1142 } else {
1143 start = index + count + 1;
1144 end = index + 1;
1145 }
1146
1147 if ((end <= 0) || (start >= (int)array_data.size())) {
1148 return *this;
1149 }
1150 if (start < 0) {
1151 start = 0;
1152 }
1153 if (end > (int)array_data.size()) {
1154 end = array_data.size();
1155 }
1156
1157 if (count) {
1158 array_data.erase(array_data.begin() + start, array_data.begin() + end);
1159 }
1160 array_data.insert(array_data.begin() + start, other.array_data.begin(), other.array_data.end());
1161
1162 return *this;
1163}
1164
1165template <typename T>
1166array<T> array<T>::subset(int index, int count) const {
1168
1169 if (!count) {
1170 return *this;
1171 }
1172
1173 if (index < 0) {
1174 index += array_data.size() + 1;
1175 }
1176
1177 int start, end;
1178
1179 if (count > 0) {
1180 start = index;
1181 end = index + count;
1182 } else {
1183 start = index + count + 1;
1184 end = index + 1;
1185 }
1186
1187 if ((end <= 0) || (start >= (int)array_data.size())) {
1188 return *this;
1189 }
1190 if (start < 0) {
1191 start = 0;
1192 }
1193 if (end > (int)array_data.size()) {
1194 end = array_data.size();
1195 }
1196
1197 if (end - start > 0) {
1198 output.array_data.reserve(end - start);
1199 }
1200 for (int i = start; i < end; i++) {
1201 output.array_data.push_back(array_data[i]);
1202 }
1203
1204 return output;
1205}
1206
1207template <typename T>
1208bool array<T>::operator()(const T &arg1, const T &arg2) const {
1209 return greater(arg1, arg2);
1210}
1211
1212template <typename T>
1213bool array<T>::isValid(int index) const {
1214 if (index < 0) {
1215 index += array_data.size();
1216 }
1217 return (index < (int)array_data.size()) && (index >= 0);
1218}
1219
1220template <typename T>
1222 auto temp = at(index1);
1225 return *this;
1226}
1227
1228template <typename T>
1229template <typename U>
1230array<U> array<T>::map(std::function<U(const T &)> lambda) const {
1232 result.increase(array_data.size());
1233
1234 for (const auto &i : array_data) {
1235 result.add(lambda(i));
1236 }
1237
1238 return result;
1239}
1240
1241template <typename T>
1242array<T> array<T>::filter(std::function<bool(const T &)> lambda) const {
1243 array result;
1244 result.increase(array_data.size()); // Increase it to the max size for performance, but it will likely be smaller than this.
1245
1246 for (const auto &i : array_data) {
1247 if (lambda(i)) {
1248 result.add(i);
1249 }
1250 }
1251
1252 return result;
1253}
1254
1255template <typename T>
1256T array<T>::reduce(const T &defaultValue, std::function<T(const T &, const T &)> lambda) const {
1257 const auto len = array_data.size();
1258 if (len == 0) {
1259 return defaultValue;
1260 }
1261
1262 auto result = array_data[0];
1263 for (int i = 1; i < len; ++i) {
1264 result = lambda(result, array_data[i]);
1265 }
1266
1267 return result;
1268}
1269
1270} // namespace core
1271} // namespace z
1272
1273#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:1213
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:380
bool operator>(const array &other) const
Array greater-than operator.
Definition array.hpp:816
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:1242
array(const array &other)
Copy constructor.
Definition array.hpp:727
virtual void shuffle() noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:437
void sort(std::function< bool(const T &, const T &)> lambda) noexcept
Sort the array based on an arbitrary function.
Definition array.hpp:400
array sorted() const noexcept
Sort the array based on default comparison operator.
Definition array.hpp:411
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:363
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:425
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:772
array(const T &arg1, const Args &...args)
List-initialized constructor.
Definition array.hpp:738
void sort() noexcept
Sort the array based on default comparison operator.
Definition array.hpp:389
bool operator<=(const array &other) const
Array less-than-or-equal operator.
Definition array.hpp:900
array & operator=(const array &other)
Array assignment operator.
Definition array.hpp:754
bool operator!=(const array &other) const
Check whether two arrays' contents are different.
Definition array.hpp:872
T & operator[](int index)
Function to get the object at the given index.
Definition array.hpp:348
size_t size() const noexcept override
Get the size of the array.
Definition array.hpp:1024
array()
Default constructor.
Definition array.hpp:149
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1035
array shuffled() const noexcept
Shuffle the elements of the array into a random order.
Definition array.hpp:452
array & insert(const T &, int)
Insert an object into the array.
Definition array.hpp:923
virtual bool operator()(const T &arg1, const T &arg2) const
Callable operator.
Definition array.hpp:1208
bool operator<(const array &other) const
Array less-than operator.
Definition array.hpp:844
array randomElements(int count) const noexcept
Get N random elements from the array.
Definition array.hpp:593
array reversed() const noexcept
Reverse the order of all elements in the array.
Definition array.hpp:479
T & at(int)
Function to get the object at the given index.
Definition array.hpp:1052
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:572
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:1085
array(const std::vector< T > &other)
Copy from std::vector.
Definition array.hpp:732
void append(const T &)
Append an object to the end of the array.
Definition array.hpp:955
array & remove(int)
Remove an object from the array.
Definition array.hpp:967
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:1256
bool operator>=(const array &other) const
Array greater-than-or-equal operator.
Definition array.hpp:886
virtual void reverse() noexcept
Reverse the order of all elements in the array.
Definition array.hpp:464
array & replace(int, int, const array< T > &)
Replace all objects in the given range with an array of objects.
Definition array.hpp:1132
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:1166
array & remove(int, int)
Remove all elements in a subset of the array.
Definition array.hpp:989
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:621
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:633
bool operator==(const array &other) const
Check whether two arrays' contents are the same.
Definition array.hpp:792
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:1230
array & swap(int index1, int index2)
Swap two elements in an array.
Definition array.hpp:1221
void clear()
Clear the data in the array.
Definition array.hpp:906
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: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:34