#include "Python.h" #include "Numeric/arrayobject.h" #define SEARCH_LOOP(OP, INC) { \ for (i = start_addr; i != end_addr; INC) { \ if (*i OP value) { \ return (void*)i; \ } \ } \ return (void*)0; } #define SWITCH_ON_OP(TYPE, INC) { \ TYPE* i; \ switch (op) { \ case EQ: \ SEARCH_LOOP(==, INC) \ case GT: \ SEARCH_LOOP(>, INC) \ case GTE: \ SEARCH_LOOP(>=, INC) \ case LT: \ SEARCH_LOOP(<, INC) \ case LTE: \ SEARCH_LOOP(<=, INC) \ case NEQ: \ SEARCH_LOOP(!=, INC) \ default: \ return (void*)0; \ } \ } #define SWITCH_ON_STRIDE(TYPE) { \ if (stride > 0) \ { \ SWITCH_ON_OP(TYPE, i++) \ } \ else \ { \ SWITCH_ON_OP(TYPE, i--) \ } \ } enum comp_operators { EQ, GT, GTE, LT, LTE, NEQ }; static void* array_find_byte(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { char value = (char)(PyInt_AsLong(searchval)); SWITCH_ON_STRIDE(char) } static void* array_find_short(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { short value = (short)(PyInt_AsLong(searchval)); SWITCH_ON_STRIDE(short) } static void* array_find_long(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { long value = PyInt_AsLong(searchval); SWITCH_ON_STRIDE(long) } static void* array_find_longlong(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { long long value = PyLong_AsLongLong(searchval); SWITCH_ON_STRIDE(long long) } static void* array_find_ubyte(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { unsigned char value = (unsigned char)(PyInt_AsUnsignedLongMask(searchval)); SWITCH_ON_STRIDE(unsigned char) } static void* array_find_ushort(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { unsigned short value = (unsigned short)(PyInt_AsUnsignedLongMask(searchval)); SWITCH_ON_STRIDE(unsigned short) } static void* array_find_ulong(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { unsigned long value = PyInt_AsUnsignedLongMask(searchval); SWITCH_ON_STRIDE(unsigned long) } static void* array_find_ulonglong(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { unsigned long long value = PyLong_AsUnsignedLongLong(searchval); SWITCH_ON_STRIDE(unsigned long long) } static void* array_find_float(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { float value = (float)(PyFloat_AsDouble(searchval)); SWITCH_ON_STRIDE(float) } static void* array_find_double(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op) { double value = PyFloat_AsDouble(searchval); SWITCH_ON_STRIDE(double) } static void* array_find_eq_string(char* value, void* start_addr, void* end_addr, int stride, int elsize) { char dest[elsize+1]; dest[elsize] = '\0'; void* i; for (i = start_addr; i != end_addr; i += stride) { memcpy((void*)dest, i, elsize); if (strcmp(dest, value) == 0) { return i; } } return 0; } static void* array_find_neq_string(char* value, void* start_addr, void* end_addr, int stride, int elsize) { char dest[elsize+1]; dest[elsize] = '\0'; void* i; for (i = start_addr; i != end_addr; i += stride) { memcpy((void*)dest, i, elsize); if (strcmp(dest, value) != 0) { return i; } } return 0; } static void* array_find_string(PyObject* searchval, void* start_addr, void* end_addr, int stride, int op, int elsize) { char* value = PyString_AsString(searchval); if (op == NEQ) { return array_find_neq_string(value, start_addr, end_addr, stride, elsize); } else { return array_find_eq_string(value, start_addr, end_addr, stride, elsize); } } static PyObject* multi_find(PyObject* self, PyObject* args, short direction) { PyArrayObject* arr; PyObject* value; short eqtest; int start, end; if (!PyArg_ParseTuple(args, "O!Ohii", &PyArray_Type, &arr, &value, &eqtest, &start, &end)) { return NULL; } char type = arr->descr->type; int elsize = arr->descr->elsize; int stride = arr->strides[0]; void* base_addr = PyArray_DATA(arr); void* start_addr; void* end_addr; int dirstride = stride; void* temp; if (stride > 0) { start_addr = base_addr + stride * start; end_addr = base_addr + stride * end; } else { start_addr = base_addr + stride * start; end_addr = base_addr + stride * end; } if (!direction) { temp = start_addr; //Shift by one place so we read the same set of data backwards start_addr = end_addr - stride; end_addr = temp - stride; dirstride = -1 * stride; } void* dest_addr; switch (type) { case 'b': dest_addr = array_find_byte(value, start_addr, end_addr, dirstride, eqtest); break; case 'h': dest_addr = array_find_short(value, start_addr, end_addr, dirstride, eqtest); break; case 'i': dest_addr = array_find_long(value, start_addr, end_addr, dirstride, eqtest); break; case 'l': dest_addr = array_find_long(value, start_addr, end_addr, dirstride, eqtest); break; case 'q': dest_addr = array_find_longlong(value, start_addr, end_addr, dirstride, eqtest); break; case 'B': dest_addr = array_find_ubyte(value, start_addr, end_addr, dirstride, eqtest); break; case 'H': dest_addr = array_find_ushort(value, start_addr, end_addr, dirstride, eqtest); break; case 'I': dest_addr = array_find_ulong(value, start_addr, end_addr, dirstride, eqtest); break; case 'L': dest_addr = array_find_ulong(value, start_addr, end_addr, dirstride, eqtest); break; case 'Q': dest_addr = array_find_ulonglong(value, start_addr, end_addr, dirstride, eqtest); break; case 'f': dest_addr = array_find_float(value, start_addr, end_addr, dirstride, eqtest); break; case 'd': dest_addr = array_find_double(value, start_addr, end_addr, dirstride, eqtest); break; case 'S': dest_addr = array_find_string(value, start_addr, end_addr, dirstride, eqtest, elsize); break; default: dest_addr = 0; } // printf("%s\t%s\t%d\t%d\t%p\t%p\t%p\t%p\n", &(arr->descr->kind), &type, elsize, dirstride, // base_addr, start_addr, end_addr, dest_addr); int dest_index; if (dest_addr > 0) { dest_index = (dest_addr - base_addr) / stride; } else { dest_index = -1; } return Py_BuildValue("i", dest_index); } static char py_find_doc[] = "Finds the first index of the occurrence of a value in an array."; static PyObject* py_find(PyObject* self, PyObject* args) { return multi_find(self, args, 1); } static char py_rfind_doc[] = "Finds the last index of the occurrence of a value in an array."; static PyObject* py_rfind(PyObject* self, PyObject* args) { return multi_find(self, args, 0); } static PyMethodDef _npfindmethods[] = { {"np_find", py_find, METH_VARARGS, py_find_doc}, {"np_rfind", py_rfind, METH_VARARGS, py_rfind_doc}, {NULL, NULL, 0, NULL} }; void init_npfind(void) { Py_InitModule("_npfind", _npfindmethods); import_array(); }