From db2fe5f45df7d5d85f02765ec0d3772940122277 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 15 May 2020 12:42:48 -0500 Subject: [PATCH] Added custom allocators (heap and nofree allocators) #8 #9 --- bh.h | 422 +++++++++++++++++++++++++++++++++++++++++++++++++----- onyx | Bin 43368 -> 50520 bytes onyx.c | 8 +- onyxlex.c | 4 +- onyxlex.h | 2 +- 5 files changed, 397 insertions(+), 39 deletions(-) diff --git a/bh.h b/bh.h index 2af69298..54a2f382 100644 --- a/bh.h +++ b/bh.h @@ -28,6 +28,14 @@ typedef unsigned long isize; typedef i32 b32; typedef void* ptr; + + + + + + + + //------------------------------------------------------------------------------------- // Better debug functions //------------------------------------------------------------------------------------- @@ -45,6 +53,12 @@ void* bh__debug_malloc(size_t size, const char* file, u64 line) { return p; } +void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line) { + void* p = aligned_alloc(size, alignment); + printf("[DEBUG] %p = aligned_alloc(%ld, %ld) at %s:%ld\n", p, alignment, size, file, line); + return p; +} + void bh__debug_free(void* ptr, const char* file, u64 line) { printf("[DEBUG] free(%p) at %s:%ld\n", ptr, file, line); free(ptr); @@ -58,12 +72,23 @@ void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line) { #endif -#define malloc(size) (bh__debug_malloc(size, __FILE__, __LINE__)) -#define free(ptr) (bh__debug_free(ptr, __FILE__, __LINE__)) -#define realloc(ptr, size) (bh__debug_realloc(ptr, size, __FILE__, __LINE__)) +#define malloc(size) (bh__debug_malloc(size, __FILE__, __LINE__)) +#define aligned_alloc(size, alignment) (bh__debug_aligned_alloc(size, alignment, __FILE__, __LINE__)) +#define free(ptr) (bh__debug_free(ptr, __FILE__, __LINE__)) +#define realloc(ptr, size) (bh__debug_realloc(ptr, size, __FILE__, __LINE__)) #endif + + + + + + + + + + //------------------------------------------------------------------------------------- // Better character functions //------------------------------------------------------------------------------------- @@ -75,6 +100,12 @@ b32 char_in_range(const char lo, const char hi, const char a); char charset_contains(const char* charset, char ch); i64 chars_match(char* ptr1, char* ptr2); + + + + + + //------------------------------------------------------------------------------------- // Better math functions //------------------------------------------------------------------------------------- @@ -83,6 +114,91 @@ i64 chars_match(char* ptr1, char* ptr2); #define bh_clamp(v, a, b) (bh_min((b), bh_max((a), (v)))) #define bh_abs(x) ((x) < 0 ? -(x) : (x)) +#define bh_pointer_add(ptr, amm) ((void *)((u8 *) ptr + amm)) + + + + + + + +//------------------------------------------------------------------------------------- +// Custom allocators +//------------------------------------------------------------------------------------- + +typedef enum bh_allocator_actions { + bh_allocator_action_alloc, + bh_allocator_action_free, + bh_allocator_action_resize, +} bh_allocator_actions; + +#define BH_ALLOCATOR_PROC(name) \ +ptr name(ptr data, bh_allocator_actions action, \ + isize size, isize alignment, \ + void* prev_memory, \ + u64 flags) + +typedef BH_ALLOCATOR_PROC(bh__allocator_proc); // NOTE: so bh__allocator_proc can be used instead of that type + +typedef struct bh_allocator { + bh__allocator_proc* proc; // Procedure that can handle bh_allocator_actions + ptr data; // Pointer to the other data for the allocator +} bh_allocator; + +typedef enum bh_allocator_flags { + bh_allocator_flag_clear = 1 // Sets all memory to be 0 +} bh_allocator_flags; + +ptr bh_alloc(bh_allocator a, isize size); +ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment); +ptr bh_resize(bh_allocator a, ptr data, isize new_size); +ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment); +void bh_free(bh_allocator a, ptr data); + +#define bh_alloc_item(allocator_, T) (T *) bh_alloc(allocator_, sizeof(T)) +#define bh_alloc_araray(allocator_, T, n) (T *) bh_alloc(allocator_, sizeof(T) * (n)) + +// NOTE: This should get optimized out since alignment should be a power of two +#define bh__align(x, alignment) ((((x) / alignment) + 1) * alignment) + + + + +// HEAP ALLOCATOR +// Essentially a wrapper for malloc, free and realloc +bh_allocator bh_heap_allocator(void); +BH_ALLOCATOR_PROC(bh_heap_allocator_proc); + + + + + +// NOFREE ALLOCATOR + +typedef struct bh_alloc_nofree { + ptr memory; + ptr next_allocation; + isize size, total_size; // in bytes +} bh_alloc_nofree; + +BH_ALLOCATOR_PROC(bh_alloc_nofree_allocator_proc); +void bh_alloc_nofree_init(bh_alloc_nofree* alloc, isize total_size); +void bh_alloc_nofree_free(bh_alloc_nofree* alloc); +bh_allocator bh_alloc_nofree_allocator(bh_alloc_nofree* alloc); + + + + + + + + + + + + + + //------------------------------------------------------------------------------------- // Better strings //------------------------------------------------------------------------------------- @@ -139,6 +255,14 @@ void bh_string_print(bh_string* str); #endif + + + + + + + + //------------------------------------------------------------------------------------- // Better files //------------------------------------------------------------------------------------- @@ -178,7 +302,7 @@ typedef enum bh_file_standard { } bh_file_standard; typedef struct bh_file_contents { - // This will hold the allocator as well + bh_allocator allocator; isize length; void* data; } bh_file_contents; @@ -200,23 +324,33 @@ i32 bh_file_read(bh_file* file, void* buffer, isize buff_size); i32 bh_file_write(bh_file* file, void* buffer, isize buff_size); i64 bh_file_size(bh_file* file); -#define bh_file_read_contents(x) _Generic((x), \ +#define bh_file_read_contents(allocator_, x) _Generic((x), \ bh_file*: bh_file_read_contents_bh_file, \ const char*: bh_file_read_contents_direct, \ - char*: bh_file_read_contents_direct)(x) + char*: bh_file_read_contents_direct)((allocator_), x) -bh_file_contents bh_file_read_contents_bh_file(bh_file* file); -bh_file_contents bh_file_read_contents_direct(const char* filename); +bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file); +bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename); i32 bh_file_contents_delete(bh_file_contents* contents); #endif + + + + + + + + + //------------------------------------------------------------------------------------- // Better dynamically-sized arrays //------------------------------------------------------------------------------------- #ifndef BH_NO_ARRAY typedef struct bh__arr { + bh_allocator allocator; i32 length, capacity; } bh__arr; @@ -227,6 +361,7 @@ typedef struct bh__arr { #define bh_arr(T) T* #define bh__arrhead(arr) (((bh__arr *)(arr)) - 1) +#define bh_arr_allocator(arr) (arr ? bh__arrhead(arr)->allocator : bh_heap_allocator()) #define bh_arr_length(arr) (arr ? bh__arrhead(arr)->length : 0) #define bh_arr_capacity(arr) (arr ? bh__arrhead(arr)->capacity : 0) #define bh_arr_size(arr) (arr ? bh__arrhead(arr)->capacity * sizeof(*(arr)) : 0) @@ -236,9 +371,9 @@ typedef struct bh__arr { #define bh_arr_last(arr) ((arr)[bh__arrhead(arr)->length - 1]) #define bh_arr_end(arr, i) ((i) >= &(arr)[bh_arr_length(arr)]) -#define bh_arr_new(arr, cap) (bh__arr_grow((void**) &arr, sizeof(*(arr)), cap)) -#define bh_arr_free(arr) (bh__arr_free((void**) &(arr))) -#define bh_arr_copy(arr) (bh__arr_copy((arr), sizeof(*(arr)))) +#define bh_arr_new(allocator_, arr, cap) (bh__arr_grow((allocator_), (void**) &arr, sizeof(*(arr)), cap)) +#define bh_arr_free(arr) (bh__arr_free((void**) &(arr))) +#define bh_arr_copy(allocator_, arr) (bh__arr_copy((allocator_), (arr), sizeof(*(arr)))) #define bh_arr_grow(arr, cap) (bh__arr_grow((void **) &(arr), sizeof(*(arr)), cap)) #define bh_arr_shrink(arr, cap) (bh__arr_shrink((void **) &(arr), sizeof(*(arr)), cap)) @@ -253,7 +388,7 @@ typedef struct bh__arr { bh__arrhead(arr)->length += n) #define bh_arr_push(arr, value) ( \ - bh__arr_grow((void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + 1), \ + bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + 1), \ arr[bh__arrhead(arr)->length++] = value) #define bh_arr_is_empty(arr) (arr ? bh__arrhead(arr)->length == 0 : 1) @@ -262,15 +397,26 @@ typedef struct bh__arr { #define bh_arr_deleten(arr, i, n) (bh__arr_deleten((void **) &(arr), sizeof(*(arr)), i, n)) #define bh_arr_fastdelete(arr, i) (arr[i] = arr[--bh__arrhead(arr)->length]) -b32 bh__arr_grow(void** arr, i32 elemsize, i32 cap); +b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap); b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap); b32 bh__arr_free(void **arr); -void* bh__arr_copy(void *arr, i32 elemsize); +void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize); void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems); void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems); #endif + + + + + + + + + + + //------------------------------------------------------------------------------------- // HASH TABLE FUNCTIONS //------------------------------------------------------------------------------------- @@ -345,6 +491,44 @@ b32 bh_hash_iter_next(bh_hash_iterator* it); #undef BH_DEFINE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + //------------------------------------------------------------------------------------- // IMPLEMENTATIONS //------------------------------------------------------------------------------------- @@ -387,8 +571,146 @@ i64 chars_match(char* ptr1, char* ptr2) { return *ptr2 == '\0' ? len : 0; } + + + + + + +//------------------------------------------------------------------------------------- +// CUSTOM ALLOCATORS IMPLEMENTATION +//------------------------------------------------------------------------------------- + + +ptr bh_alloc(bh_allocator a, isize size) { + return bh_alloc_aligned(a, size, 16); +} + +ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment) { + return a.proc(a.data, bh_allocator_action_alloc, size, alignment, NULL, 0); +} + +ptr bh_resize(bh_allocator a, ptr data, isize new_size) { + return bh_resize_aligned(a, data, new_size, 16); +} + +ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment) { + return a.proc(a.data, bh_allocator_action_resize, new_size, alignment, data, 0); +} + +void bh_free(bh_allocator a, ptr data) { + if (data != NULL) a.proc(a.data, bh_allocator_action_free, 0, 0, data, 0); +} + + + +// HEAP ALLOCATOR IMPLEMENTATION + +bh_allocator bh_heap_allocator(void) { + return (bh_allocator) { + .proc = bh_heap_allocator_proc, + .data = NULL + }; +} + +BH_ALLOCATOR_PROC(bh_heap_allocator_proc) { + ptr retval = NULL; + + switch (action) { + case bh_allocator_action_alloc: { + retval = aligned_alloc(alignment, size); + + if (flags & bh_allocator_flag_clear && retval != NULL) { + memset(retval, 0, size); + } + } break; + + case bh_allocator_action_resize: { + // TODO: Maybe replace with better custom function + retval = realloc(prev_memory, size); + } break; + + case bh_allocator_action_free: { + free(prev_memory); + } break; + } + + return retval; +} + + + + + + + +// NOFREE ALLOCATOR IMPLEMENTATION + +BH_ALLOCATOR_PROC(bh_alloc_nofree_allocator_proc) { + bh_alloc_nofree* alloc_nf = (bh_alloc_nofree*) data; + + ptr retval = NULL; + + switch (action) { + case bh_allocator_action_alloc: { + size = bh__align(size, alignment); + + retval = alloc_nf->next_allocation; + + alloc_nf->next_allocation = bh_pointer_add(alloc_nf->next_allocation, size); + alloc_nf->size += size; + if (alloc_nf->size > alloc_nf->total_size) { + // Out of memory + fprintf(stderr, "NoFree allocator out of memory\n"); + return NULL; + } + } break; + + case bh_allocator_action_resize: { + // Need to think about this one + } break; + + case bh_allocator_action_free: { + // Do nothing since this allocator isn't made for freeing memory + } break; + } + + return retval; +} + +void bh_alloc_nofree_init(bh_alloc_nofree* alloc, isize total_size) { + ptr data = malloc(total_size); + + alloc->total_size = total_size; + alloc->size = 0; + alloc->memory = data; + alloc->next_allocation = data; +} + +void bh_alloc_nofree_free(bh_alloc_nofree* alloc) { + free(alloc->memory); + alloc->memory = NULL; + alloc->next_allocation = NULL; + alloc->total_size = 0; + alloc->size = 0; +} + +bh_allocator bh_alloc_nofree_allocator(bh_alloc_nofree* alloc) { + return (bh_allocator) { + .proc = bh_alloc_nofree_allocator_proc, + .data = alloc, + }; +} + + + + + + + + //------------------------------------------------------------------------------------- -// STRING IMPLEMENTATION +// STRING IMPLEMENTATION (BROKEN) //------------------------------------------------------------------------------------- #ifndef BH_NO_STRING @@ -521,6 +843,14 @@ void bh_string_print(bh_string* str) { #endif // ifndef BH_NO_STRING + + + + + + + + //------------------------------------------------------------------------------------- // FILE IMPLEMENTATION //------------------------------------------------------------------------------------- @@ -675,13 +1005,16 @@ i64 bh_file_size(bh_file* file) { return size; } -bh_file_contents bh_file_read_contents_bh_file(bh_file* file) { - bh_file_contents fc = { .length = 0, .data = NULL }; +bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file) { + bh_file_contents fc = { + .allocator = alloc, + .length = 0, .data = NULL + }; isize size = bh_file_size(file); if (size <= 0) return fc; - fc.data = malloc(size + 1); + fc.data = bh_alloc(alloc, size + 1); fc.length = size; bh_file_read_at(file, 0, fc.data, fc.length, NULL); ((u8*) fc.data)[fc.length] = '\0'; @@ -689,36 +1022,46 @@ bh_file_contents bh_file_read_contents_bh_file(bh_file* file) { return fc; } -bh_file_contents bh_file_read_contents_direct(const char* filename) { +bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename) { bh_file file; bh_file_open(&file, filename); - bh_file_contents fc = bh_file_read_contents(&file); + bh_file_contents fc = bh_file_read_contents(alloc, &file); bh_file_close(&file); return fc; } b32 bh_file_contents_delete(bh_file_contents* contents) { - free(contents->data); + bh_free(contents->allocator, contents->data); contents->length = 0; return 1; } #endif // ifndef BH_NO_FILE + + + + + + + + + //------------------------------------------------------------------------------------- // ARRAY IMPLEMENTATION //------------------------------------------------------------------------------------- #ifndef BH_NO_ARRAY -b32 bh__arr_grow(void** arr, i32 elemsize, i32 cap) { +b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap) { bh__arr* arrptr; if (*arr == NULL) { if (cap == 0 && elemsize == 0) return 1; - arrptr = (bh__arr *) malloc(sizeof(*arrptr) + elemsize * cap); + arrptr = (bh__arr *) bh_alloc(alloc, sizeof(*arrptr) + elemsize * cap); if (arrptr == NULL) return 0; + arrptr->allocator = alloc; arrptr->capacity = cap; arrptr->length = 0; @@ -730,7 +1073,7 @@ b32 bh__arr_grow(void** arr, i32 elemsize, i32 cap) { i32 newcap = arrptr->capacity; while (newcap < cap) newcap = BH_ARR_GROW_FORMULA(newcap); - p = realloc(arrptr, sizeof(*arrptr) + elemsize * newcap); + p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * newcap); if (p) { arrptr = (bh__arr *) p; @@ -752,7 +1095,7 @@ b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) { cap = bh_max(cap, arrptr->length); if (arrptr->capacity > cap) { - void* p = realloc(arrptr, sizeof(*arrptr) + elemsize * cap); + void* p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * cap); if (p) { arrptr = (bh__arr *) p; @@ -768,17 +1111,17 @@ b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) { b32 bh__arr_free(void **arr) { bh__arr* arrptr = bh__arrhead(*arr); - free(arrptr); + bh_free(arrptr->allocator, arrptr); *arr = NULL; } -void* bh__arr_copy(void *arr, i32 elemsize) { +void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize) { bh__arr* arrptr = bh__arrhead(arr); const i32 cap = arrptr->length; void* newarr = NULL; - bh__arr_grow(&newarr, elemsize, cap); + bh__arr_grow(alloc, &newarr, elemsize, cap); bh__arrhead(newarr)->length = cap; bh__arrhead(newarr)->capacity = cap; memcpy(newarr, arr, elemsize * arrptr->length); @@ -800,15 +1143,14 @@ void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems) { } void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) { - bh__arr* arrptr = bh__arrhead(*arr); - if (numelems) { if (*arr == NULL) { - bh__arr_grow(arr, elemsize, numelems); // Making a new array + bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, numelems); // Making a new array return; } - if (!bh__arr_grow(arr, elemsize, arrptr->length + numelems)) return; // Fail case + bh__arr* arrptr = bh__arrhead(*arr); + if (!bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, arrptr->length + numelems)) return; // Fail case memmove( (char *)(*arr) + elemsize * (index + numelems), (char *)(*arr) + elemsize * index, @@ -819,6 +1161,20 @@ void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) { #endif // ifndef BH_NO_ARRAY + + + + + + + + + + + + + + //------------------------------------------------------------------------------------- // HASHTABLE IMPLEMENTATION //------------------------------------------------------------------------------------- @@ -863,7 +1219,7 @@ ptr bh__hash_put(ptr *table, i32 elemsize, char *key) { // Didn't find it in the array, make a new one arrptr = table[index]; len = bh_arr_length(arrptr); - bh__arr_grow(&arrptr, elemsize, len + 1); + bh__arr_grow(bh_arr_allocator(arrptr), &arrptr, elemsize, len + 1); bh__arrhead(arrptr)->length++; table[index] = arrptr; diff --git a/onyx b/onyx index 70fbd91f40f2f08e39891923682c6b1b47aeaf63..57bbd0546305f1b2277e9eb07e1b08de762d515f 100755 GIT binary patch literal 50520 zcmeIb3w%`7wLgB&OfqvwLK0vC;U&X6pd-tBa3TprNECbxA(@brkfg~B54}7z z(lW->#P)jimRqo;{;aQ3Z4m)&R4Vvr8?Dv+yn0P7(9q~@>Vu{h&F{O`-uuj%lZm&V z-|hW<{-6KHqs-cSt+m%)d+oLNUT2?kc6Ry-mpOD@Qv-kWXNopyvqys<`^3Xax<4cLGwmc@BZF!*P;NL8T$VL`jPW>Q@S^f|}-K z1eGIQy*F_d(8~!0*O4-~>Lpa=NIfc-E6e4|atiiJ#S~QSBQf-^M7GZkmx4x@g2YQ# z@##r+rRSIeoXUVrJ_oSKSRHPyA@ zt+TeyyL8s2bF&-kvgdHSNj~vjwW5@3qW+emnC?NIa754i<(S6n@A%-M5BERw!jRXV zNzcCK`|J*5Kv(_72`Pf`^FL}v^Dt4@7Gt2Eiu}g8vwJFaFuDMj+zJA3F$s z_aOL!LGW`2!7m;Jziklw!9nnM41!OC!M&i_FB(?y+I#IF_=^U?|7Z~WcL%}m90dP^ zLGTTO;4c`YT{NuYwd*e6C*hy{+6crjEmPZ7=4Fx^?;6HKIl2F(T4Si8wtQ2)fc4w7 zK%g;HR=zP%UbQh$Syo-6H3Z9QYU;{CC~IsCHiQIrQ*cvbFr?Kq27?l>i9cw=yYqw{4%_hKCBEH;pDXbvZTLco@37&665naV-zxE4HvByj-)+M` zDDk~E{85STv*CX&@miTzqf7binLN&FMwyor3V%M2vs!wYmlFyMd zWnRuv>`d{Ky5>oKHxRl)0_IupG!v`KZ^1hi60q2Ux5npdEO={ty3T^9y46)>!7HC5 zTD=92iQBxkTJT9GR?~J_@W~eZ9t$1|f_b%C@bcD&Y4=(1a_VRNehYq>DMiyBvf!<8 z#X$>xgoXdG1y3=ty4o%H421+dX~B=Q;5#h%Obg!M^nu}TPW=2Dujb#~9&+?|_?wO! zFPI$tmrMewf9e$crcKC0it<%NKik!hYw8%vlWUyq;QVmPlS`a!=X?_7$ra8X%9AUc-NpGoQl4DkY(3}Sr#yB2*>#+MoAT78!^2hbd28ezx}uAf|qw^68ZC z;{3l-ei-FDIDZf2scX-+bN)`sQOg!p|DuDA3rZ9&Ig}P>g*!LK7Iir(H>&I z>1-u9CLBE1Fm4(LO0Q^1MuD`e!`vk90J(>;Cc%$wus`okjNf zb-@bBhsoc25)V^LUV4EvZ}z1}+Wjq_Ul0nNb7}>Q*PP(EiK%E;J=%32+SOVC^wcck zLK9}U_bf*pt<=J_L)wC*aF)z^{Vl~hrz6Fr2D4aj)B-z>TCPN;J=+dbolVy?_(X;v za65=0-9P{N@HbERI#^pJDB|n%pYU~2+oT{bbVU1QMQkc6ZZQ>_Z3thR_LT2&w5T%Tdt6cfVTuVCnK`iD99eJoKf2z^rtObwX}j;o z#PvVW8b3Q!rx0l=L*|JL8XyFG39WmXI#bFL|D{^3YlX zo*9y7isZS+$^+eqXQ<@SB+u8aJhX;^=R<6jP}|@6Otih&%0ufOcseA{VabzY<)O6> zJU^B^-;q42R-U1Pr&aRQOP&v56VpDaf~QgP6iS{~j<)L*KJg-Qe`y|hFD-VTL;Q5i{2}vH8 zm4`ws@O)G96ic4d@IBK$6mEehD0wcDJjbm(6pDjqiR3XP&kw9T6rO=+qU1T%C)$3y zm4`xi@bu3FK-=3TPnng6!g%n!D|z-xo;)iL?U91#sN~ryc_vtS#tNSMB~OXu`2u6g zZ2Ne@vqkdcN}hMEJQoO_QpuAdd5&3mCJ3InlBfGGqV3peQOUDL@{F?bOc6YHN}jor=N#rP(>_xLPnG0J zmps3<@=Oyv%OuYS=S16oYUP29-UH7;n((o@gM{c=tp3!7 z1(VWtucf8^gpWfkz;b@jpXRMz)lKEVBb#I7v4g)JIw1V-K$v?5&jayWJmteMw};nC&}9EFDGM6 z^p6ft{}c1f?)DgeS&$vt1C=qjNz0R@vPIkfcDHY8?fF`3&xY2Xiq@X8)}EVNdv0j$ zS<~86+S;?KwP$5(Pho3ML2J*l)}AG;J$bD?3tM|GZ|%9PwP$W?&+OKo?AD$OTYIuv zd#1MbOls|!(AqPuwP$o|&&bxE5v@Jxtvy3qdy-mv+^szctvx!rv*7BOmEsmBKOK1r<9m_z0)n-uufl(E3f~@t61#uh+utv4FY-%P`)~VTKN%&`SAbhJ zjH$?5g^?5f$j|6D*dKYOiorjxVbDVN!qz*D?%D1B=G{!B_&tKL7n40~W{aVcVodkz z9pJSUJqZut*dB~j4>)k+uzM?#P!N;eKU31*EHrE0O`7E&#%8+qG>vqBMmQmdKOc+3T2!yn!w8{v}9zdRgWgLNN+EYyCP#!lTs;cMH4sqpsfa3J#TT0wPcK?`H+Mlt(BG36Fzwt+Yjk{1^q)XcB zBeK=^vHt*j3bP7{EydlI zubF-1zcJoc$aKmxR4gLR#-n{MjezfO?{2R?X+Fa|MI%hK-nTH-%Co+fNEKoZI-N%C8YogiriT^$^Tw#3JjJ6NZNEs6NK55$ii55!5Yy(21w0FMm)Xt}A!toz@^1}t! z)U>w4?N9pu@;?2}=0W)n)a;kJi6ds40tRQX)=3=v!NK-W(TE53sRr{ zz>C1+5?Bo@o#2W5InojNY)|R=$jf_5q53CjhkWNR2l!rl+My0q(Kr8jPPa>6htEWM z!Phg2><)|0^L-L_q0}cm83-BrXpJQF9qr-&VBa>&!F92dg|0;XT2C67yAfYtk3|*h z;$orU)MaUh(g6rF@A(jIdr71DBJY8IwpOl|HG+F=&pH9)EM z<)&)d-l>JAK^oeMZAVy6N$KFW9-&q~OEYv13f*Ei#_7~ht(X?|0H^yQj@wGR> zW3bX(&s(0M)uM}iecTDed%C;7zh{Azbn@xVLegVW(qe2ckfffmXz9r#w=ngRyCwB^ zsE1<}%TzpQQ+PJUbSbAL(WJCH_M;utECbCt`!C!mUng6~{}*iKh^@>Hf7*{RmvHaF zr?96h_70KeJ-1G=!wUD48?Md8G$1T!$`ZGP2xR6zzj>y=Iq|obdttNZj?n!hcNYf! z)3~|qu7P3LUwaG@kokH|NAsEs82bOn!@?@tP>L)%3b*EDGt@|a(FLV4Iej9J92dRD zcqmKC5DV)aT_@6cB(c8Qktc=laZ-3K2`ADC5=F9*%)`x*na;GNxjrSBhG$D+DX-S0 zebI>qes{w63FgIqo4a|bU)tD(RnHv`4t(JZbVG;3j@*MmTR!+IIvOGCL5-M z?P^p(E=U@AT~}IDU&@v>yy?E1kkIvS*z&-hJB33niT{ZVmau-@U~-|Ji;&2N=$^?) zeq)TiX5k>Hhu*KL!wXXhw{=O)f*jsGVp_ zC;2b4%Qn#R5&ncHRdxrOT!n|TJ!5T{XF8>27Gc}NoIHhg&@hLUZi6oDp-tOQYN2HC zoJ8&9ki6uY1}ug|=!9VyDLsjKsU7puVe7pCorZp|j+c$L2S*X?a&D_e+7==r&yidp7Dyx0US8OCqe#!Bx43UEVMn${VuhoWdi|<>k@nwpW ziUSpwefYT8#vh<~)d1;n6t_v1o}m<9J&5R`14PSMNGORWUjdGY?|jqt^XNJdNmq;# z(|f74@M#JG$SE;VqL8@jd=WiB0}c(Mc!D(q@yYWxV+|-ijLeLHKW_0C?Zvy*Vn;et z?XOc~)zX0c5Yc$19TGIC#Lpgq<6D(Fvk9Bui2wDKXe z{Gi?Inz1p^g3SkE!WU`HY{6bi3)v{VA6lT)iS9?p;>>oU``c{hBFrrR)t(DjVkeyP z_bgtM&Q8aZHLv=8{$@i2ENrg>WG|x1SRi)3%^MiMc0e91TY555bbKlAr_fwYkL$x* zX#+5v-n9L=7EWS8XWbYB&A#JlKStZ{Lw9AOKRQq!ByjbgeT?dut{S%=fkL*i5WQM|>ajWHfF6K-=NQ zT&uU^76eP91~jr)_}c&J_d?4LNJ~GovXnv*^s_fSQ?F0qLy+Sj$c2=N1q z+x2B?Px~^py9QAk123N1N?~DX_!3VIHlHe{3aMoxBvj#E(+9$xFkH+XKU$bgcN#Eg zV7!B2YA!|Z!cBnGU*p}2Uw2<3^rIRs z^t}_I2(B+uoGx~0g@SaWIFAe)3BM63?T8e;+O+*uE$xos7>!`>l;gEP#1$0mVd}-$ z;d>X_$~*OE>|SnvwVB>o33nDm+VN&j5#6A7u#rD16r=Y|%%EqV5gyAzMQ=fKUpMY- zntiXfjB^ZH$xf=oS_AI^qlQjiMqcdR!jFe{U-hUypVQ0JP_`H~ngzeo&_G5Oyi$#}Vv-0QNxD)ICO%F{} z94=#IkVevoa>!qbXd8ymdL~F(bLn}i|GD>_wD}}PLX+>je%to*=kbVZM`!Fz%aekV zfxBOpA1i|=+0eMSH27^P7JF+2M#6xfL?`NnbBtK?!lFRtvGAAS9uFCYiN&)Rg2^K zf5gTt&nwF9?N0fAADd6Ks5rgpc^zIfP#y9V__0H_LOQN!36q+OVp_iQEwyt2$?Y&} z?7np?$naBt)KBx|_@<>80#BN~)AUE~ojxFOdoADMB4t$1$i-GVZjhJW&`_|0z`Oot zFLlFQP=*%Ii{yfQ(%M~bzsXyf@}_Yt-Nm4{up0WhxvRR-RVR2&Hz&?P)qeHt-=+2- zii-GQ0$w(JJOz7Me-JLeHJL{7!rudQ?|`n+=H$d{PO@lDk}ySkUQhfM9gl5M@gSpy zZbjkVX20}c`$mNemVSwj7@juOi0QWXg;->;akdeIf;$D9BwZLMT2Cge7Fg%hQ0b;! z*``hJ=(PCIgh96!u>;NfTkg3R1qbbIVA!`{la=mSXqNCGL{$&|d~`c2Ui8D0yhIe0 z-6?OzBc-omRc2k(>I~RRx&ihvq$pN|E*<_vno*I1&aa9PohE`VUh^Vx!+nrD&HW+a z**qJni1BY!75RHJ_R)BAk(Xc(ypYf$WW5t$gA9D(^}X+agcb7os;k`kGi z(FtqyMHYKlF=3kgQt@b&+%xjb0=}pESuTKeF7M=rr-Vfd4S#dGzh!qlv+~W|MR?*9 z*c^ADaN(2gG3Bg~@3T z+^W^z(!!NAhj&5mJ>+0N$Lep^eWLq7FK3Hcl@r}{Jj?QAl#Nyv}ZAK(+lX#+F$SOug~nSPw%fc`g6N~_y&YF9nUR_bQeZ`7kQf^;Fg6C znUy~G8qv9AmcO}W4OtQs1OgFse-hp{#n$+ zVnmxpm~Hy717%uhGvGuw)rqy>PUKrDzfN>Mw-ecar5lD8`2Zeo`ks>;-B<-Xtxs?7 zWRbycJi5)l>82N=uY&XY*ZJ4wUt17)i-tjA%hc=%{A&3uf~)f*pBF^V70#fyvJL-p zpF6vM{cBXY`@@iT_P?w5!3!gw6-Lf2jr=LU-}8>Y=>^?C|K0E((QU>JH&KQ8H|Gal zXpL6-@e42z$&+6h=y)xlWaV<-ia^QQVqc(i#qt#^uUlb7`Bp3qtS(vQ%P+EGm#i!* z@~tSbqL%yCUbk`;GnX!jODSFLi&wz6rg-J5xCIK9#pN%IFK5}xRq@!Du8fCWJ6n?8;);zc_!D zFQ(EZg)3M42BMjH@v8hKF}4)U1JEY(a$k&rqwF>U7sy|6Rbd?I1JJA276pn6OIKT4 zNVuYc6$6p0OY&p7hYR~wEwOnKp_i>L%wO%dOI;in%Wk_G{gsdYj8U2-Em>K(GRCNc zT+2dqS{UCY zS66C5e9^2`)-?q24KqP}{u~N7)M^!V_#(NkT-#7nx4x`Ko3%(=FiXqQW@xu++qE0C zo3sTuisC|TmNrw%(WYuQYL{QGU9MfBU8F74)@eI%_QcKFG%Y|AGp-w!`WBa7b(42$ zy?3Ekd^VjmwWeZ*w=CqH+ITsV^uWr-7xP^;v0vo1mr-)*>*%bh^CWg!%3tS>7MdeM7P@{A;HYNL1h)bi=xtitMA6eRmC zsjFcdCTVrG+qPzxYmN8>y{He z#%$3|uv8#WRn}M)*nn^1`TKNypE%ZeMJ6Jt#V}#XO9?{5K z2LQLe+TVX1@Ls@EfNyp7_a|VBq3YlJ`!51~8n6&>+&lgKHGl!Yy8xdDd=xPJZh!x) zfCm6S06YPhf*UC9KTsZU3Sc2%31AK2U4VB1o&kImaOQg`54aid1Hg8`6ub*ItPAA< zHvkp`ZUd|bT#D$e6>tU~mmCEACSV6(7ho^or-12riSrgbgvtec2(TFN*MRka-^Sy& zR={Tg4+5s6?>hir2kZr$eg@?chU^B+1?&Q(FAWy`0p$Vj2W$oW72rX@p|~;Y04xOT z1^gjkI)dAM2x4;qm;4ds0e1n`1O65pD6N2ZeSq?SzXt38ydSZ1FW}|aLP#H?X^nqE zKLP#`umo@uLfjDGSiBl|AK>eNhXD^D`soCG0FS);05h;9p9$Z{MHn;>a4v4eXhl-IVN?C-yj7~~b7AN>kC@pr$7_EGGfn!YSG z^XjzZEygbG$}v~Wym-na5<%sc;$J%CqIu>;WpBj4;qXrmwewTczu{Oi)aCdYG!nA^ z3G_!nzko_9`dTJ)-Ftz481#JHwVQP3f)wH){f^<^E4blogI}BUtM76)B{*+)2r(?@ z6v%Vo_tyZLe2zj>j|8+Y2zq%8{brLs1@wnNUt*>25EYCAZYk)md`bBV&{O|+fB%!# z@{Y$%`FDW+0O&bZ`q!fJ4}g9U^vPDbP>i|91O5YfzPXWCP^m$f#W0bxW^ght9x6&P@%s}?30DTU2SjkV!`h88#Tfjl|J3zk{ z^g=7$ag|yA0O+@aesv7pXVQ;@{wV12`qzsxr$B!f^lPo0=vH z$0DwR=~C1&}D zK<@^fzkya`r8uhJNzmT~eRoXxU1s@i&=+Iw&bHF4qveeRe7g?%bSr&*l%56pb)X-& z(j7lH<@-VZ8|XZ@DE%s<<>^ak7uJMTG3AAUx&5He1O53J`ZK2dhd_TD^wJo*FaVW5 z33?jVmci`X4SEsiH^h{`)|78xZQ1iB<+DJ4@k`44LD#W{(F>TS|I}OB5Bf;Zue8!> z03grp2mO*Sp+5wA3Fw3Q$4SszK>y4t-|?y0zHZPrU~N4RL*Hl84Xlklpf9x2w?_5L z0^PvcTZ*~FY@f4OCl1n|zD8S!HTWrOdB+o`{3_7tU6&eb^HK4mtno%5+kF*tRn^M`?o-EilGZ7 zsg8?4|1;?LA~$LSs^dVkj$-iKiWp%qJJf?d{A_P)Rd}V>JEbx^DzOukq7Wm2nUs>QQ3;ciE z0_*tWESwK3A>Cfmr66t5($z&L?BJ3>D_JD+qXjU}m&Mmse9`^~U1J2$)H$=Xr$CpY zfBHp#9p&$nH<8%R;EVQM=)$c%U+t2Pt#H2PNd@ti7hjnY@;;hO6TtQuU*3S1p}JS) zQ^J5z`{cNN=4+IMnryhj8#1Bv?!&$lUD&$kOVxjY%qzaX^^5jFT}FK&^M_@_`lEC% ziN^(Ok6n`fSDEKMWGVX}3Di07c9|pTv?N^9B)n9@WfER1VWotdCH#hj_e%Jngoh-2 zQNlMRJR{*b30-NT-jNbclkidrmq{qN{{CNMoi{GCI=@(*SFFw_R_76`^M}=W!#&dP z)p^3|{9tunusR=Dod>MW|5fMxs`Gu-dA{oWUUgotJ5Q)NUc$K&7D^bD@Ky=$k?=tY zk4pG!3C~D)UP5)gtvb(EonNcYt5xUIs`F^o`LpW0S#`dwI!{)eAM0MM@ukj(Rp-H8 zwPeZV-mKE~;o4Bxds+6}?A%$i!c@+IVC+jNS6!# zPcW>+VDor|3eVuX;CL53rW2#q(C@@}Oj&`+U?(u~Dst$?7z}xb!(B=s!JPqShv7~q zpu5H~E%7{NDQ7|=P9+B|u@bTpiimR8%}^kLHh~>2luR^S2JJqg+ebDV>!&n#kLQYc(&8n_(`lHC~NqL?!Q}ucW#;I2qs-xyPq6a1E@s`@Q-+a2F43PrJ;$}7Gf9PiO}Zau&2;UjMkenf zh6gCAC1;WD->2pp$v2Qy9;DW$!yp0RTt+8yspJu)cG_Yj2ur=m*yj~?gqD6Inq;gZ zwXW0&Z`4sbPo)1s_2hHfW!woN?jEoVxdLjrze&{(*^JuVdpJqY^xP3nzD0t@kWQ(8 zMsgPThiUFf07JGBX)Iyj-esr@BOn>L;dtFa8#0`_V|e(|x!MrVVoFwDJVzUnNs@+F z6LvHYga0H+W0_$+F^nq%VmRK~(1whs{uuEHB)Su>Kyt`!$3XLZf*;K@658sX%cxc@ zfp~`Oz7K?idi)G&c^$tQE%^Bi|3*?`B$XYx#rz@JBdO zmi!Y+w^3mOCO-j~K&(UVA)%udz@XkCxq1-1DO(T_44JJ@rE)1=^uv%jI@Oh)!a^=) zpUKoRsnC$QdM@}z4MjS0$U6N&Q$U$jzXqJc<5k9r-y>D1kYzEljzxvw9Au2MLpjJ zyWx3&6!+XkDtKN*I@vQ76{dI|26d>XAHS)dX5iC2O^}@KxdNQSJg-5*aL?VOhv#cl zxrYvw%kX>({74U3Zj|RZ%4T}5hqTciI{I*oX9+N4J%@l9=UE5N@g5pQ7kKhfc7o^M zfcJXp@H^4-b6_TUeuGkzJv64Kc&-BfRL`rRPV-y>%yiF#pk{eeQP&L5bd21Y9uKG& zY6)bSq$QciBn=~;B;Pjxk~7eXq-A6(E&0#*O}dIqZX}aiB>CAZg!v1|{F%vgFh&xm zy;=eZO1gR>ep6|DK7a%d`U|x&UC8SRZNLn1de?a&6Rn&95&ECjqspf7jM4bL2qg8r zgdKN?8OSl6Z5=ztSC)gl3Iu1{$sOY;q5p|`-r3f^V@xv@>mAD3{X56}j;MbnDbBX; z9T$W)YWjI$$gw{XLfi)_#+^?Q*Q#@*>-vd{K25Y zE`tWl*lr~C8ws&^n2^BldmyRry&gs$_ZMcMq_b_;POkhWVt2IVO{8-#^`1qt!ISFw z@jXPtKyDl zE9w~^+6ZOVh&F=hb~1qfcIc)ekRzf3@C)ns$vTdL*8A@%WnR5OU;ljyC@| zaz@=x&gf`cDpV_|flNnR69Q*TVo!#HRf?!V;;9P=5bqN9=A2-aa&^^w>9Q*TVo!#HRf?!V;;9P=5bqN9=A2- zaa&^^w>9Q*TVo!#HRf?!V;*-*%;T0Zk2@OkxGgb{+YXXUO0&&yYAVkIT3QV`TV<@H|Z)HVcDq1O-7l2SFn!2+}zS8bLvj&Owm7 z0R=`-B&0_pA)O8+F$k&xa-g((tx7my<%{T>qP z8IHRO5h3W`xfzIz>w(alahugJ9J%F2<~=XRJVBhc=p+ z^oe>Z$fMsO!eoy6$1Ftzn66LN8$cLaS)u9E^ed6nQocq^({-Bo4Q({B=~?=6kTM&h z_081jkmQVSfeMvLr;J)Ci28_0&(?Qg)8WSPz7NGOK{~I=P$(IdzfoXrrl+Uar%7xMP+Ry?B?)_8ryJW$xFb1|%b?mulW6?~J&d%=xDj}dHF`ad zhGcN`n!(X)1}q1!;OI4jqt^_MUNbm)&EV)YgQM3Bj$Si3dd=YIHG`wq431tiIC{ESSO3YX(QJ863T4aP*qN(Q5`ruNfS@W*mnOnHe0tW^nYHu>_d0863T4ti#$o zK7*sz431tiIC{Z^h#;3ie71FW8Br~F-H>J?Y(n3esJ;2M}YcX`r~8c zr;vX$gR||?9pi80?1P{q6x(sZWEySBG?<)iT{|Yw2LO%~8vD++V>>RGK*EQU>vJrM zpw{7`LBXM7IdpN1dIt@op!NcaVjZKYN(y-=AUbkPq<6z9;`4qJ=$-gC#QDReq$BPL zW-btk7X{Gffy|}G3mF|dv`Ir33SyYZSx+IUnXXzn_sC-;*#dlKp9^||>%9>2zgq`vnT;Fv-IohOl!h}x!Zqj51Q@hWLm zI6Adv@-lM$q(n*=NiiX*oxXQ0W|V0i5C9Gub_k-U@%Tzgq!ACB?wn4wBy)L0ky_Sw z(E<9ogyMNZ$mgc4Crw%B5=fS_?eI<^>|BBn_S2nHcxpJ8KvAf(?V+7BA}FN)C4t<; z(Y9_z2DSOG2{dvMzfR{c{4*}?Xe*rYT~hROnJt-Kt?6ILOtCg|B2A$0bI~1_38nb0 zIwbYIt07mk^L^G05wKA0eJNn6(CmGw*K@1{-y;*Y2wut>fRBV=?e0W>JnK^>a z@0=p3?|m4;rr=W}qEg!Qx^1e_)7bx2HgDQ9)CD3-V{ek{Vj+`GW1&l!a96@XmbQl4 zL{XZ{poKeY7#XZ4!6y}YfQyhKUWgTn)JR3v2=}j%ij)XNRJK?sqOyge+D)?BDsAS! z(_C|N0@Z!1G|S6oZTnE$G@6OQK~pg%6;Zh;5SSi*GBcfo4RZX3%D&;l#GtMn-Lib zg_kG+!dgp|wWhFsDk~j(nbLmJZ>7j0snc{c=4z>Z6+G|?s(k|2eo>C#;TNfq)c1al z+J*Hd#9D6xD-*Te1k-v#9hE;Qt?4!O`BYXyoBwo?KDkPt8DA%DX3M7C2=%hzT>21J z?@!sHgk093UJf3wOk0X&3>=iE{Q{RkYwXM!)GK-drI*Wc2Sjm{yO+wbQ|R0*XItye zX&eIU31WHNzjMY+be--<5UcyaozrPkDuD&UhoBhwcdwHwxMr4+{Fzz7IkSRZrw9P{ z@0`X0d!0mcwn>41W&v2sX7D}6IVZ&~7@BAXRXp=8QsNIz+F4Qq8X@%$ zEEVo3#B_53TEk9J`Li;MvC>cW{k@as_@|}3D@}QOO?khU@~WnNO%$NP1$oncLL=$- zQcF1h3F@BrSl%rIHv}6sz0*lcyrZo~o7qVEc5wUuc%f+M4Q6|{oANr8ycs{I_P(a7vAc|n@2j&pwY0EJSqXDAwYT*(sxei0S$ zJyP&l&i`hn&?KtR&8C27m4In4U^bQoOoe`K%DeFQ)WAdBgFB?WQnP`tK;9I(Pdp?| zdZQ3`NR}_2_Kqk{H==OAY24gHPAUg47TxibWTvr6jy&@$Ipu>~<*^x}uIJ4v*Ljo; z9+XY+i#i{aV)BGfKIjzNrikm# zZSoI^em}eMm9lo}9q{{$aStfm;(l3s6?e-0PP%z_v{i_?>wYKAUA!i(At&6y;%?0n ztvGHr<{ner4zn?zl2`3;(q@FCtwhM%A?5jJbd%HWijJypk%4bv@g-9HbW{9qO!2oU zZH2sBq`Y;Q)~LB57BEc;$TkH`9;uoeGWFxhIV1%X&sa(A+bq?s(Iy|I{0%Jc0jbGu zQ{L^SycsC5{4OaTjpR$;`%@Cn zi^&lOrNtujUGQd2Bdb2)xLB5n&fMK*nJ3ILS+6F8`$vx7P7{)&qk8TrRl|=Y_nK+E z4fP|3ST2fZ&;vaEVTZU^!91TsJrv=5?^Gf0v;gp@*GL|h5F9jccaa4mj@NnOESbiu zQACROPkWFYKxOl$?Iukl4w}R{1eie9j5z4Vi3Z?|sg%D{wQNQyvELh z+)h4MsybNofXYI6A(5|P;gh8Bt4-nMQusBo!Uel2{2C=(n|UosD`IJHP8MPcO=&-o z(uz!J>>Wk2_!^;`%Hr;KC^=sNOS?x(TWU({mC_1KyRoza)t%bp?~(V+bI?*TPZq!4 zES@(8?(rSLK{xKyn)|KUVsR@spUcx&ocuWTLyn_~WJq~(zW`%l7s(q(ot)zk(`VI` z@+!rTxmBCoOU{3xgJPzRNkWla0Z{%`l%G;lM+|oYiJ)Uj74Gy@u8LelWhxMVk)fxv ztVg9R*?W+6o@9Z4x)P<$+)BDnW`6psEp*Kn0Q?t?75tM;{>f!z`U%WmEcs=V!GELV zpAhBWMf_u#f1>1<@j3YKlKf+%{Era-6FQCb+KEDuCry3M5kC$XAr83|P2pXWCwPOD zCfe7j{F7Xs!Zn1{Kb5qK>3A}$GV8Q)=V?M(aw~)<%Zkd)if+U!n6vnq12ez}#jG0y+r8XAO9H{af#U0$(w-tjin@(d?WiA>iI<{y+ZU70nqdVW(|uZuaLP& z$Xq96E)p`=Xyb;Gw)2QJC}l;pO&X7lMAmPf&~MFno=;^?YCA7R+j$mk=PPY<-l2xf zp{z&N5}i;)4RcftY=JpKX0gzAj*#gm3tX&Z;z5u;HFZR?Gj(k0Fnzc?9czPQ3SQM% z1Qe!onZyuC7^yi^FHgQAxd6dkVj5U*uTOyT?r9nUW3J#yEEsX+=mi+*LnH!B0+BRA zccvyMlN=odl82f?=RsbI%%VJHhpH;EEvf4TBdA2$MAVc6V)_Uar8wacleQwv7S9nJk5?ONH();>;*_N3}#=}pp2 zrb;(SBsZBRwUD&wu^yFW>JOIU+1HD2@3# zb^v6X;^C(;dgNFsmWt8qYq9J&v~Kcc{cov5@vEc38vf}y;l_rX>e}*}a78d@>%2jt&J%}WnIQ1@ZBKrE+gl$7!H?lsVOJ6eJB`2hPW+BXUB*Pp zxX3vjBs$Tx);ToW_}F-CGaBZYJR%ps_&68tgMpZ9e9Y`2mt)$9J*?2}GA75)+Z>%*$Z-iV5KDKuDN2kHM z+_?S-;7fq^{L%2o8#XUQ-#TW%1pIrn3A3q@19d(&&YDKS_<5_zc&ih3t1>=1W8@g& zqevU~95r4#y4E>7+c7hPhP&_vN2O~&j4IXJZ{+Oz^vtn+$ht%qQGYn7s}pF3uHwFP0nEy>0lW zJ4c0%8iMPHYcsf=atHJ7-Yu;;~xH9=nNUH&NOe60jt8{L}ek?Q+IKLEtQho zgnPtDF&=e=zx7Ml*HR2*tByjA5WZfxC&zf~f#wcyXQNGnX?;)I=A4grK?r)?WÐ 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 literal 43368 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 a9amsvy^?SkGO_p{d6-jNZDFt!mH!Ko3k56y diff --git a/onyx.c b/onyx.c index ebb03052..7b718f2c 100644 --- a/onyx.c +++ b/onyx.c @@ -1,5 +1,5 @@ #define BH_NO_STRING -// #define BH_DEBUG +#define BH_DEBUG #define BH_DEFINE #include "bh.h" @@ -15,12 +15,14 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - bh_file_contents fc = bh_file_read_contents(&source_file); + bh_allocator alloc = bh_heap_allocator(); + + bh_file_contents fc = bh_file_read_contents(alloc, &source_file); bh_file_close(&source_file); bh_hash(u16) symbol_count; bh_hash_init(symbol_count); - bh_arr(OnyxToken) token_arr = onyx_parse_tokens(&fc, symbol_count); + bh_arr(OnyxToken) token_arr = onyx_parse_tokens(alloc, &fc, symbol_count); printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr)); diff --git a/onyxlex.c b/onyxlex.c index 91224a03..8447be00 100644 --- a/onyxlex.c +++ b/onyxlex.c @@ -236,7 +236,7 @@ token_parsed: return tk; } -bh_arr(OnyxToken) onyx_parse_tokens(bh_file_contents *fc, bh_hash(u16) symcount) { +bh_arr(OnyxToken) onyx_parse_tokens(bh_allocator tk_alloc, bh_file_contents *fc, bh_hash(u16) symcount) { OnyxTokenizer tknizer = { .start = fc->data, .curr = fc->data, @@ -247,7 +247,7 @@ bh_arr(OnyxToken) onyx_parse_tokens(bh_file_contents *fc, bh_hash(u16) symcount) }; bh_arr(OnyxToken) token_arr = NULL; - bh_arr_grow(token_arr, 512); + bh_arr_new(tk_alloc, token_arr, 512); OnyxToken tk; do { diff --git a/onyxlex.h b/onyxlex.h index fe6b729d..1e4d287b 100644 --- a/onyxlex.h +++ b/onyxlex.h @@ -75,6 +75,6 @@ typedef struct OnyxToken { const char* onyx_get_token_type_name(OnyxToken tkn); OnyxToken onyx_get_token(OnyxTokenizer* tokenizer); -bh_arr(OnyxToken) onyx_parse_tokens(bh_file_contents *fc, bh_hash(u16) symcount); +bh_arr(OnyxToken) onyx_parse_tokens(bh_allocator tk_alloc, bh_file_contents *fc, bh_hash(u16) symcount); #endif \ No newline at end of file -- 2.25.1