Start refactor, restructure basic
This commit is contained in:
497
src/basic/basic_array.h
Normal file
497
src/basic/basic_array.h
Normal file
@@ -0,0 +1,497 @@
|
||||
#pragma once
|
||||
/*
|
||||
// Iterating and removing elements
|
||||
for (int i = 0; i < array.len; i += 1) {
|
||||
auto &it = array[i];
|
||||
bool remove_item = false;
|
||||
defer {
|
||||
if (remove_item) {
|
||||
array.ordered_remove(it);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple delete
|
||||
IterRemove(arr) {
|
||||
IterRemovePrepare(arr);
|
||||
|
||||
remove_item = true;
|
||||
}
|
||||
|
||||
// Deleting backwards
|
||||
For(arr.reverse_iter()) {
|
||||
defer{ arr.unordered_remove(it); };
|
||||
}
|
||||
*/
|
||||
#define IterRemove(a) for (int i = 0; i < (a).len; i += 1)
|
||||
#define IterRemovePrepare(a) \
|
||||
auto &it = (a)[i]; \
|
||||
bool remove_item = false; \
|
||||
defer { \
|
||||
if (remove_item) { \
|
||||
Remove(&(a), it); \
|
||||
i -= 1; \
|
||||
} \
|
||||
}
|
||||
#define ForItem(it, array) for (auto &it : (array))
|
||||
#define For(array) ForItem(it, array)
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Slice {
|
||||
T *data;
|
||||
int64_t len;
|
||||
|
||||
Slice() = default;
|
||||
Slice(T *s, int64_t l) : data(s), len(l) {}
|
||||
|
||||
T &operator[](int64_t index) {
|
||||
Assert(index < len);
|
||||
return data[index];
|
||||
}
|
||||
T *begin() { return data; }
|
||||
T *end() { return data + len; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Slice<T> Copy(Allocator alo, Slice<T> array) {
|
||||
Slice<T> result = {};
|
||||
result.data = AllocArray(alo, T, array.len);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Pop(Slice<T> *arr) {
|
||||
Assert(arr->len > 0);
|
||||
return arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Contains(Slice<T> &arr, T item) {
|
||||
For(arr) if (it == item) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int64_t GetIndex(Slice<T> &arr, const T &item) {
|
||||
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
|
||||
Assert(index >= 0 && index < arr.len);
|
||||
return (int64_t)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Get(Slice<T> &arr, int64_t i, T default_value = {}) {
|
||||
T result = default_value;
|
||||
if (i >= 0 && i < arr.len) result = arr[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsLast(Slice<T> &arr, T &item) {
|
||||
bool result = arr.last() == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsFirst(Slice<T> &arr, T &item) {
|
||||
bool result = arr.first() == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetFirst(Slice<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetLast(Slice<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data + arr.len - 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Chop(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Skip(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data + len, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPostfix(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
int64_t remain_len = arr.len - len;
|
||||
Slice<T> result = {arr.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPrefix(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetSlice(Slice<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
Slice<T> result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Make arrays resize on every item
|
||||
#define ARRAY_DEBUG 0
|
||||
#if ARRAY_DEBUG
|
||||
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) IF
|
||||
#else
|
||||
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct Array {
|
||||
Allocator allocator;
|
||||
int64_t cap;
|
||||
union {
|
||||
Slice<T> slice;
|
||||
struct {
|
||||
T *data;
|
||||
int64_t len;
|
||||
};
|
||||
};
|
||||
|
||||
T &operator[](int64_t index) {
|
||||
Assert(index >= 0 && index < len);
|
||||
return data[index];
|
||||
}
|
||||
T *begin() { return data; }
|
||||
T *end() { return data + len; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T *GetFirst(Array<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetLast(Array<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data + arr.len - 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Reserve(Array<T> *arr, int64_t size) {
|
||||
if (size > arr->cap) {
|
||||
if (!arr->allocator.proc) arr->allocator = GetSystemAllocator();
|
||||
|
||||
T *new_data = AllocArray(arr->allocator, T, size);
|
||||
Assert(new_data);
|
||||
memcpy(new_data, arr->data, arr->len * sizeof(T));
|
||||
Dealloc(arr->allocator, &arr->data);
|
||||
|
||||
arr->data = new_data;
|
||||
arr->cap = size;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void TryGrowing(Array<T> *arr) {
|
||||
if (arr->len + 1 > arr->cap) {
|
||||
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
|
||||
int64_t new_size = ClampBottom(initial_size, arr->cap ARRAY_IF_DEBUG_ELSE(+1, *2));
|
||||
Reserve(arr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void TryGrowing(Array<T> *arr, int64_t item_count) {
|
||||
if (arr->len + item_count > arr->cap) {
|
||||
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
|
||||
int64_t new_size = ClampBottom(initial_size, (arr->cap + item_count) ARRAY_IF_DEBUG_ELSE(+1, *2));
|
||||
Reserve(arr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, T item) {
|
||||
TryGrowing(arr);
|
||||
arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, Array<T> &another) {
|
||||
For(another) Add(arr, it);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, T *items, int64_t item_count) {
|
||||
for (int64_t i = 0; i < item_count; i += 1) Add(arr, items[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BoundedAdd(Array<T> *arr, T item) {
|
||||
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BoundedAddError(Array<T> *arr, T item) {
|
||||
Assert(arr->len + 1 <= arr->cap);
|
||||
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Insert(Array<T> *arr, T item, int64_t index) {
|
||||
if (index == arr->len) {
|
||||
Add(arr, item);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(index < arr->len);
|
||||
Assert(index >= 0);
|
||||
TryGrowing(arr);
|
||||
int64_t right_len = arr->len - index;
|
||||
memmove(arr->data + index + 1, arr->data + index, sizeof(T) * right_len);
|
||||
arr->data[index] = item;
|
||||
arr->len += 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Array<T> Copy(Allocator alo, Array<T> array) {
|
||||
Array<T> result = {alo};
|
||||
Reserve(&result, array.cap);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Array<T> TightCopy(Allocator alo, Array<T> array) {
|
||||
Array<T> result = {alo};
|
||||
Reserve(&result, array.len);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Pop(Array<T> *arr) {
|
||||
Assert(arr->len > 0);
|
||||
return arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Contains(Array<T> &arr, T item) {
|
||||
For(arr) if (it == item) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int64_t GetIndex(Array<T> &arr, const T &item) {
|
||||
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
|
||||
Assert(index >= 0 && index < arr.len);
|
||||
return (int64_t)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveByIndex(Array<T> *arr, int64_t index) {
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
int64_t right_len = arr->len - index - 1;
|
||||
memmove(arr->data + index, arr->data + index + 1, right_len * sizeof(T));
|
||||
arr->len -= 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveManyByIndex(Array<T> *arr, int64_t index, int64_t count) {
|
||||
if (count == 0) return;
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
Assert((index + count) > 0 && (index + count) <= arr->len);
|
||||
int64_t right_len = arr->len - index - count;
|
||||
memmove(arr->data + index, arr->data + index + count, right_len * sizeof(T));
|
||||
arr->len -= count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveMany(Array<T> *arr, T &item, int64_t count) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(&item >= arr->begin() && &item < arr->end());
|
||||
int64_t index = GetIndex(*arr, item);
|
||||
RemoveManyByIndex(arr, index, count);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Remove(Array<T> *arr, T &item) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(&item >= arr->begin() && &item < arr->end());
|
||||
int64_t index = GetIndex(*arr, item);
|
||||
RemoveByIndex(arr, index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UnorderedRemove(Array<T> *arr, T &item) {
|
||||
Assert(arr->len > 0);
|
||||
Assert((&item >= arr->begin()) && (&item < arr->end()));
|
||||
item = arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UnorderedRemoveByIndex(Array<T> *arr, int64_t index) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
arr->data[index] = arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void InsertArray(Array<T> *arr, T *items, int64_t count, int64_t index) {
|
||||
if (index == arr->len) {
|
||||
Add(arr, items, count);
|
||||
return;
|
||||
}
|
||||
Assert(index < arr->len);
|
||||
|
||||
TryGrowing(arr, count);
|
||||
T *gap_begin = arr->data + index;
|
||||
T *gap_end = gap_begin + count;
|
||||
int64_t item_count = arr->len - index;
|
||||
memmove(gap_end, gap_begin, item_count * sizeof(T));
|
||||
for (int64_t i = 0; i < count; i += 1) arr->data[index + i] = items[i];
|
||||
arr->len += count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Get(Array<T> &arr, int64_t i, T default_value = {}) {
|
||||
T result = default_value;
|
||||
if (i >= 0 && i < arr.len) result = arr[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Dealloc(Array<T> *arr) {
|
||||
if (arr->data) Dealloc(arr->allocator, &arr->data);
|
||||
arr->len = arr->cap = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsLast(Array<T> &arr, T &item) {
|
||||
bool result = GetLast(arr) == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsFirst(Array<T> &arr, T &item) {
|
||||
bool result = GetFirst(arr) == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Chop(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Skip(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data + len, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPostfix(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
int64_t remain_len = arr.len - len;
|
||||
Slice<T> result = {arr.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPrefix(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetSlice(Array<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
Slice<T> result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct ReverseIter {
|
||||
T *data;
|
||||
Slice<T> *arr;
|
||||
|
||||
ReverseIter operator++(int) {
|
||||
ReverseIter ret = *this;
|
||||
data -= 1;
|
||||
return ret;
|
||||
}
|
||||
ReverseIter &operator++() {
|
||||
data -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T &operator*() { return data[0]; }
|
||||
T *operator->() { return data; }
|
||||
|
||||
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
|
||||
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
|
||||
|
||||
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
|
||||
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ReverseIter<T> IterateInReverse(Array<T> *arr) {
|
||||
return {arr->end() - 1, &arr->slice};
|
||||
}
|
||||
template <class T>
|
||||
ReverseIter<T> IterateInReverse(Slice<T> *slice) {
|
||||
return {slice->end() - 1, slice};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user