diff --git a/qrenderdoc/Code/pyrenderdoc/container_handling.h b/qrenderdoc/Code/pyrenderdoc/container_handling.h index 8a11fac4b..b0ce99819 100644 --- a/qrenderdoc/Code/pyrenderdoc/container_handling.h +++ b/qrenderdoc/Code/pyrenderdoc/container_handling.h @@ -214,8 +214,23 @@ fail: template PyObject *array_sort(arrayType *thisptr, PyObject *key, bool reverse) { - // TODO - implement sort + typedef typename arrayType::value_type val; + if(key) + { + SWIG_exception_fail(SWIG_RuntimeError, "key sort is not supported on rdcarray"); + } + else + { + std::sort(thisptr->begin(), thisptr->end(), [](const val &a, const val &b) { return a < b; }); + } + + if(reverse) + array_reverse(thisptr); + return SWIG_Py_Void(); + +fail: + return NULL; } template @@ -292,3 +307,385 @@ PyObject *array_pop(arrayType *thisptr, PyObject *index) fail: return NULL; } + +template +PyObject *array_indexOf(arrayType *thisptr, PyObject *item, PyObject *start, PyObject *end) +{ + typename arrayType::value_type converted; + int res = 0; + + size_t startIdx = 0; + size_t endIdx = ~0U; + + if(start) + { + if(!PyLong_Check(start)) + { + SWIG_exception_fail(SWIG_TypeError, "start index is not an integer"); + } + + startIdx = (size_t)PyLong_AsLong(start); + } + + if(end) + { + if(!PyLong_Check(end)) + { + SWIG_exception_fail(SWIG_TypeError, "end index is not an integer"); + } + endIdx = (size_t)PyLong_AsLong(end); + } + + res = ConvertFromPy(item, converted); + + if(SWIG_IsOK(res)) + { + int idx = thisptr->indexOf(converted, startIdx, endIdx); + + if(idx < 0) + { + SWIG_exception_fail(SWIG_ValueError, "item is not in list"); + } + + return PyLong_FromLong(idx); + } + + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in index"); +fail: + return NULL; +} + +template +PyObject *array_countOf(arrayType *thisptr, PyObject *item) +{ + typename arrayType::value_type converted; + int res = ConvertFromPy(item, converted); + + if(SWIG_IsOK(res)) + { + int count = 0; + + for(size_t i = 0; i < thisptr->size(); i++) + if(thisptr->at(i) == converted) + count++; + + return PyLong_FromLong(count); + } + + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in count"); +fail: + return NULL; +} + +template +PyObject *array_removeOne(arrayType *thisptr, PyObject *item) +{ + typename arrayType::value_type converted; + int res = ConvertFromPy(item, converted); + + if(SWIG_IsOK(res)) + { + int idx = thisptr->indexOf(converted); + + if(idx < 0) + { + SWIG_exception_fail(SWIG_ValueError, "item is not in list"); + } + + thisptr->erase(idx); + + return SWIG_Py_Void(); + } + + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in remove"); +fail: + return NULL; +} + +template +PyObject *array_concat(arrayType *thisptr, PyObject *items) +{ + Py_ssize_t count = 0; + PyObject *list = NULL; + PyObject *ret = NULL; + + if(!PySequence_Check(items)) + SWIG_exception_fail(SWIG_TypeError, "can't concatenate non-sequence"); + + list = PyList_New(0); + if(!list) + return NULL; + + for(size_t i = 0; i < thisptr->size(); i++) + { + ret = ConvertToPy(thisptr->at(i)); + + PyList_Append(list, ret); + + if(!ret) + SWIG_exception_fail(SWIG_TypeError, "failed to convert element while copying"); + } + + count = PySequence_Size(items); + + for(Py_ssize_t i = 0; i < count; i++) + { + PyObject *item = PySequence_GetItem(items, i); + PyList_Append(list, item); + Py_DECREF(item); + } + + return list; +fail: + if(list) + Py_XDECREF(list); + + return NULL; +} + +template +PyObject *array_selfconcat(arrayType *thisptr, PyObject *items) +{ + typename arrayType::value_type converted; + int res = 0; + Py_ssize_t count = 0; + + if(!PySequence_Check(items)) + SWIG_exception_fail(SWIG_TypeError, "can't concatenate non-sequence"); + + count = PySequence_Size(items); + + for(Py_ssize_t i = 0; i < count; i++) + { + PyObject *item = PySequence_GetItem(items, i); + res = ConvertFromPy(item, converted); + + if(SWIG_IsOK(res)) + thisptr->push_back(converted); + + Py_DECREF(item); + + if(!SWIG_IsOK(res)) + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in extend"); + } + + return SWIG_Py_Void(); + +fail: + return NULL; +} + +template +PyObject *array_repeat(arrayType *thisptr, Py_ssize_t count) +{ + PyObject *list = PyList_New(0); + if(!list) + return NULL; + + if(count <= 0 || thisptr->empty()) + { + return list; + } + + PyObject *ret = NULL; + rdcarray converted; + + for(size_t i = 0; i < thisptr->size(); i++) + { + ret = ConvertToPy(thisptr->at(i)); + + converted.push_back(ret); + + if(!ret) + SWIG_exception_fail(SWIG_TypeError, "failed to convert element while copying"); + } + + for(Py_ssize_t c = 0; c < count; c++) + for(size_t i = 0; i < converted.size(); i++) + PyList_Append(list, converted[i]); + + return list; +fail: + if(list) + Py_XDECREF(list); + + return NULL; +} + +template +PyObject *array_selfrepeat(arrayType *thisptr, Py_ssize_t count) +{ + if(count <= 0 || thisptr->empty()) + { + thisptr->clear(); + return SWIG_Py_Void(); + } + + size_t origCount = thisptr->size(); + + thisptr->reserve(origCount * count); + for(Py_ssize_t i = 0; i < count - 1; i++) + { + thisptr->append(thisptr->data(), origCount); + } + + return SWIG_Py_Void(); +} + +template +PyObject *array_getsubscript(arrayType *thisptr, PyObject *idxobj) +{ + if(PyIndex_Check(idxobj)) + { + Py_ssize_t idx = array_revindex(thisptr, idxobj); + + // if an error occurred an exception has been thrown, just return NULL + if(idx == PY_SSIZE_T_MIN) + return NULL; + + return array_getitem(thisptr, idx); + } + + if(PySlice_Check(idxobj)) + { + int len = thisptr->count(); + Py_ssize_t start, stop, step, slicelength; + + if(PySlice_GetIndicesEx(idxobj, len, &start, &stop, &step, &slicelength) < 0) + return NULL; + + PyObject *list = PyList_New(0); + if(!list) + return NULL; + + PyObject *ret = NULL; + + for(int i = start, count = 0; count < slicelength; i += step, count++) + { + ret = ConvertToPy(thisptr->at(i)); + + PyList_Append(list, ret); + + if(!ret) + { + Py_DECREF(list); + SWIG_exception_fail(SWIG_TypeError, "failed to convert element while getting slice"); + } + } + + return list; + } + + SWIG_exception_fail(SWIG_TypeError, "list index not index or slice"); + +fail: + return NULL; +} + +template +int array_setsubscript(arrayType *thisptr, PyObject *idxobj, PyObject *val) +{ + typename arrayType::value_type converted; + int res = 0; + + if(PyIndex_Check(idxobj)) + { + Py_ssize_t idx = array_revindex(thisptr, idxobj); + + // if an error occurred an exception has been thrown, just return NULL + if(idx == PY_SSIZE_T_MIN) + return -1; + + return array_setitem(thisptr, idx, val); + } + + if(PySlice_Check(idxobj)) + { + int len = thisptr->count(); + Py_ssize_t start, stop, step, slicelength; + + if(PySlice_GetIndicesEx(idxobj, len, &start, &stop, &step, &slicelength) < 0) + { + return -1; + } + + if(val == NULL) + { + // we're deleting this slice. Erase all the indices + + for(int i = start, count = 0; count < slicelength; i += step, count++) + { + int idx = i; + + // if we're stepping forwards, erasing the earlier indices will have moved the ones to + // delete, so adjust the index based on how many we've deleted. + // if we're stepping backwards then there's no need to change anything + if(step > 1) + idx -= count; + + ExtRefcount::Dec(thisptr->at(idx)); + thisptr->erase(idx); + } + } + else + { + // we must be assigning an iterable object + if(!PySequence_Check(val)) + { + SWIG_exception_fail(SWIG_TypeError, "can only assign an iterable"); + } + + Py_ssize_t vallen = PySequence_Size(val); + + // if the range isn't contiguous or reversed or something, the input size must match + if(step != 1) + { + if(slicelength != vallen) + { + SWIG_exception_fail(SWIG_ValueError, + "can't assign sequence of different size to extended slice"); + } + + for(int i = start, count = 0; count < slicelength; i += step, count++) + { + // dec refcount on previous item in this index + ExtRefcount::Dec(thisptr->at(i)); + + // convert the input item + PyObject *item = PySequence_GetItem(val, count); + res = ConvertFromPy(item, thisptr->at(i)); + Py_DECREF(item); + + if(!SWIG_IsOK(res)) + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in slice set"); + } + } + else + { + // the range is contiguous. First erase it, dec refcount if needed + for(int i = start; i < start + slicelength; i++) + ExtRefcount::Dec(thisptr->at(i)); + thisptr->erase(start, slicelength); + + // then insert the new items + for(Py_ssize_t count = 0; count < vallen; count++) + { + PyObject *item = PySequence_GetItem(val, count); + res = ConvertFromPy(item, converted); + Py_DECREF(item); + + if(!SWIG_IsOK(res)) + SWIG_exception_fail(SWIG_ArgError(res), "failed to convert element in slice set"); + + thisptr->insert(count + start, converted); + } + } + } + + return 0; + } + + SWIG_exception_fail(SWIG_TypeError, "list index not index or slice"); +fail: + return -1; +} \ No newline at end of file diff --git a/qrenderdoc/Code/pyrenderdoc/container_handling.i b/qrenderdoc/Code/pyrenderdoc/container_handling.i index 1c23326e0..8bb458ab0 100644 --- a/qrenderdoc/Code/pyrenderdoc/container_handling.i +++ b/qrenderdoc/Code/pyrenderdoc/container_handling.i @@ -94,6 +94,7 @@ // overloads %feature("kwargs") pop; %feature("kwargs") sort; + %feature("kwargs") index; PyObject *append(PyObject *value) { @@ -130,13 +131,25 @@ return array_reverse($self); } - /* -// named functions to implement for list compatibility -index(x[, start[, end]]); // Return zero-based index in the list of the first item whose value is x -count(value); // Return the number of times x appears in the list. -extend(iterable); // Extend the list by appending all the items from the iterable -remove(x); // Remove the first item from the list whose value is x. -*/ + PyObject *index(PyObject *item, PyObject *start = NULL, PyObject *end = NULL) + { + return array_indexOf($self, item, start, end); + } + + PyObject *count(PyObject *item) + { + return array_countOf($self, item); + } + + PyObject *extend(PyObject *items) + { + return array_selfconcat($self, items); + } + + PyObject *remove(PyObject *item) + { + return array_removeOne($self, item); + } } // %extend Container %enddef // define EXTEND_ARRAY_CLASS_METHODS(Container) @@ -149,27 +162,18 @@ remove(x); // Remove the first item from the list whose value is x. %feature("python:sq_item") array_type STRINGIZE(getitem_##unique_name); %feature("python:sq_ass_item") array_type STRINGIZE(setitem_##unique_name); %feature("python:sq_length") array_type STRINGIZE(length_##unique_name); +%feature("python:sq_concat") array_type STRINGIZE(concat_##unique_name); +%feature("python:sq_repeat") array_type STRINGIZE(repeat_##unique_name); +%feature("python:sq_inplace_concat") array_type STRINGIZE(selfconcat_##unique_name); +%feature("python:sq_inplace_repeat") array_type STRINGIZE(selfrepeat_##unique_name); +%feature("python:mp_subscript") array_type STRINGIZE(getsubscript_##unique_name); +%feature("python:mp_ass_subscript") array_type STRINGIZE(setsubscript_##unique_name); // https://docs.python.org/3/library/collections.abc.html // https://docs.python.org/3/library/stdtypes.html#typesseq-common // https://docs.python.org/3/library/stdtypes.html#typesseq-mutable // https://docs.python.org/3/library/stdtypes.html#list -/* -// slots to implement for list compatibility -slice retrieve -binaryfunc mp_subscript; - -slice set/delete -objobjargproc mp_ass_subscript; - -concat/repeat -binaryfunc sq_concat; -ssizeargfunc sq_repeat; -binaryfunc sq_inplace_concat; -ssizeargfunc sq_inplace_repeat; -*/ - %enddef // define C exported wrappers to bind to the slots that forward to templated implementations @@ -216,6 +220,84 @@ int length_##unique_name(PyObject *self, Py_ssize_t idx, PyObject *val) return array_len(thisptr); } + +PyObject *getsubscript_##unique_name(PyObject *self, PyObject *idx) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return NULL; + + return array_getsubscript(thisptr, idx); +} + +int setsubscript_##unique_name(PyObject *self, PyObject *idx, PyObject *val) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return -1; + + return array_setsubscript(thisptr, idx, val); +} + +PyObject *concat_##unique_name(PyObject *self, PyObject *vals) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return NULL; + + return array_concat(thisptr, vals); +} + +PyObject *repeat_##unique_name(PyObject *self, Py_ssize_t count) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return NULL; + + return array_repeat(thisptr, count); +} + +PyObject *selfconcat_##unique_name(PyObject *self, PyObject *vals) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return NULL; + + PyObject *ret = array_selfconcat(thisptr, vals); + + if(ret) + { + Py_DECREF(ret); + Py_INCREF(self); + return self; + } + + return NULL; +} + +PyObject *selfrepeat_##unique_name(PyObject *self, Py_ssize_t count) +{ + array_type *thisptr = array_thisptr(self); + + if(!thisptr) + return NULL; + + PyObject *ret = array_selfrepeat(thisptr, count); + + if(ret) + { + Py_DECREF(ret); + Py_INCREF(self); + return self; + } + + return NULL; +} %} %enddef diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i index 97e444c52..efbca2fd4 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -76,6 +76,8 @@ TEMPLATE_ARRAY_DECLARE(rdcarray); %include "Code/Interface/PersistantConfig.h" %include "Code/Interface/RemoteHost.h" +DOCUMENT(""); + TEMPLATE_ARRAY_INSTANTIATE(rdcarray, EventBookmark) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SPIRVDisassembler) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BoundBuffer) diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 480847c55..7e05b9e8b 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -172,10 +172,11 @@ TEMPLATE_ARRAY_DECLARE(rdcarray); %feature("docstring") ""; %extend rdcarray { - // we ignored insert, append and clear before, need to restore them so we can declare our own impls + // we ignored some functions before, need to restore them so we can declare our own impls %rename("%s") insert; %rename("%s") append; %rename("%s") clear; + %rename("%s") count; } // add python array members that aren't in slots