// ke_util.h - kernel utility macros (dynamic arrays, etc.) #pragma once #include #include // --------------------------------------------------------------------------- // Dynamic array (stretchy-buffer style) // // T *buf = NULL; // arr_push(buf, value); // appends; grows automatically // arr_push_front(buf, value); // prepends // arr_remove(buf, i); // removes index i, shifts tail left // size_t n = arr_len(buf); // element count (0 if buf == NULL) // arr_free(buf); // frees header + data // // The allocation layout is: // [ Header (count, capacity) ][ T[0] ][ T[1] ] ... // buf always points at T[0]; the Header lives one slot before it. // --------------------------------------------------------------------------- typedef struct { size_t count; size_t capacity; } _ArrHeader; #define _ARR_INIT_CAPACITY 2 #define _arr_header(arr) ((_ArrHeader *)(arr) - 1) #define arr_len(arr) ((arr) ? _arr_header(arr)->count : 0u) #define _arr_maybe_grow(arr) \ do { \ if (!(arr)) { \ _ArrHeader *_h = MmAllocatePool(sizeof(_ArrHeader) + \ sizeof(*(arr)) * _ARR_INIT_CAPACITY); \ _h->count = 0; \ _h->capacity = _ARR_INIT_CAPACITY; \ (arr) = (void *)(_h + 1); \ } \ _ArrHeader *_h = _arr_header(arr); \ if (_h->count >= _h->capacity) { \ _h->capacity *= 2; \ _h = MmReallocatePool(_h, sizeof(_ArrHeader) + \ sizeof(*(arr)) * _h->capacity); \ (arr) = (void *)(_h + 1); \ } \ } while (0) #define arr_push(arr, x) \ do { \ _arr_maybe_grow(arr); \ (arr)[_arr_header(arr)->count++] = (x); \ } while (0) #define arr_push_front(arr, x) \ do { \ _arr_maybe_grow(arr); \ _ArrHeader *_h = _arr_header(arr); \ memmove(&(arr)[1], &(arr)[0], sizeof(*(arr)) * _h->count); \ (arr)[0] = (x); \ _h->count++; \ } while (0) #define arr_remove(arr, index) \ do { \ if ((arr) && (size_t)(index) < arr_len(arr)) { \ _ArrHeader *_h = _arr_header(arr); \ memmove(&(arr)[index], &(arr)[(index) + 1], \ sizeof(*(arr)) * (_h->count - (size_t)(index) - 1)); \ _h->count--; \ } \ } while (0) #define arr_free(arr) MmFreePool(_arr_header(arr))