#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 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 Slice Copy(Allocator alo, Slice array) { Slice result = {}; result.data = AllocArray(alo, T, array.len); memcpy(result.data, array.data, sizeof(T) * array.len); result.len = array.len; return result; } template T Pop(Slice *arr) { Assert(arr->len > 0); return arr->data[--arr->len]; } template bool Contains(Slice &arr, T item) { For(arr) if (it == item) return true; return false; } template int64_t GetIndex(Slice &arr, const T &item) { ptrdiff_t index = (ptrdiff_t)(&item - arr.data); Assert(index >= 0 && index < arr.len); return (int64_t)index; } template T Get(Slice &arr, int64_t i, T default_value = {}) { T result = default_value; if (i >= 0 && i < arr.len) result = arr[i]; return result; } template bool IsLast(Slice &arr, T &item) { bool result = arr.last() == &item; return result; } template bool IsFirst(Slice &arr, T &item) { bool result = arr.first() == &item; return result; } template T *GetFirst(Slice &arr) { Assert(arr.len > 0); return arr.data; } template T *GetLast(Slice &arr) { Assert(arr.len > 0); return arr.data + arr.len - 1; } template Slice Chop(Slice &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data, arr.len - len}; return result; } template Slice Skip(Slice &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data + len, arr.len - len}; return result; } template Slice GetPostfix(Slice &arr, int64_t len) { len = ClampTop(len, arr.len); int64_t remain_len = arr.len - len; Slice result = {arr.data + remain_len, len}; return result; } template Slice GetPrefix(Slice &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data, len}; return result; } template Slice GetSlice(Slice &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 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 BUILD_SLOW #if ARRAY_DEBUG #define ARRAY_IF_DEBUG_ELSE(IF, ELSE) IF #else #define ARRAY_IF_DEBUG_ELSE(IF, ELSE) ELSE #endif template struct Array { Allocator allocator; int64_t cap; union { Slice 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 T *GetFirst(Array &arr) { Assert(arr.len > 0); return arr.data; } template T *GetLast(Array &arr) { Assert(arr.len > 0); return arr.data + arr.len - 1; } template void Reserve(Array *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 void TryGrowing(Array *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 void TryGrowing(Array *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 void Add(Array *arr, T item) { TryGrowing(arr); arr->data[arr->len++] = item; } template void Add(Array *arr, Array &another) { For(another) Add(arr, it); } template void Add(Array *arr, T *items, int64_t item_count) { for (int64_t i = 0; i < item_count; i += 1) Add(arr, items[i]); } template void BoundedAdd(Array *arr, T item) { if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item; } template void BoundedAddError(Array *arr, T item) { Assert(arr->len + 1 <= arr->cap); if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item; } template void Insert(Array *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 Array Copy(Allocator alo, Array array) { Array result = {alo}; Reserve(&result, array.cap); memcpy(result.data, array.data, sizeof(T) * array.len); result.len = array.len; return result; } template Array TightCopy(Allocator alo, Array array) { Array result = {alo}; Reserve(&result, array.len); memcpy(result.data, array.data, sizeof(T) * array.len); result.len = array.len; return result; } template T Pop(Array *arr) { Assert(arr->len > 0); return arr->data[--arr->len]; } template bool Contains(Array &arr, T item) { For(arr) if (it == item) return true; return false; } template int64_t FindValueIndex(Array &arr, T item) { for (int64_t i = 0; i < arr.len; i += 1) { if (arr.data[i] == item) { return i; } } return -1; } template int64_t GetIndex(Array &arr, const T &item) { ptrdiff_t index = (ptrdiff_t)(&item - arr.data); Assert(index >= 0 && index < arr.len); return (int64_t)index; } template void RemoveByIndex(Array *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 void RemoveManyByIndex(Array *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 void RemoveMany(Array *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 void Remove(Array *arr, T &item) { Assert(arr->len > 0); Assert(&item >= arr->begin() && &item < arr->end()); int64_t index = GetIndex(*arr, item); RemoveByIndex(arr, index); } template void UnorderedRemove(Array *arr, T &item) { Assert(arr->len > 0); Assert((&item >= arr->begin()) && (&item < arr->end())); item = arr->data[--arr->len]; } template void UnorderedRemoveByIndex(Array *arr, int64_t index) { Assert(arr->len > 0); Assert(index >= 0 && index < arr->len); arr->data[index] = arr->data[--arr->len]; } template void InsertArray(Array *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 T Get(Array &arr, int64_t i, T default_value = {}) { T result = default_value; if (i >= 0 && i < arr.len) result = arr[i]; return result; } template void Dealloc(Array *arr) { if (arr->data) { Dealloc(arr->allocator, arr->data); arr->data = NULL; } arr->len = arr->cap = 0; } template bool IsLast(Array &arr, T &item) { bool result = GetLast(arr) == &item; return result; } template bool IsFirst(Array &arr, T &item) { bool result = GetFirst(arr) == &item; return result; } template Slice Chop(Array &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data, arr.len - len}; return result; } template Slice Skip(Array &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data + len, arr.len - len}; return result; } template Slice GetPostfix(Array &arr, int64_t len) { len = ClampTop(len, arr.len); int64_t remain_len = arr.len - len; Slice result = {arr.data + remain_len, len}; return result; } template Slice GetPrefix(Array &arr, int64_t len) { len = ClampTop(len, arr.len); Slice result = {arr.data, len}; return result; } template Slice GetSlice(Array &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 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 struct ReverseIter { T *data; Slice *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 ReverseIter IterateInReverse(Array *arr) { return {arr->end() - 1, &arr->slice}; } template ReverseIter IterateInReverse(Slice *slice) { return {slice->end() - 1, slice}; }