Start refactor, restructure basic

This commit is contained in:
Krzosa Karol
2025-11-27 09:00:10 +01:00
parent 38b9b7df10
commit 781c2dc53c
30 changed files with 5716 additions and 3490 deletions

497
src/basic/basic_array.h Normal file
View 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};
}