py3dutil/src/obarr.c
cecilkorik 1d8b688a61
Some checks failed
Packages / Build distribution 📦 (push) Failing after 43s
attempt to modernize slightly
2024-02-03 13:37:22 -05:00

509 lines
11 KiB
C

#define NEED_STATIC
#include "obarr.h"
#undef NEED_STATIC
PyObject* obarr_get_element(ObarrObject* self, long index)
{
return self->pData[index];
}
int obarr_find(ObarrObject* self, PyObject* other_in)
{
long i;
for (i = 0; i < self->nSize; i++)
{
if (self->pData[i] == other_in)
return i;
}
return -1;
}
void obarr_set_element(ObarrObject* self, long index, PyObject* new_in)
{
PyObject* old = obarr_get_element(self, index);
Py_INCREF(new_in);
self->pData[index] = new_in;
Py_DECREF(old);
}
void obarr_empty(ObarrObject* self)
{
long i;
for (i = 0; i < self->nAllocSize; i++)
{
Py_DECREF(self->pData[i]);
}
if (self->pData != NULL)
free(self->pData);
self->nAllocSize = 0;
self->nSize = 0;
self->pData = NULL;
}
void obarr_del_index(ObarrObject* self, long i)
{
Py_DECREF(self->pData[i]);
if ((self->nSize - i - 1) > 0)
{
/* slide the tail end of the array up so we don't have a hole in the middle */
self->pData[i] = self->pData[self->nSize - 1];
/* fill the end of the array with a None before we reduce the size to cover that up */
/* to turn it back into "allocated but unused" space */
self->pData[self->nSize - 1] = Py_None;
Py_INCREF(Py_None);
}
else
{
self->pData[i] = Py_None;
Py_INCREF(Py_None);
}
self->nSize = self->nSize - 1;
}
int obarr_valid_index(ObarrObject* self, long i)
{
if (i >= 0 && i < self->nSize)
return 1;
return 0;
}
int obarr_set_size(ObarrObject* self, long size)
{
long i, newsize;
void* tmp;
if (size == 0)
{
obarr_empty(self);
return 1;
}
else if (size > self->nAllocSize)
{
newsize = self->nChunkSize * (size / self->nChunkSize);
if ((size % self->nChunkSize) != 0)
newsize = newsize + self->nChunkSize;
if (self->pData == NULL)
{
self->pData = (PyObject**)malloc(newsize * sizeof(void*));
if (self->pData == NULL)
{
return 0;
}
for (i = 0; i < newsize; i++)
{
Py_INCREF(Py_None);
self->pData[i] = Py_None;
}
}
else
{
tmp = realloc(self->pData, newsize * sizeof(void*));
if (tmp == NULL)
return 0;
self->pData = (PyObject**)tmp;
for (i = self->nAllocSize; i < newsize; i++)
{
Py_INCREF(Py_None);
self->pData[i] = Py_None;
}
}
self->nAllocSize = newsize;
}
else
{
for (i = size; i < self->nAllocSize; i++)
{
if (self->pData[i] != Py_None)
{
Py_DECREF(self->pData[i]);
Py_INCREF(Py_None);
self->pData[i] = Py_None;
}
}
}
self->nSize = size;
return 1;
}
int obarr_append(ObarrObject *self, PyObject *other)
{
if (obarr_set_size(self, self->nSize + 1))
{
obarr_set_element(self, self->nSize - 1, other);
return 1;
}
return 0;
}
int Obarr_init(ObarrObject *self, PyObject *args, PyObject *kwds)
{
self->nSize = 0;
self->nChunkSize = 64;
self->nAllocSize = 0;
self->pData = NULL;
return 0;
}
void Obarr_dealloc(PyObject* self_in)
{
ObarrObject* self = (ObarrObject*)self_in;
obarr_empty(self);
}
PyObject* Obarr_repr(PyObject *self_in)
{
ObarrObject *self;
PyObject *tuple, *fmtstring, *reprstring;
if (!Obarr_Check(self_in))
return PyString_FromString("<unknown object type>");
self = (ObarrObject*)self_in;
tuple = Py_BuildValue("(l)", self->nSize);
fmtstring = PyString_FromString("<array of %d objects>");
reprstring = PyString_Format(fmtstring, tuple);
Py_DECREF(tuple);
Py_DECREF(fmtstring);
return reprstring;
}
Py_ssize_t Obarr_len(PyObject *self_in)
{
ObarrObject* self = (ObarrObject*)self_in;
return self->nSize;
}
PyObject * Obarr_item(PyObject *self_in, Py_ssize_t index)
{
ObarrObject* self = (ObarrObject*)self_in;
PyObject* ob;
if (!obarr_valid_index(self, index))
{
PyErr_SetString(PyExc_IndexError, "index not in range");
return NULL;
}
ob = obarr_get_element(self, index);
Py_INCREF(ob);
return ob;
}
int Obarr_setitem(PyObject* self_in, Py_ssize_t index, PyObject* new_in)
{
ObarrObject* self = (ObarrObject*)self_in;
if (!obarr_valid_index(self, index))
{
PyErr_SetString(PyExc_IndexError, "index not in range");
return -1;
}
obarr_set_element(self, index, new_in);
return 0;
}
PyObject* Obarr_remove(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
long i;
PyObject* other_in = NULL;
if (!PyArg_ParseTuple(args, "O", &other_in))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
i = obarr_find(self, other_in);
if (i == -1)
{
PyErr_SetString(PyExc_ValueError, "supplied argument not found in list");
return NULL;
}
obarr_del_index(self, i);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Obarr_delete(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
long i;
if (!PyArg_ParseTuple(args, "l", &i))
{
PyErr_SetString(PyExc_TypeError, "must be called with an index as an argument");
return NULL;
}
if (!obarr_valid_index(self, i))
{
PyErr_SetString(PyExc_IndexError, "index not in range");
return NULL;
}
obarr_del_index(self, i);
Py_INCREF(Py_None);
return Py_None;
}
int Obarr_contains(PyObject* self_in, PyObject* other_in)
{
ObarrObject* self = (ObarrObject*)self_in;
long i;
i = obarr_find(self, other_in);
if (i == -1)
return 0;
return 1;
}
PyObject* Obarr_index(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
long i;
PyObject* other_in = NULL;
if (!PyArg_ParseTuple(args, "O", &other_in))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
i = obarr_find(self, other_in);
if (i == -1)
{
PyErr_SetString(PyExc_ValueError, "not found");
return NULL;
}
return PyInt_FromLong(i);
}
PyObject* Obarr_find(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
long i;
PyObject* other_in = NULL;
if (!PyArg_ParseTuple(args, "O", &other_in))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
i = obarr_find(self, other_in);
return PyInt_FromLong(i);
}
int compare_doubles(const void *a, const void *b)
{
const sortkey *sa = (const sortkey*)a;
const sortkey *sb = (const sortkey*)b;
return (sa->d > sb->d) - (sa->d < sb->d);
}
PyObject* Obarr_sort(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
ObarrObject* other = NULL;
PyObject* other_in = NULL;
PyObject* pyfloat = NULL;
sortkey* pSortkeys = NULL;
PyObject** pNewData = NULL;
long i;
if (!PyArg_ParseTuple(args, "O!", &ObarrObjectType, &other_in))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
other = (ObarrObject*)other_in;
if (other->nSize != self->nSize)
{
PyErr_SetString(PyExc_ValueError, "array to sort by must be the same size");
return NULL;
}
pSortkeys = malloc(sizeof(sortkey) * self->nSize);
if (!pSortkeys)
{
PyErr_SetString(PyExc_MemoryError, "insufficient free memory");
return NULL;
}
for (i = 0; i < self->nSize; i++)
{
pyfloat = other->pData[i];
if (!PyFloat_Check(pyfloat))
{
PyErr_SetString(PyExc_TypeError, "array to sort by must contain only floats");
return NULL;
}
pSortkeys[i].d = PyFloat_AsDouble(pyfloat);
pSortkeys[i].i = i;
}
qsort(pSortkeys, self->nSize, sizeof(sortkey), compare_doubles);
pNewData = malloc(self->nAllocSize * sizeof(void*));
if (!pNewData)
{
PyErr_SetString(PyExc_MemoryError, "insufficient free memory");
return NULL;
}
memcpy(pNewData, self->pData, self->nAllocSize * sizeof(void*));
for (i = 0; i < self->nSize; i++)
{
pNewData[i] = self->pData[pSortkeys[i].i];
}
free(pSortkeys);
free(self->pData);
self->pData = pNewData;
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Obarr_append(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
PyObject* other_in = NULL;
long index;
int r;
if (!PyArg_ParseTuple(args, "O", &other_in))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
index = self->nSize;
r = obarr_set_size(self, self->nSize + 1);
if (!r)
{
PyErr_SetString(PyExc_MemoryError, "insufficient free memory");
return NULL;
}
obarr_set_element(self, index, other_in);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Obarr_resize(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
long newsize;
int r;
if (!PyArg_ParseTuple(args, "l", &newsize))
{
PyErr_SetString(PyExc_TypeError, "wrong arguments");
return NULL;
}
r = obarr_set_size(self, newsize);
if (!r)
{
PyErr_SetString(PyExc_MemoryError, "insufficient free memory");
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Obarr_clear(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
obarr_empty(self);
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Obarr_debug(PyObject* self_in, PyObject* args)
{
ObarrObject* self = (ObarrObject*)self_in;
printf("AllocSize: %d\n", self->nAllocSize);
printf("Chunk: %d\n", self->nChunkSize);
printf("Size: %d\n", self->nSize);
Py_INCREF(Py_None);
return Py_None;
}
/* Python object definition structures */
PySequenceMethods Obarr_as_seq[] = {
Obarr_len, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
Obarr_item, /* sq_item */
0, /* sq_slice */
Obarr_setitem, /* sq_ass_item */
0, /* sq_ass_slice */
Obarr_contains, /* sq_contains */
};
PyMethodDef Obarr_methods[] = {
{"resize", (PyCFunction)Obarr_resize, METH_VARARGS, "allocate the array to a new size"},
{"clear", (PyCFunction)Obarr_clear, METH_NOARGS, "delete everything in the array"},
{"append", (PyCFunction)Obarr_append, METH_VARARGS, "append the object to the array"},
{"find", (PyCFunction)Obarr_find, METH_VARARGS, "find the index of an object in the array"},
{"index", (PyCFunction)Obarr_index, METH_VARARGS, "find the index of an object in the array"},
{"debug", (PyCFunction)Obarr_debug, METH_NOARGS, "debug"},
{"delete", (PyCFunction)Obarr_delete, METH_VARARGS, "delete a specific index in the array"},
{"remove", (PyCFunction)Obarr_remove, METH_VARARGS, "remove an object from the array"},
{"sort", (PyCFunction)Obarr_sort, METH_VARARGS, "sorts the array using another obarr of floats as sortkeys"},
{NULL}
};
struct PyMemberDef Obarr_members[] = {
/*{"x", T_OBJECT_EX, offsetof(ObarrObject, x), 0, "x"},
{"y", T_OBJECT_EX, offsetof(ObarrObject, y), 0, "y"},
{"z", T_OBJECT_EX, offsetof(ObarrObject, z), 0, "z"},*/
{NULL} /* Sentinel */
};
PyTypeObject ObarrObjectType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"py3dutil.obarr", /* tp_name */
sizeof(ObarrObject), /* tp_basicsize */
0, /* tp_itemsize */
Obarr_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
Obarr_repr, /* tp_repr */
0, /* tp_as_number */
Obarr_as_seq, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
"Vector objects are simple.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Obarr_methods, /* tp_methods */
Obarr_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Obarr_init, /* tp_init */
};