Array tests, allocator design changes

This commit is contained in:
Krzosa Karol
2023-12-31 16:07:58 +01:00
parent f14d5462b0
commit b3f5ce3772
11 changed files with 485 additions and 365 deletions

87
arena.c
View File

@@ -22,6 +22,7 @@ MA_API void MA_MemoryCopy(void *dst, void *src, size_t size) {
#include <stdlib.h>
#define MA_CMalloc(x) malloc(x)
#define MA_CFree(x) free(x)
#define MA_CRealloc(p, size) realloc(p, size)
#endif
#ifndef MA_StaticFunc
@@ -94,24 +95,6 @@ MA_StaticFunc size_t MA__AlignLen(MA_Arena *a) {
return aligned;
}
MA_API void *MA__BeginPackedArray(MA_Arena *arena, size_t element_size) {
MA_ASSERT(arena->memory.data);
arena->len = MA__AlignLen(arena);
arena->saved_alignment = arena->alignment;
arena->alignment = 0;
arena->packed_array_begin = arena->len;
arena->packed_array_element_size = element_size;
void *result = arena->memory.data + arena->len;
return result;
}
MA_API int MA_EndPackedArray(MA_Arena *arena) {
arena->alignment = arena->saved_alignment;
size_t different = (arena->len - arena->packed_array_begin);
int result = (int)((arena->len - arena->packed_array_begin) / arena->packed_array_element_size);
return result;
}
MA_API void MA_SetAlignment(MA_Arena *arena, int alignment) {
arena->alignment = alignment;
}
@@ -154,7 +137,6 @@ MA_API void *MA_PushSize(MA_Arena *arena, size_t size) {
MA_API void MA_InitEx(MA_Arena *a, size_t reserve) {
a->memory = MV_Reserve(reserve);
a->alignment = MA_DEFAULT_ALIGNMENT;
MA_INIT_HOOK(a);
}
MA_API void MA_Init(MA_Arena *a) {
@@ -171,7 +153,6 @@ MA_API MA_Arena *MA_Bootstrap(void) {
MA_Arena bootstrap_arena = {0};
MA_Arena *arena = MA_PushStruct(&bootstrap_arena, MA_Arena);
*arena = bootstrap_arena;
arena->allocator.obj = arena;
return arena;
}
@@ -180,7 +161,6 @@ MA_API void MA_InitFromBuffer(MA_Arena *arena, void *buffer, size_t size) {
arena->memory.commit = size;
arena->memory.reserve = size;
arena->alignment = MA_DEFAULT_ALIGNMENT;
MA_INIT_HOOK(arena);
}
MA_API MA_Arena MA_MakeFromBuffer(void *buffer, size_t size) {
@@ -190,6 +170,12 @@ MA_API MA_Arena MA_MakeFromBuffer(void *buffer, size_t size) {
return arena;
}
MA_API MA_Arena MA_Create() {
MA_Arena arena = {0};
MA_Init(&arena);
return arena;
}
MA_API char *MA_PushStringCopy(MA_Arena *arena, char *p, size_t size) {
char *copy_buffer = (char *)MA_PushSizeNonZeroed(arena, size + 1);
MA_MemoryCopy(copy_buffer, p, size);
@@ -233,12 +219,12 @@ MA_API void MA_Load(MA_Checkpoint checkpoint) {
}
MA_API void *M_AllocNonZeroed(M_Allocator allocator, size_t size) {
void *p = allocator.p(allocator.obj, M_AllocatorOp_Allocate, NULL, size);
void *p = allocator.p(allocator.obj, M_AllocatorOp_Allocate, NULL, size, 0);
return p;
}
MA_API void *M_Alloc(M_Allocator allocator, size_t size) {
void *p = allocator.p(allocator.obj, M_AllocatorOp_Allocate, NULL, size);
void *p = allocator.p(allocator.obj, M_AllocatorOp_Allocate, NULL, size, 0);
MA_MemoryZero(p, size);
return p;
}
@@ -250,10 +236,16 @@ MA_API void *M_AllocCopy(M_Allocator allocator, void *p, size_t size) {
}
MA_API void M_Dealloc(M_Allocator allocator, void *p) {
allocator.p(allocator.obj, M_AllocatorOp_Deallocate, p, 0);
allocator.p(allocator.obj, M_AllocatorOp_Deallocate, p, 0, 0);
}
MA_StaticFunc void *M_ClibAllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size) {
MA_API void *M_ReallocNonZeroed(M_Allocator allocator, void *p, size_t size, size_t old_size) {
void *result = allocator.p(allocator.obj, M_AllocatorOp_Reallocate, p, size, old_size);
// @todo: add old_size? because we can't zero
return result;
}
MA_StaticFunc void *M_ClibAllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size) {
if (kind == M_AllocatorOp_Allocate) {
return MA_CMalloc(size);
}
@@ -263,16 +255,26 @@ MA_StaticFunc void *M_ClibAllocatorProc(void *allocator, M_AllocatorOp kind, voi
return NULL;
}
if (kind == M_AllocatorOp_Reallocate) {
return MA_CRealloc(p, size);
}
MA_ASSERT("MA_Arena invalid codepath");
return NULL;
}
MA_API void *MA_AllocatorProc(M_Allocator allocator, M_AllocatorOp kind, void *p, size_t size) {
MA_API void *MA_AllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size) {
if (kind == M_AllocatorOp_Allocate) {
return MA_PushSizeNonZeroed((MA_Arena *)allocator.obj, size);
return MA_PushSizeNonZeroed((MA_Arena *)allocator, size);
}
if (kind == M_AllocatorOp_Deallocate) {
else if (kind == M_AllocatorOp_Reallocate) {
void *new_p = MA_PushSizeNonZeroed((MA_Arena *)allocator, size);
MA_MemoryCopy(new_p, p, old_size);
return new_p;
}
else if (kind == M_AllocatorOp_Deallocate) {
return NULL;
}
@@ -280,6 +282,35 @@ MA_API void *MA_AllocatorProc(M_Allocator allocator, M_AllocatorOp kind, void *p
return NULL;
}
MA_API void *MA_ExclusiveAllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size) {
MA_Arena *arena = (MA_Arena *)allocator;
if (kind == M_AllocatorOp_Reallocate) {
if (size > arena->len) {
size_t size_to_push = size - arena->len;
MA_PushSizeNonZeroed(arena, size_to_push);
return arena->memory.data;
}
}
if (kind == M_AllocatorOp_Deallocate) {
MA_DeallocateArena(arena);
return NULL;
}
MA_ASSERT("MA_Arena invalid codepath");
return NULL;
}
MA_API M_Allocator MA_GetExclusiveAllocator(MA_Arena *arena) {
M_Allocator allocator = {arena, MA_ExclusiveAllocatorProc};
return allocator;
}
MA_API M_Allocator MA_GetAllocator(MA_Arena *arena) {
M_Allocator allocator = {arena, MA_AllocatorProc};
return allocator;
}
MA_API M_Allocator M_GetSystemAllocator(void) {
M_Allocator allocator;
allocator.obj = 0;

47
arena.h
View File

@@ -26,24 +26,10 @@ typedef struct M_Allocator M_Allocator;
#define MA_COMMIT_ADD_SIZE MA_MIB(4)
#endif
#ifndef MA_INHERIT_HOOK
#define MA_INHERIT_HOOK
#endif
#ifndef MA_C_INHERIT_HOOK
#define MA_C_INHERIT_HOOK M_Allocator allocator;
#endif
#ifndef MA_ZERO_IS_INITIALIZATION
#define MA_ZERO_IS_INITIALIZATION 1
#endif
#ifndef MA_INIT_HOOK
#define MA_INIT_HOOK(arena) \
arena->allocator.obj = (void *)arena; \
arena->allocator.p = (M_AllocatorProc *)MA_AllocatorProc;
#endif
#ifndef MA_API
#ifdef __cplusplus
#define MA_API extern "C"
@@ -72,12 +58,16 @@ typedef enum M_AllocatorOp {
M_AllocatorOp_Invalid,
M_AllocatorOp_Allocate,
M_AllocatorOp_Deallocate,
M_AllocatorOp_Reallocate,
} M_AllocatorOp;
typedef void *M_AllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size);
typedef void *M_AllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size);
MA_API void *MA_AllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size);
MA_API void *MA_ExclusiveAllocatorProc(void *allocator, M_AllocatorOp kind, void *p, size_t size, size_t old_size);
struct M_Allocator {
void *obj;
void *(*p)(void *allocator, M_AllocatorOp kind, void *p, size_t size);
M_AllocatorProc *p;
};
struct MV_Memory {
@@ -86,15 +76,14 @@ struct MV_Memory {
uint8_t *data;
};
struct MA_Arena MA_INHERIT_HOOK {
MA_C_INHERIT_HOOK
struct MA_Arena {
MV_Memory memory;
int alignment;
int saved_alignment;
size_t len;
size_t packed_array_element_size;
size_t packed_array_begin;
#ifdef __cplusplus
operator M_Allocator() { return {this, MA_AllocatorProc}; }
#endif
};
struct MA_Checkpoint {
@@ -107,7 +96,6 @@ struct MA_Checkpoint {
#define MA_PushStruct(a, T) (T *)MA_PushSize(a, sizeof(T))
#define MA_PushArray(a, T, c) (T *)MA_PushSize(a, sizeof(T) * (c))
#define MA_PushStructCopy(a, T, p) (T *)MA_PushCopy(a, (p), sizeof(T))
#define MA_BeginPackedArray(arena, T) (T *)MA__BeginPackedArray(arena, sizeof(T))
#define MA_CheckpointScope(name, InArena) for (MA_Checkpoint name = MA_Save(InArena); name.arena; (MA_Load(name), name.arena = 0))
#define M_AllocStruct(a, T) (T *)M_Alloc((a), sizeof(T))
@@ -130,18 +118,20 @@ MA_API size_t MA_GetAlignOffset(size_t size, size_t align);
MA_API size_t MA_AlignUp(size_t size, size_t align);
MA_API size_t MA_AlignDown(size_t size, size_t align);
MA_API void MA_DeallocateStub(MA_Arena *arena, void *p);
MA_API void MA_InitEx(MA_Arena *a, size_t reserve);
MA_API void MA_Init(MA_Arena *a);
MA_API MA_Arena MA_Create();
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos);
MA_API void * MA_PopSize(MA_Arena *arena, size_t size);
MA_API void MA_DeallocateArena(MA_Arena *arena);
MA_API void MA_Reset(MA_Arena *arena);
MA_API void * MA__BeginPackedArray(MA_Arena *arena, size_t element_size);
MA_API int MA_EndPackedArray(MA_Arena *arena);
MA_API void MA_SetAlignment(MA_Arena *arena, int alignment);
MA_API uint8_t * MA_GetTop(MA_Arena *a);
MA_API void * MA_PushSizeNonZeroed(MA_Arena *a, size_t size);
MA_API void * MA_PushSize(MA_Arena *arena, size_t size);
MA_API void MA_InitEx(MA_Arena *a, size_t reserve);
MA_API void MA_Init(MA_Arena *a);
MA_API void MA_MakeSureInitialized(MA_Arena *a);
MA_API MA_Arena * MA_Bootstrap(void);
MA_API void MA_InitFromBuffer(MA_Arena *arena, void *buffer, size_t size);
@@ -155,7 +145,6 @@ MA_API void MA_Load(MA_Checkpoint checkpoint);
MA_API MA_Checkpoint MA_GetScratchEx(MA_Arena **conflicts, int conflict_count);
MA_API MA_Checkpoint MA_GetScratch(void);
MA_API MA_Checkpoint MA_GetScratch1(MA_Arena *conflict);
MA_API void * MA_AllocatorProc(M_Allocator allocator, M_AllocatorOp kind, void *p, size_t size);
MA_API MV_Memory MV_Reserve(size_t size);
MA_API bool MV_Commit(MV_Memory *m, size_t commit);
@@ -165,8 +154,11 @@ MA_API bool MV_DecommitPos(MV_Memory *m, size_t pos);
MA_API void * M_AllocNonZeroed(M_Allocator allocator, size_t size);
MA_API void * M_Alloc(M_Allocator allocator, size_t size);
MA_API void * M_AllocCopy(M_Allocator allocator, void *p, size_t size);
MA_API void * M_ReallocNonZeroed(M_Allocator allocator, void *p, size_t size, size_t old_size);
MA_API void M_Dealloc(M_Allocator allocator, void *p);
MA_API M_Allocator M_GetSystemAllocator(void);
MA_API M_Allocator MA_GetExclusiveAllocator(MA_Arena *arena);
MA_API M_Allocator MA_GetAllocator(MA_Arena *arena);
// clang-format on
#ifndef MA_DISABLE_SCRATCH
@@ -180,6 +172,7 @@ struct MA_Scratch {
MA_Scratch() { this->checkpoint = MA_GetScratch(); }
~MA_Scratch() { MA_Load(checkpoint); }
operator MA_Arena *() { return checkpoint.arena; }
operator M_Allocator() { return MA_GetAllocator(checkpoint.arena); }
private: // @Note: Disable copy constructors, cause its error prone
MA_Scratch(MA_Scratch &arena);

102
array.hpp
View File

@@ -1,20 +1,8 @@
#pragma once
#ifndef ARRAY_PRIVATE_FUNCTION
#if defined(__GNUC__) || defined(__clang__)
#define ARRAY_PRIVATE_FUNCTION __attribute__((unused)) static
#else
#define ARRAY_PRIVATE_FUNCTION static
#endif
#endif
#ifndef ARRAY_ALLOCATE
#include <stdlib.h>
#define ARRAY_ALLOCATE(allocator, size) malloc(size)
#endif
#ifndef ARRAY_DEALLOCATE
#ifndef ARRAY_REALLOCATE
#include <stdlib.h>
#define ARRAY_REALLOCATE(allocator, p, size, old_size) realloc(p, size)
#define ARRAY_DEALLOCATE(allocator, p) free(p)
#endif
@@ -28,44 +16,45 @@
#define ARRAY_MemoryMove(dst, src, size) memmove(dst, src, size)
#endif
#ifndef ARRAY_SET_DEFAULT_ALLOCATOR
#define ARRAY_SET_DEFAULT_ALLOCATOR
#ifndef ARRAY_Allocator
#define ARRAY_Allocator void *
#endif
// Example:
// #define ARRAY_SET_DEFAULT_ALLOCATOR if (!allocator) allocator = global_heap;
#ifndef ARRAY_SET_DEFAULT_ALLOCATOR
#define ARRAY_SET_DEFAULT_ALLOCATOR
#endif
// Iterating and removing elements
//
// ForArrayRemovable(array) {
// ForArrayRemovablePrepare(array);
// if (it == 4) ForArrayRemovableDeclare();
// }
//
#ifdef DEFER_HEADER
#define ForArrayRemovable(a) for (int __i = 0; __i < (a).len; __i += 1)
#define ForArrayRemovablePrepare(a) \
auto &it = (a)[__i]; \
bool remove_it = false; \
defer { \
if (remove_it) { \
(a).ordered_remove(it); \
__i -= 1; \
} \
}
#define ForArrayRemovableDeclare() (remove_it = true)
#define ForArrayRemovable(a) for (int __i = 0; __i < (a).len; __i += 1)
#define ForArrayRemovablePrepare(a) \
auto &it = (a)[__i]; \
bool remove_it = false; \
defer { \
if (remove_it) { \
(a).ordered_remove(it); \
__i -= 1; \
} \
}
#define ForArrayRemovableDeclare() (remove_it = true)
#endif
#if !defined(ARRAY_ALLOCATOR_CODE)
#if defined(ARRAY_ALLOCATOR_TYPE)
#define ARRAY_ALLOCATOR_CODE(x) x
#define ARRAY_ALLOCATOR_PARAM ARRAY_ALLOCATOR_TYPE allocator,
#else
#define ARRAY_ALLOCATOR_CODE(x)
#define ARRAY_ALLOCATOR_PARAM
#endif
#endif
#if !defined(For)
#define For2(array,it) for(auto &it : (array))
#define For(array) For2(array,it)
#ifndef For
#define For2(it, array) for(auto &it : (array))
#define For(array) For2(it, array)
#endif
template <class T>
struct Array {
ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE allocator;)
ARRAY_Allocator allocator;
T *data;
int cap, len;
@@ -81,8 +70,8 @@ struct Array {
bool is_first(T &item) { return &item == first(); }
bool is_last(T &item) { return &item == last(); }
bool contains(T *item) {
bool result = item >= data && item < data + len;
bool contains(T &item) {
bool result = &item >= data && &item < data + len;
return result;
}
@@ -154,24 +143,19 @@ struct Array {
if (size > cap) {
ARRAY_SET_DEFAULT_ALLOCATOR;
void *p = ARRAY_ALLOCATE(allocator, size * sizeof(T));
void *p = ARRAY_REALLOCATE(allocator, data, size * sizeof(T), cap * sizeof(T));
ARRAY_ASSERT(p);
if (data) {
ARRAY_MemoryMove(p, data, len * sizeof(T));
ARRAY_DEALLOCATE(allocator, data);
}
data = (T *)p;
cap = size;
}
}
void init(ARRAY_ALLOCATOR_PARAM int size) {
void init(ARRAY_Allocator allocator, int size) {
len = 0;
cap = 0;
data = 0;
ARRAY_ALLOCATOR_CODE(this->allocator = allocator;)
this->allocator = allocator;
reserve(size);
}
@@ -190,6 +174,11 @@ struct Array {
item = data[--len];
}
void unordered_remove_index(int index) {
ARRAY_ASSERT(index >= 0 && index < len);
data[index] = data[--len];
}
int get_index(const T &item) {
ptrdiff_t index = (ptrdiff_t)(&item - data);
ARRAY_ASSERT(index >= 0 && index < len);
@@ -201,8 +190,11 @@ struct Array {
ARRAY_ASSERT(len > 0);
ARRAY_ASSERT(&item >= begin() && &item < end());
int index = get_index(item);
ARRAY_ASSERT(index >= 0 && index < len);
ordered_remove_index(index);
}
void ordered_remove_index(int index) {
ARRAY_ASSERT(index >= 0 && index < len);
int right_len = len - index - 1;
ARRAY_MemoryMove(data + index, data + index + 1, right_len * sizeof(T));
len -= 1;
@@ -230,9 +222,9 @@ struct Array {
len = cap = 0;
}
Array<T> exact_copy(ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE *allocator)) {
Array<T> exact_copy(ARRAY_Allocator allocator) {
Array result = {};
ARRAY_ALLOCATOR_CODE(result.allocator = allocator;)
result.allocator = allocator;
result.reserve(cap);
ARRAY_MemoryMove(result.data, data, sizeof(T) * len);
@@ -240,7 +232,7 @@ struct Array {
return result;
}
Array<T> tight_copy(ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE *allocator)) {
Array<T> tight_copy(ARRAY_Allocator allocator) {
Array result = {};
ARRAY_ALLOCATOR_CODE(result.allocator = allocator;)
result.reserve(len);

View File

@@ -14,13 +14,14 @@ set RELEASE_LINE=%RELEASE% %WRN% %COMMON% -link -incremental:no %LINK_RELEASE%
mkdir build
cd build
cl.exe -Fe:test_arena.exe ../test/test_arena.cpp %DEBUG_LINE%
cl.exe -Fe:test_array.exe ../test/test_array.cpp %DEBUG_LINE%
if %errorlevel% neq 0 exit /b %errorlevel%
test_arena.exe
test_array.exe
if %errorlevel% neq 0 exit /b %errorlevel%
cl.exe -Fe:cpp_debug.exe ../test/main.cpp %DEBUG_LINE%
if %errorlevel% neq 0 exit /b %errorlevel%
cl.exe -Fe:cpp_release.exe ../test/main.cpp %RELEASE_LINE%
if %errorlevel% neq 0 exit /b %errorlevel%
cl.exe -Fe:c_debug.exe ../test/main.c %DEBUG_LINE%

View File

@@ -3,6 +3,6 @@ set -e
mkdir build
cd build
clang -o test_arena ../test/test_arena.cpp -fno-exceptions -fno-rtti -Wno-writable-strings
./test_arena
clang -o test_array ../test/test_array.cpp -fno-exceptions -fno-rtti -Wno-writable-strings
./test_array
cd ..

8
core.c
View File

@@ -2,29 +2,21 @@
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#define IO_VSNPRINTF stbsp_vsnprintf
#define IO_SNPRINTF stbsp_snprintf
#include "io.c"
#define MA_ASSERT(x) IO_Assert(x)
#include "arena.c"
#define RE_ASSERT(x) IO_Assert(x)
#include "regex.c"
#include "unicode.c"
#define S8_VSNPRINTF stbsp_vsnprintf
#define S8_ALLOCATE(allocator, size) MA_PushSize(allocator, size)
#define S8_ASSERT(x) IO_Assert(x)
#define S8_MemoryCopy MA_MemoryCopy
#include "string.c"
#define MU_ASSERT IO_Assert
#include "multimedia.h"
#include "hash.c"
#include "load_library.c"
#include "filesystem.c"

2
core.h
View File

@@ -21,6 +21,8 @@
#include "table.hpp"
#define ARRAY_ASSERT IO_Assert
#define ARRAY_ALLOCATOR_TYPE M_Allocator
#define ARRAY_REALLOCATE(allocator, p, size, old_size) M_ReallocNonZeroed(allocator, p, size, old_size)
#define ARRAY_DEALLOCATE(allocator, p) M_Dealloc(allocator, p)
#define ARRAY_SET_DEFAULT_ALLOCATOR \
if (!allocator.p) allocator = M_GetSystemAllocator();
#include "array.hpp"

View File

@@ -1,4 +1,5 @@
#pragma once
#define DEFER_HEADER
template <typename T>
struct DEFER_ExitScope {

View File

@@ -73,11 +73,11 @@ struct Table {
Value value;
};
size_t len, cap;
Entry *values;
#ifdef TABLE_ALLOCATOR_TYPE
TABLE_ALLOCATOR_TYPE allocator;
#endif
size_t len, cap;
Entry *values;
inline bool is_empty(Entry *entry) { return entry->hash == 0; }
inline bool is_occupied(Entry *entry) { return entry->hash != 0; }

View File

@@ -1,14 +0,0 @@
#include "../io.c"
#define MA_ASSERT(x) IO_Assert(x)
#include "../arena.c"
int main() {
MA_Scratch scratch;
int *thing = MA_PushStruct(scratch, int);
*thing = 10;
MA_Arena *arena = MA_Bootstrap();
float *thingf = MA_PushStruct(arena, float);
*thingf = 10.0f;
}

122
test/test_array.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include "../io.c"
#define MA_ASSERT(x) IO_Assert(x)
#include "../arena.c"
#include "../defer.hpp"
#define ARRAY_REALLOCATE(allocator, p, size, old_size) M_ReallocNonZeroed(allocator, p, size, old_size)
#define ARRAY_DEALLOCATE(allocator, p) M_Dealloc(allocator, p)
#define ARRAY_Allocator M_Allocator
#define ARRAY_SET_DEFAULT_ALLOCATOR \
if (!allocator.p) allocator = M_GetSystemAllocator();
#include "../array.hpp"
void TestExclusiveArenaBackedArray() {
MA_Scratch scratch;
MA_Arena ex = MA_Create();
Array<int> array = {MA_GetExclusiveAllocator(&ex)};
Array<int *> ptrs = {scratch};
array.reserve(16);
ptrs.reserve(16);
void *initial_p0 = array.data;
void *initial_p1 = ptrs.data;
for (int i = 0; i < 1000; i += 1) {
array.add(i);
ptrs.add(&array[i]);
}
for (int i = 0; i < 1000; i += 1) {
IO_Assert(array[i] == i);
IO_Assert(&array[i] == ptrs[i]);
}
int i = 0;
For(array) {
IO_Assert(it == i++);
}
IO_Assert(initial_p0 == array.data);
IO_Assert(initial_p1 != ptrs.data);
array.dealloc();
}
Array<int> GenArray() {
Array<int> result = {M_GetSystemAllocator()};
for (int i = 0; i < 100; i += 1) result.add(i);
return result;
}
void TestRemoveForLoop() {
Array<int> array = GenArray();
IO_Assert(array.len == 100);
IO_Assert(array[4] == 4);
ForArrayRemovable(array) {
ForArrayRemovablePrepare(array);
if (it == 4) ForArrayRemovableDeclare();
}
IO_Assert(array[4] != 4);
IO_Assert(array[4] == 5);
IO_Assert(array[5] == 6);
IO_Assert(array[3] == 3);
IO_Assert(array.len == 99);
}
void TestBasic() {
Array<int> array = GenArray();
array.unordered_remove_index(40);
IO_Assert(array.len == 99);
IO_Assert(array[40] != 40);
IO_Assert(array[40] == 99);
array.ordered_remove_index(35);
IO_Assert(array.len == 98);
IO_Assert(array[35] == 36);
array.ordered_remove_index(array[34]);
IO_Assert(array.len == 97);
IO_Assert(array[34] == 36);
array.unordered_remove(array[30]);
IO_Assert(array.len == 96);
IO_Assert(array[30] != 30);
IO_Assert(array[30] == 98);
array.insert(101, 20);
IO_Assert(array[20] == 101);
IO_Assert(array[21] == 20);
IO_Assert(array.len == 97);
IO_Assert(array.contains(array[20]));
IO_Assert(array.contains(array[96]));
IO_Assert(array.contains(array[0]));
IO_Assert(!array.contains(array.data[97]));
IO_Assert(array.is_first(array[0]));
IO_Assert(!array.is_first(array[1]));
IO_Assert(!array.is_last(array[0]));
IO_Assert(array.is_last(array[array.len - 1]));
array.reset();
IO_Assert(array.len == 0);
array.dealloc();
}
void TestReverseLoop() {
Array<int> array = GenArray();
int i = 99;
For(array.reverse()) {
assert(it == i--);
}
array.dealloc();
}
int main() {
TestExclusiveArenaBackedArray();
TestRemoveForLoop();
TestBasic();
TestReverseLoop();
return 0;
}