2016-02-17 20:41:29 -08:00
|
|
|
#ifndef RUNTIME_ARRAY_H_
|
|
|
|
|
#define RUNTIME_ARRAY_H_
|
2015-11-15 09:55:36 -08:00
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
2015-11-18 08:47:15 -08:00
|
|
|
#include <assert.h>
|
2016-01-28 21:18:57 -08:00
|
|
|
#include <stdbool.h>
|
2016-01-15 15:08:42 -08:00
|
|
|
#include "runtime/alloc.h"
|
2015-11-15 09:55:36 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define Array(T) \
|
2016-02-17 14:45:00 -08:00
|
|
|
struct { \
|
|
|
|
|
T *contents; \
|
|
|
|
|
size_t size; \
|
|
|
|
|
size_t capacity; \
|
|
|
|
|
}
|
2016-01-19 18:07:24 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_init(self) \
|
2016-02-17 14:45:00 -08:00
|
|
|
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
|
2016-02-05 11:18:22 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_get(self, index) \
|
2016-02-17 14:45:00 -08:00
|
|
|
(assert((size_t)index < (self)->size), &(self)->contents[index])
|
2016-01-19 18:07:24 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_front(self) array_get(self, 0)
|
2015-11-15 09:55:36 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_back(self) array_get(self, (self)->size - 1)
|
2016-01-19 18:07:24 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_clear(self) ((self)->size = 0)
|
2015-11-20 00:01:53 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_grow(self, new_capacity) \
|
|
|
|
|
array__grow((VoidArray *)(self), array__elem_size(self), new_capacity)
|
2015-11-18 08:47:15 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_erase(self, index) \
|
|
|
|
|
array__erase((VoidArray *)(self), array__elem_size(self), index)
|
2016-02-08 12:08:15 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_delete(self) array__delete((VoidArray *)self)
|
2015-11-20 00:01:53 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_push(self, element) \
|
|
|
|
|
(((self)->size < (self)->capacity || \
|
|
|
|
|
array_grow((self), (self)->capacity * 2)) && \
|
2016-02-17 14:45:00 -08:00
|
|
|
((self)->contents[(self)->size++] = (element), true))
|
|
|
|
|
|
2016-02-23 09:45:27 -08:00
|
|
|
#define array_splice(self, index, old_count, new_count, new_elements) \
|
|
|
|
|
array__splice((VoidArray *)(self), array__elem_size(self), index, old_count, \
|
|
|
|
|
new_count, new_elements)
|
2016-02-21 22:31:04 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_pop(self) ((self)->contents[--(self)->size])
|
2016-02-17 14:45:00 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_reverse(self) \
|
|
|
|
|
array__reverse((VoidArray *)(self), array__elem_size(self))
|
2016-02-17 14:45:00 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array_copy(self) \
|
|
|
|
|
{ \
|
|
|
|
|
memcpy(ts_calloc((self)->capacity, array__elem_size(self)), \
|
|
|
|
|
(self)->contents, (self)->size *array__elem_size(self)), \
|
|
|
|
|
(self)->size, (self)->capacity, \
|
2016-02-17 14:45:00 -08:00
|
|
|
}
|
2016-02-04 11:15:46 -08:00
|
|
|
|
2016-02-17 14:45:00 -08:00
|
|
|
// Private
|
|
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
typedef Array(void) VoidArray;
|
2016-02-17 14:45:00 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#define array__elem_size(self) sizeof(*(self)->contents)
|
2016-02-17 14:45:00 -08:00
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
static inline void array__delete(VoidArray *self) {
|
2016-02-17 14:45:00 -08:00
|
|
|
ts_free(self->contents);
|
|
|
|
|
self->contents = NULL;
|
2015-11-18 08:47:15 -08:00
|
|
|
self->size = 0;
|
2016-02-17 14:45:00 -08:00
|
|
|
self->capacity = 0;
|
2015-11-18 08:47:15 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
static inline void array__erase(VoidArray *self, size_t element_size,
|
|
|
|
|
size_t index) {
|
2015-11-18 08:47:15 -08:00
|
|
|
assert(index < self->size);
|
|
|
|
|
char *contents = (char *)self->contents;
|
2016-02-17 14:45:00 -08:00
|
|
|
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
|
|
|
|
(self->size - index - 1) * element_size);
|
2015-11-18 08:47:15 -08:00
|
|
|
self->size--;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
static inline bool array__grow(VoidArray *self, size_t element_size,
|
|
|
|
|
size_t new_capacity) {
|
2016-02-17 14:45:00 -08:00
|
|
|
if (new_capacity == 0)
|
|
|
|
|
return true;
|
2015-11-15 09:55:36 -08:00
|
|
|
|
2016-02-17 14:45:00 -08:00
|
|
|
void *new_contents;
|
|
|
|
|
if (self->contents)
|
|
|
|
|
new_contents = ts_realloc(self->contents, new_capacity * element_size);
|
|
|
|
|
else
|
|
|
|
|
new_contents = ts_calloc(new_capacity, element_size);
|
|
|
|
|
|
|
|
|
|
if (!new_contents)
|
|
|
|
|
return false;
|
|
|
|
|
self->capacity = new_capacity;
|
|
|
|
|
self->contents = new_contents;
|
2016-01-19 18:07:24 -08:00
|
|
|
return true;
|
2015-11-15 09:55:36 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-21 22:31:04 -08:00
|
|
|
static inline bool array__splice(VoidArray *self, size_t element_size,
|
|
|
|
|
size_t index, size_t old_count,
|
|
|
|
|
size_t new_count, void *elements) {
|
|
|
|
|
assert(index + old_count <= self->size);
|
|
|
|
|
assert(index < self->size);
|
|
|
|
|
size_t new_size = self->size + new_count - old_count;
|
|
|
|
|
size_t old_end = index + old_count;
|
|
|
|
|
size_t new_end = index + new_count;
|
|
|
|
|
if (new_size >= self->capacity) {
|
|
|
|
|
if (!array__grow(self, element_size, new_size))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *contents = (char *)self->contents;
|
|
|
|
|
if (self->size > old_end)
|
2016-02-23 09:45:27 -08:00
|
|
|
memmove(contents + new_end * element_size, contents + old_end * element_size,
|
2016-02-21 22:31:04 -08:00
|
|
|
(self->size - old_end) * element_size);
|
|
|
|
|
if (new_count > 0)
|
2016-02-23 09:45:27 -08:00
|
|
|
memcpy((contents + index * element_size), elements,
|
|
|
|
|
new_count * element_size);
|
2016-02-21 22:31:04 -08:00
|
|
|
self->size += new_count - old_count;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
static inline void array__reverse(VoidArray *self, size_t element_size) {
|
2016-02-17 14:45:00 -08:00
|
|
|
char swap[element_size];
|
2015-11-15 09:55:36 -08:00
|
|
|
char *contents = (char *)self->contents;
|
2016-02-17 14:45:00 -08:00
|
|
|
for (size_t i = 0, limit = self->size / 2; i < limit; i++) {
|
|
|
|
|
size_t offset = i * element_size;
|
|
|
|
|
size_t reverse_offset = (self->size - 1 - i) * element_size;
|
|
|
|
|
memcpy(&swap, contents + offset, element_size);
|
|
|
|
|
memcpy(contents + offset, contents + reverse_offset, element_size);
|
|
|
|
|
memcpy(contents + reverse_offset, &swap, element_size);
|
2015-11-15 09:55:36 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-02-17 20:41:29 -08:00
|
|
|
#endif // RUNTIME_ARRAY_H_
|