|
@@ -0,0 +1,728 @@
|
|
|
+#include "dynar.h"
|
|
|
+#include "mem.h"
|
|
|
+
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+#define ARRAY_ROOM 16
|
|
|
+
|
|
|
+/**
|
|
|
+* Dynar is a DYNamic ARray of size elements each of elsz size.
|
|
|
+* For simplicity, dynarr is exactly sized, that is,
|
|
|
+* it does not allocate any extra elements but the amount requested.
|
|
|
+* In other words it's capacity is equal to it's size.
|
|
|
+*/
|
|
|
+struct Dynar_ {
|
|
|
+ char * data;
|
|
|
+ // use a char * pointer since that makes pointer arithmetic easier
|
|
|
+ int size;
|
|
|
+ int elsz;
|
|
|
+};
|
|
|
+
|
|
|
+/** Gets the array's size. Returns 0 if self is NULL. */
|
|
|
+int dynar_size(Dynar * self) {
|
|
|
+ if(!self) return 0;
|
|
|
+ return self->size;
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets the amount of elements in the vector. Returns 0 if self is NULL.
|
|
|
+ * Alias for dynar_size(self).
|
|
|
+ **/
|
|
|
+int dynar_amount(Dynar * self) {
|
|
|
+ if(!self) return 0;
|
|
|
+ return self->size;
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets the array's element size. Returns 0 if self is NULL. */
|
|
|
+int dynar_elementsize(Dynar * self) {
|
|
|
+ if(!self) return 0;
|
|
|
+ return self->elsz;
|
|
|
+}
|
|
|
+
|
|
|
+/** Frees the contents of an array. Has the same effect as emptying the array. Does not call a desctructor on any elements contained! */
|
|
|
+Dynar * dynar_done(Dynar * self) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ mem_free(self->data);
|
|
|
+ self->data = NULL;
|
|
|
+ self->size = 0;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Calls a destructor on the contents of the array if it is not null.
|
|
|
+ The contents are considered to be pointers. Does not call dynar_free()!!! */
|
|
|
+Dynar * dynar_destroy(Dynar * self, MemDestructor * destroy) {
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ if(!self) return self;
|
|
|
+ if(!destroy) return NULL;
|
|
|
+ for(index = 0; index < size ; index++) {
|
|
|
+ void * ptr = dynar_getptr(self, index);
|
|
|
+ destroy(ptr);
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Calls a destructor on the contents of the array if it is not null.
|
|
|
+ The contents are considered to be structs. Does not call dynar_free()!!! */
|
|
|
+Dynar * dynar_destroy_structs(Dynar * self, MemDestructor * destroy) {
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ if(!self) return self;
|
|
|
+ if(!destroy) return NULL;
|
|
|
+ for(index = 0; index < size ; index++) {
|
|
|
+ void * ptr = dynar_getdata(self, index);
|
|
|
+ destroy(ptr);
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Frees an array. Returns NULL. */
|
|
|
+Dynar * dynar_free(Dynar * self) {
|
|
|
+ dynar_done(self);
|
|
|
+ return mem_free(self);
|
|
|
+}
|
|
|
+
|
|
|
+/** Calls a destructor on the elements of the array and then frees the array */
|
|
|
+Dynar * dynar_free_destroy(Dynar * self, MemDestructor * destroy) {
|
|
|
+ dynar_destroy(self, destroy);
|
|
|
+ return dynar_free(self);
|
|
|
+}
|
|
|
+
|
|
|
+/** Calls a destructor on the elements of the array and then frees the array */
|
|
|
+Dynar * dynar_destroy_structs_and_free(Dynar * self, MemDestructor * destroy) {
|
|
|
+ dynar_destroy_structs(self, destroy);
|
|
|
+ return dynar_free(self);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Allocates a new empty array. */
|
|
|
+Dynar * dynar_alloc() {
|
|
|
+ return STRUCT_ALLOC(Dynar);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Initializes an empty array with 0 elements of size elsz each. */
|
|
|
+Dynar * dynar_initempty(Dynar * self, int elsz) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ if(elsz < 0) return NULL;
|
|
|
+ self->size = 0;
|
|
|
+ self->elsz = elsz;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Allocates a new empty array for elements of size elsz each. */
|
|
|
+Dynar * dynar_newempty(int elsz) {
|
|
|
+ Dynar * res = dynar_alloc();
|
|
|
+ if(!dynar_initempty(res, elsz)) {
|
|
|
+ return dynar_free(res);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+/** Changes the size of the dynamic array. Newsize must be >= 1. */
|
|
|
+Dynar * dynar_size_(Dynar* self, int newsize) {
|
|
|
+ int elsz = dynar_elementsize(self);
|
|
|
+ void * newd = NULL;
|
|
|
+ int delta;
|
|
|
+ if(!self) return NULL;
|
|
|
+ // don't allow a newsize of 0, since that will make realloc call
|
|
|
+ // free on self->data, which we don't want.
|
|
|
+ if(newsize < 1) return NULL;
|
|
|
+ newd = mem_realloc(self->data, newsize * elsz);
|
|
|
+ if(!newd) return NULL;
|
|
|
+ // if we get here realloc was successful, so it should be safe to reassign
|
|
|
+ // self->data
|
|
|
+ self->data = newd;
|
|
|
+ // now, empty the unused new data, but only if growing! (XXX: is this ok???)
|
|
|
+ delta = newsize - self->size;
|
|
|
+ if(delta > 0) {
|
|
|
+ memset(self->data + (self->size * self->elsz), 0, (delta * self->elsz));
|
|
|
+ }
|
|
|
+ self->size = newsize;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Initializes a new array with a amount elements of size
|
|
|
+elsz each. */
|
|
|
+Dynar * dynar_init(Dynar * self, int amount, int elsz) {
|
|
|
+ Dynar * aid = dynar_initempty(self, elsz);
|
|
|
+ if(!aid) return NULL;
|
|
|
+ if(!dynar_size_(self, amount)) return NULL;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Initializes a new array with a capacity to store amount void* pointers.*/
|
|
|
+Dynar * dynar_initptr(Dynar * self, int amount) {
|
|
|
+ return dynar_init(self, amount, sizeof(void *));
|
|
|
+}
|
|
|
+
|
|
|
+/** Allocates a new array with amount elements of size elsz each. */
|
|
|
+Dynar * dynar_new(int amount, int elsz) {
|
|
|
+ Dynar * res = dynar_alloc();
|
|
|
+ if(!dynar_init(res, amount, elsz)) {
|
|
|
+ return dynar_free(res);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Allocates a new array that will be able to contain amount void * pointers.*/
|
|
|
+Dynar * dynar_newptr(int amount) {
|
|
|
+ return dynar_new(amount, sizeof(void *));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Sets the amount of elements of the the array, but ony if
|
|
|
+* amount bigger than the bigger than the current size.
|
|
|
+* Returns NULL if the array was not grown, otherwise returns self.
|
|
|
+*/
|
|
|
+Dynar * dynar_grow(Dynar * self, int amount) {
|
|
|
+ int mysize = dynar_size(self);
|
|
|
+ if (mysize >= amount) return NULL;
|
|
|
+ return dynar_size_(self, amount);
|
|
|
+}
|
|
|
+
|
|
|
+/** Checks if the index is smaller than the array's available room . */
|
|
|
+int dynar_sizeindex_ok(Dynar * self, int index) {
|
|
|
+ if(!self) return FALSE;
|
|
|
+ return index < dynar_size(self);
|
|
|
+}
|
|
|
+
|
|
|
+/** Checks if the int index is smaller than the array's available room. */
|
|
|
+int dynar_index_ok(Dynar * self, int index) {
|
|
|
+ if(!self) return FALSE;
|
|
|
+ if (index < 0) return FALSE;
|
|
|
+ return dynar_sizeindex_ok(self, (int)(index));
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a pointer to the index-th element of the array.
|
|
|
+Does no bounds checking! */
|
|
|
+void * dynar_getraw_unsafe(Dynar * self, int index) {
|
|
|
+ return self->data + (index * self->elsz);
|
|
|
+}
|
|
|
+
|
|
|
+/** Copies dynar_elementsize(self) of bytes from the index-th element
|
|
|
+of the array to out, which must be pointing to a bufer of at least
|
|
|
+dynar_elementsize(self). Does no bounds checking!
|
|
|
+Returns NULL on failure, out on success.
|
|
|
+*/
|
|
|
+void * dynar_getcopy_unsafe(Dynar * self, int index, void * out) {
|
|
|
+ char * cptr = (char *) dynar_getraw_unsafe(self, index);
|
|
|
+ int size = dynar_elementsize(self);
|
|
|
+ if((!self) || (!out) || (!cptr)) return NULL;
|
|
|
+ mem_move(out, cptr, size);
|
|
|
+ return out;
|
|
|
+}
|
|
|
+
|
|
|
+/** Copies dynar_elementsize(self) of bytes from the data pointed to
|
|
|
+* by ptr into the location pointed to by index.
|
|
|
+* Does no bounds checking!
|
|
|
+*/
|
|
|
+Dynar * dynar_putraw_unsafe(Dynar * self, int index, void * ptr) {
|
|
|
+ char * cptr = (char *) dynar_getraw_unsafe(self, index);
|
|
|
+ int size = dynar_elementsize(self);
|
|
|
+ if((!self) || (!ptr) || (!cptr)) return NULL;
|
|
|
+ mem_move(cptr, ptr, size);
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a pointer to the index-th element of the array.
|
|
|
+Does bounds checking and return NULL if out of bounds */
|
|
|
+void * dynar_getraw(Dynar * self, int index) {
|
|
|
+ // Bounds check
|
|
|
+ if(!dynar_index_ok(self, index)) { return NULL; }
|
|
|
+ return dynar_getraw_unsafe(self, index);
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a pointer to the index-th element of the array.
|
|
|
+Does bounds checking and return NULL if out of bounds */
|
|
|
+void * dynar_getcopy(Dynar * self, int index, void * ptr) {
|
|
|
+ // Bounds check
|
|
|
+ if(!dynar_index_ok(self, index)) { return NULL; }
|
|
|
+ return dynar_getcopy_unsafe(self, index, ptr);
|
|
|
+}
|
|
|
+
|
|
|
+/** Copies the dynar_elementsize(self) of bytes from the data pointed to
|
|
|
+* by ptr into the location pointed to by index.
|
|
|
+* Does bounds checking and return NULL if ouut of bounds.
|
|
|
+*/
|
|
|
+Dynar * dynar_putraw(Dynar * self, int index, void * ptr) {
|
|
|
+ // Bounds check
|
|
|
+ if(!dynar_index_ok(self, index)) { return NULL; }
|
|
|
+ return dynar_putraw_unsafe(self, index, ptr);
|
|
|
+}
|
|
|
+
|
|
|
+/** Stores a pointer at the index of the array.
|
|
|
+* Does bounds checking. dynar_elementsize(self) sould have been
|
|
|
+* initialized as sizeof(void *) by using dynar_newptr
|
|
|
+*/
|
|
|
+void * dynar_putptr(Dynar * self, int index, void * ptr) {
|
|
|
+ return dynar_putraw(self, index, &ptr);
|
|
|
+ // use &ptr because we want to put the contents of the pointer,
|
|
|
+ // not the pointer itself.
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a pointer that was stored at the index index of the array. */
|
|
|
+void * dynar_getptr(Dynar * self, int index) {
|
|
|
+ void * res = NULL;
|
|
|
+ if(!dynar_getcopy(self, index, &res)) return NULL;
|
|
|
+ // use &ptr because we want to fetch the contents of the pointer,
|
|
|
+ // which will be copied from the element of the array.
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+/** Copies the element that *ptr points to into this array at position
|
|
|
+index */
|
|
|
+void * dynar_putdata(Dynar * self, int index, void * ptr) {
|
|
|
+ return dynar_putraw(self, index, ptr);
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a pointer to the index-th element of the array. */
|
|
|
+void * dynar_getdata(Dynar * self, int index) {
|
|
|
+ return dynar_getraw(self, index);
|
|
|
+}
|
|
|
+
|
|
|
+/* Applies quick sort to the array using the given comparator. */
|
|
|
+Dynar * dynar_qsort(Dynar * self, DynarCompare * compare) {
|
|
|
+ void * base; int nmemb; size_t size;
|
|
|
+ if(!self) return NULL;
|
|
|
+ base = self->data;
|
|
|
+ nmemb = self->size;
|
|
|
+ size = self->elsz;
|
|
|
+ qsort(base, nmemb, size, compare);
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/* Applies a binary search to the array using the given comparator.
|
|
|
+ User must call dynar_qsort first. */
|
|
|
+void * dynar_bsearch(Dynar * self, const void * key, DynarCompare * compare) {
|
|
|
+ void * base; int nmemb; size_t size;
|
|
|
+ if (!self) return NULL;
|
|
|
+ base = self->data;
|
|
|
+ nmemb = self->size;
|
|
|
+ size = self->elsz;
|
|
|
+ return bsearch(key, base, nmemb, size, compare);
|
|
|
+}
|
|
|
+
|
|
|
+/* Puts NULL in every element of this array using dynar_putptr */
|
|
|
+Dynar * dynar_putnullall(Dynar * self) {
|
|
|
+ int stop = dynar_size(self);
|
|
|
+ int index;
|
|
|
+ for (index = 0; index < stop; index++) {
|
|
|
+ dynar_putptr(self, index, NULL);
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/* Iterator helper: fill in every->now as data. */
|
|
|
+Every * dynar_everynow_data(Every * every) {
|
|
|
+ every->now = dynar_getdata(every->on, every->index);
|
|
|
+ if(every->now) return every;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helper: fill in every->now as pointer. */
|
|
|
+Every * dynar_everynow_ptr(Every * every) {
|
|
|
+ every->now = dynar_getptr(every->on, every->index);
|
|
|
+ if(every->now) return every;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: init */
|
|
|
+Every * dynar_everyinit_data(Every * every) {
|
|
|
+ every->index = 0;
|
|
|
+ return dynar_everynow_data(every);
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: next */
|
|
|
+Every * dynar_everynext_data(Every * every) {
|
|
|
+ every->index++;
|
|
|
+ return dynar_everynow_data(every);
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: put. */
|
|
|
+void * dynar_everyput_data(Every * every, void * data) {
|
|
|
+ return dynar_putdata(every->on, every->index, data);
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: done. */
|
|
|
+void * dynar_everydone(Every * every) {
|
|
|
+ return every;
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: init pointers */
|
|
|
+Every * dynar_everyinit_ptr(Every * every) {
|
|
|
+ every->index = 0;
|
|
|
+ return dynar_everynow_ptr(every);
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: next pointers */
|
|
|
+Every * dynar_everynext_ptr(Every * every) {
|
|
|
+ every->index++;
|
|
|
+ return dynar_everynow_ptr(every);
|
|
|
+}
|
|
|
+
|
|
|
+/* Iterator helpers: put pointers. */
|
|
|
+void * dynar_everyput_ptr(Every * every, void * data) {
|
|
|
+ return dynar_putptr(every->on, every->index, data);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Iterator helper table. */
|
|
|
+static EveryActs dynar_every_data_acts_ = {
|
|
|
+ dynar_everydone,
|
|
|
+ dynar_everyinit_data,
|
|
|
+ dynar_everynext_data,
|
|
|
+ dynar_everyput_data
|
|
|
+};
|
|
|
+
|
|
|
+/* Iterator helper table. */
|
|
|
+static EveryActs dynar_every_ptr_acts_ = {
|
|
|
+ dynar_everydone,
|
|
|
+ dynar_everyinit_ptr,
|
|
|
+ dynar_everynext_ptr,
|
|
|
+ dynar_everyput_ptr
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/** Iterates over the data. Call every_free when done. */
|
|
|
+Every * dynar_every_data(Dynar * dynar) {
|
|
|
+ return every_new(&dynar_every_data_acts_);
|
|
|
+}
|
|
|
+
|
|
|
+/** Iterates over the pointers in this array. Call every_free when done. */
|
|
|
+Every * dynar_every_ptr(Dynar * dynar) {
|
|
|
+ return every_new(&dynar_every_ptr_acts_);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Walks over the array using the each interface, accessing
|
|
|
+the data as pointers. eachdo should return non-null to break the iteration,
|
|
|
+the data thus found is returned bu this function. */
|
|
|
+void * dynar_each_ptr(Dynar * self, EachDo * eachdo, void * extra) {
|
|
|
+ Each each;
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ each_init(&each, self, extra);
|
|
|
+ for(index = 0; index < size ; index++) {
|
|
|
+ void * aid;
|
|
|
+ void * ptr = dynar_getptr(self, index);
|
|
|
+ each_next(&each, ptr);
|
|
|
+ aid = eachdo(&each);
|
|
|
+ if (aid) return aid;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array using the Each interface, accessing
|
|
|
+the data as stored structs. */
|
|
|
+void * dynar_each_data(Dynar * self, EachDo * eachdo, void * extra) {
|
|
|
+ Each each;
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ each_init(&each, self, extra);
|
|
|
+ for(index = 0; index < size ; index++) {
|
|
|
+ void * aid;
|
|
|
+ void * ptr = dynar_getdata(self, index);
|
|
|
+ each_next(&each, ptr);
|
|
|
+ aid = eachdo(&each);
|
|
|
+ if (aid) return aid;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array using the walker interface, accessing
|
|
|
+the data as stored pointers. */
|
|
|
+void * dynar_walkptrbetween(Dynar * self, int low, int high,
|
|
|
+ Walker * walker, void * extra) {
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ low = (low < 0) ? 0 : low;
|
|
|
+ high = (high > size) ? size : high;
|
|
|
+ for(index = low; index < high ; index++) {
|
|
|
+ void * aid;
|
|
|
+ void * ptr = dynar_getptr(self, index);
|
|
|
+ aid = walker(ptr, extra);
|
|
|
+ if (aid) return aid;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array using the walker interface, accessing
|
|
|
+the data as stored structs. */
|
|
|
+void * dynar_walkptr(Dynar * self, Walker * walker, void * extra) {
|
|
|
+ return dynar_walkptrbetween(self, 0, dynar_size(self), walker, extra);
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array using the walker interface, accessing
|
|
|
+the data as stored pointers. */
|
|
|
+void * dynar_walkdatabetween(Dynar * self, int low, int high,
|
|
|
+ Walker * walker, void * extra) {
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ low = (low < 0) ? 0 : low;
|
|
|
+ high = (high > size) ? size : high;
|
|
|
+ for(index = low; index < high ; index++) {
|
|
|
+ void * aid;
|
|
|
+ void * ptr = dynar_getdata(self, index);
|
|
|
+ aid = walker(ptr, extra);
|
|
|
+ if (aid) return aid;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array using the walker interface, accessing
|
|
|
+the data as stored structs. */
|
|
|
+void * dynar_walkdata(Dynar * self, Walker * walker, void * extra) {
|
|
|
+ return dynar_walkdatabetween(self, 0, dynar_size(self), walker, extra);
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array updating it, using the walker interface, accessing
|
|
|
+the data as stored pointers. */
|
|
|
+void * dynar_walkmapptrbetween(Dynar * self, int low, int high,
|
|
|
+ Walker * walker, void * extra) {
|
|
|
+ int index;
|
|
|
+ int size = dynar_size(self);
|
|
|
+ low = (low < 0) ? 0 : low;
|
|
|
+ high = (high > size) ? size : high;
|
|
|
+ for(index = low; index < high ; index++) {
|
|
|
+ void * aid;
|
|
|
+ void * ptr = dynar_getptr(self, index);
|
|
|
+ aid = walker(ptr, extra);
|
|
|
+ dynar_putptr(self, index, ptr);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Walks over the array updating it using the walker interface, accessing
|
|
|
+the data as stored structs. */
|
|
|
+void * dynar_walkmapptr(Dynar * self, Walker * walker, void * extra) {
|
|
|
+ return dynar_walkmapptrbetween(self, 0, dynar_size(self), walker, extra);
|
|
|
+}
|
|
|
+
|
|
|
+/* Resizes a dynar filled with pointers, and if the dynar shrinks, calls the
|
|
|
+ * given destructor on all elements that are to be removed. Returns self on success
|
|
|
+ * and NULL on failure. Even in this case, the superfluous elements
|
|
|
+ fmay have been removed. */
|
|
|
+Dynar * dynar_resize(Dynar * self, int newsize, MemDestructor * destroy) {
|
|
|
+ int index;
|
|
|
+ int last;
|
|
|
+ if (!self) return NULL;
|
|
|
+ last = dynar_size(self);
|
|
|
+ for(index = newsize; index < last; index ++) {
|
|
|
+ void * aid = dynar_getptr(self, index);
|
|
|
+ dynar_putptr(self, index, destroy(aid));
|
|
|
+ }
|
|
|
+ return dynar_size_(self, newsize);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/** Makes a new empty dynar to contain long integers */
|
|
|
+Dynar * dynar_new_long() {
|
|
|
+ return dynar_newempty(sizeof(long));
|
|
|
+}
|
|
|
+
|
|
|
+/** Stores a long integer into a dynar (preferrably created with dynar_new_long */
|
|
|
+Dynar * dynar_put_long(Dynar * self, int index, long value) {
|
|
|
+ return dynar_putdata(self, index, &value);
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets a long integer from a dynar */
|
|
|
+Dynar * dynar_get_long(Dynar * self, int index, long * value) {
|
|
|
+ return dynar_getcopy(self, index, value);
|
|
|
+}
|
|
|
+
|
|
|
+/** Grows the size of the array by 1 and appends the long in the last position */
|
|
|
+Dynar * dynar_append_long(Dynar * self, long value) {
|
|
|
+ int pos = dynar_size(self);
|
|
|
+ if (!dynar_size_(self, pos+1)) return NULL;
|
|
|
+ return dynar_put_long(self, pos, value);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+* Lilis is a doubly Linked List that points to it's members via void pointers
|
|
|
+* but does not own them in the sense that it doesn't clean them up unless requested.
|
|
|
+*/
|
|
|
+struct Lilis_ {
|
|
|
+ Lilis * next;
|
|
|
+ Lilis * prev;
|
|
|
+ void * data;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+* frees the tail of a llist only. Does nothing to self or other.
|
|
|
+*/
|
|
|
+
|
|
|
+Lilis * lilis_freetail(Lilis * self) {
|
|
|
+ Lilis * next, * now;
|
|
|
+ if(!self) return NULL;
|
|
|
+ now = self->next; // skip current node, that will be deleted in lilis_free
|
|
|
+ while (now) {
|
|
|
+ next = now->next; // already get next one
|
|
|
+ mem_free(now); // now we can safely free the current node
|
|
|
+ now = next; // set current to next one.
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Frees the tail of the list pointed to by self. It does not free any of the
|
|
|
+emlements contained in * data. Does not alter self->prev, and doesn't
|
|
|
+free that either. */
|
|
|
+Lilis * lilis_done(Lilis * self ) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ lilis_freetail(self);
|
|
|
+ self->data = NULL;
|
|
|
+ self->next = NULL;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Frees a linked list node and it's tail. Returns NULL. */
|
|
|
+Lilis * lilis_free(Lilis * self) {
|
|
|
+ lilis_done(self);
|
|
|
+ return mem_free(self);
|
|
|
+}
|
|
|
+
|
|
|
+/** Allocates a new empty linked list. */
|
|
|
+Lilis * lilis_alloc() {
|
|
|
+ return STRUCT_ALLOC(Lilis);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Initializes a linked list node */
|
|
|
+Lilis * lilis_init(Lilis * self, Lilis * next, Lilis * prev, void * data) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ self->data = data;
|
|
|
+ self->next = next;
|
|
|
+ self->prev = prev;
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** Initializes a new linked list node that points to nothing. */
|
|
|
+Lilis * lilis_initempty(Lilis * self) {
|
|
|
+ return lilis_init(self, NULL, NULL, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Returns a newly allocatd linked list node. */
|
|
|
+Lilis * lilis_new(Lilis * next, Lilis * prev, void * data) {
|
|
|
+ Lilis * res = lilis_alloc();
|
|
|
+ if(!lilis_init(res, next, prev, data)) {
|
|
|
+ return lilis_free(res);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+/** Returns a newly allocated linked list node that points to nothing. */
|
|
|
+Lilis * lilis_newempty() {
|
|
|
+ return lilis_new(NULL, NULL, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+/** Appends a node to the current one, inserting it if needed.
|
|
|
+* returns other.
|
|
|
+*/
|
|
|
+Lilis * lilis_add(Lilis * self, Lilis * other) {
|
|
|
+ Lilis * oldnext = self->next;
|
|
|
+ if ((!self) || (!other)) return NULL;
|
|
|
+ if (oldnext) {
|
|
|
+ oldnext->prev = other; // next one's previous becomes the inserted link
|
|
|
+ other->next = oldnext; // inserted link's next is the old next
|
|
|
+ }
|
|
|
+ // these two belowear always needed even if there is no oldnext.
|
|
|
+ other->prev = self; // and other's previous one is self.
|
|
|
+ self->next = other; // and curent next is the inserted link
|
|
|
+ return other;
|
|
|
+}
|
|
|
+
|
|
|
+/** Creates a new node and adds it */
|
|
|
+Lilis * lilis_addnew(Lilis * self, void * data) {
|
|
|
+ Lilis * other = lilis_new(NULL, NULL, data);
|
|
|
+ return lilis_add(self, other);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** Removes the node that follows self, but does NOT call lilis_free on it.
|
|
|
+* returns the removed node
|
|
|
+*/
|
|
|
+Lilis * lilis_removenext(Lilis * self) {
|
|
|
+ Lilis * next, * nextnext;
|
|
|
+ if(!self) return NULL;
|
|
|
+ next = self->next;
|
|
|
+ if(!next) return NULL;
|
|
|
+ nextnext = next->next;
|
|
|
+ if(nextnext) {
|
|
|
+ nextnext->prev = self;
|
|
|
+ self->next = nextnext;
|
|
|
+ } else {
|
|
|
+ self->next = NULL;
|
|
|
+ }
|
|
|
+ return next;
|
|
|
+}
|
|
|
+
|
|
|
+/** Removes self, modifies prev if this is needed, but does NOT call
|
|
|
+* lilis_free on it.
|
|
|
+* returns the removed node
|
|
|
+*/
|
|
|
+Lilis * lilis_remove(Lilis * self) {
|
|
|
+ Lilis * prev, * next;
|
|
|
+ if(!self) return NULL;
|
|
|
+ next = self->next;
|
|
|
+ prev = self->prev;
|
|
|
+ if(next) { // link prev node to next node, so this node is cut out.
|
|
|
+ prev->next = next;
|
|
|
+ next->prev = prev;
|
|
|
+ } else { // no next node, prev also gets no next node.
|
|
|
+ prev->next = NULL;
|
|
|
+ }
|
|
|
+ // finally unlink self.
|
|
|
+ self->next = NULL;
|
|
|
+ self->prev = NULL;
|
|
|
+ return next;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/** Removes the node self, and calls lilis_free on it.
|
|
|
+* returns NULL
|
|
|
+*/
|
|
|
+Lilis * lilis_erase(Lilis * self) {
|
|
|
+ Lilis * eraseme = lilis_remove(self);
|
|
|
+ return lilis_free(eraseme);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/** Removes the node that follows self, and calls lilis_free on it.
|
|
|
+* returns NULL
|
|
|
+*/
|
|
|
+Lilis * lilis_erasenext(Lilis * self) {
|
|
|
+ Lilis * eraseme = lilis_removenext(self);
|
|
|
+ return lilis_free(eraseme);
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets the next node in the list. */
|
|
|
+Lilis * lilis_next(Lilis * self) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ return self->next;
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets the previous node in the list. */
|
|
|
+Lilis * lilis_previous(Lilis * self) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ return self->prev;
|
|
|
+}
|
|
|
+
|
|
|
+/** Gets the data of the list node */
|
|
|
+void * lilis_data(Lilis * self) {
|
|
|
+ if(!self) return NULL;
|
|
|
+ return self->data;
|
|
|
+}
|