In array.h, add comments and sort functions more logically

This commit is contained in:
Max Brunsfeld 2020-09-02 09:59:26 -07:00
parent 4b9db41584
commit 31a22fc627

View file

@ -12,9 +12,9 @@ extern "C" {
#include <stdbool.h>
#include "./alloc.h"
#define Array(T) \
struct { \
T *contents; \
#define Array(T) \
struct { \
T *contents; \
uint32_t size; \
uint32_t capacity; \
}
@ -37,15 +37,15 @@ extern "C" {
#define array_reserve(self, new_capacity) \
array__reserve((VoidArray *)(self), array__elem_size(self), new_capacity)
#define array_erase(self, index) \
array__erase((VoidArray *)(self), array__elem_size(self), index)
// Free any memory allocated for this array.
#define array_delete(self) array__delete((VoidArray *)self)
#define array_push(self, element) \
(array__grow((VoidArray *)(self), 1, array__elem_size(self)), \
(self)->contents[(self)->size++] = (element))
// Increase the array's size by a given number of elements, reallocating
// if necessary. New elements are zero-initialized.
#define array_grow_by(self, count) \
(array__grow((VoidArray *)(self), count, array__elem_size(self)), \
memset((self)->contents + (self)->size, 0, (count) * array__elem_size(self)), \
@ -54,52 +54,46 @@ extern "C" {
#define array_push_all(self, other) \
array_splice((self), (self)->size, 0, (other)->size, (other)->contents)
// Remove `old_count` elements from the array starting at the given `index`. At
// the same index, insert `new_count` new elements, reading their values from the
// `new_contents` pointer.
#define array_splice(self, index, old_count, new_count, new_contents) \
array__splice((VoidArray *)(self), array__elem_size(self), index, old_count, \
new_count, new_contents)
// Insert one `element` into the array at the given `index`.
#define array_insert(self, index, element) \
array__splice((VoidArray *)(self), array__elem_size(self), index, 0, 1, &element)
// Remove one `element` from the array at the given `index`.
#define array_erase(self, index) \
array__erase((VoidArray *)(self), array__elem_size(self), index)
#define array_pop(self) ((self)->contents[--(self)->size])
#define array_assign(self, other) \
array__assign((VoidArray *)(self), (const VoidArray *)(other), array__elem_size(self))
#define array__search_sorted(self, start, compare, suffix, needle, index, exists) \
do { \
*(index) = start; \
*(exists) = false; \
uint32_t size = (self)->size - *(index); \
if (size == 0) break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) *(index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(index)] suffix), (needle)); \
if (comparison == 0) *(exists) = true; \
else if (comparison < 0) *(index) += 1; \
} while (0)
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#define array_search_sorted_by(self, field, needle, index, exists) \
array__search_sorted(self, 0, _compare_int, field, needle, index, exists)
// Search a sorted array for a given `needle` value, using the given `compare`
// callback to determine the order.
//
// If an existing element is found to be equal to `needle`, then the `index`
// out-parameter is set to the existing value's index, and the `exists`
// out-parameter is set to true. Otherwise, `index` is set to an index where
// `needle` should be inserted in order to preserve the sorting, and `exists`
// is set to false.
#define array_search_sorted_with(self, compare, needle, index, exists) \
array__search_sorted(self, 0, compare, , needle, index, exists)
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned index, exists; \
array_search_sorted_by(self, field, (value) field, &index, &exists); \
if (!exists) array_insert(self, index, value); \
} while (0)
// Search a sorted array for a given `needle` value, using integer comparisons
// of a given struct field (specified with a leading dot) to determine the order.
//
// See also `array_search_sorted_with`.
#define array_search_sorted_by(self, field, needle, index, exists) \
array__search_sorted(self, 0, _compare_int, field, needle, index, exists)
// Insert a given `value` into a sorted array, using the given `compare`
// callback to determine the order.
#define array_insert_sorted_with(self, compare, value) \
do { \
unsigned index, exists; \
@ -107,6 +101,17 @@ extern "C" {
if (!exists) array_insert(self, index, value); \
} while (0)
// Insert a given `value` into a sorted array, using integer comparisons of
// a given struct field (specified with a leading dot) to determine the order.
//
// See also `array_search_sorted_by`.
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned index, exists; \
array_search_sorted_by(self, field, (value) field, &index, &exists); \
if (!exists) array_insert(self, index, value); \
} while (0)
// Private
typedef Array(void) VoidArray;
@ -192,6 +197,30 @@ static inline void array__splice(VoidArray *self, size_t element_size,
self->size += new_count - old_count;
}
// A binary search routine, based on Rust's `std::slice::binary_search_by`.
#define array__search_sorted(self, start, compare, suffix, needle, index, exists) \
do { \
*(index) = start; \
*(exists) = false; \
uint32_t size = (self)->size - *(index); \
if (size == 0) break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) *(index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(index)] suffix), (needle)); \
if (comparison == 0) *(exists) = true; \
else if (comparison < 0) *(index) += 1; \
} while (0)
// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
// parameter by reference in order to work with the generic sorting function above.
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#ifdef __cplusplus
}
#endif