Fix leak in BPy_BMElem_PySeq_As_Array

Also add BPy_BMElem_PySeq_As_Array_FAST
This commit is contained in:
Campbell Barton 2015-07-29 09:55:34 +10:00
parent d226a4ba6d
commit 376e4c945e
2 changed files with 104 additions and 85 deletions

View File

@ -3759,106 +3759,120 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
*
* The 'bm_r' value is assigned when empty, and used when set.
*/
void *BPy_BMElem_PySeq_As_Array_FAST(
BMesh **r_bm, PyObject *seq_fast, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
const char htype,
const bool do_unique_check, const bool do_bm_check,
const char *error_prefix)
{
BMesh *bm = (r_bm && *r_bm) ? *r_bm : NULL;
const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast);
Py_ssize_t i;
BPy_BMElem *item;
BMElem **alloc;
*r_size = 0;
if (seq_len < min || seq_len > max) {
PyErr_Format(PyExc_TypeError,
"%s: sequence incorrect size, expected [%d - %d], given %d",
error_prefix, min, max, seq_len);
return NULL;
}
/* from now on, use goto */
alloc = PyMem_MALLOC(seq_len * sizeof(BPy_BMElem **));
for (i = 0; i < seq_len; i++) {
item = (BPy_BMElem *)PySequence_Fast_GET_ITEM(seq_fast, i);
if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) {
PyErr_Format(PyExc_TypeError,
"%s: expected %.200s, not '%.200s'",
error_prefix, BPy_BMElem_StringFromHType(htype), Py_TYPE(item)->tp_name);
goto err_cleanup;
}
else if (!BPY_BM_IS_VALID(item)) {
PyErr_Format(PyExc_TypeError,
"%s: %d %s has been removed",
error_prefix, i, Py_TYPE(item)->tp_name);
goto err_cleanup;
}
/* trick so we can ensure all items have the same mesh,
* and allows us to pass the 'bm' as NULL. */
else if (do_bm_check && (bm && bm != item->bm)) {
PyErr_Format(PyExc_ValueError,
"%s: %d %s is from another mesh",
error_prefix, i, BPy_BMElem_StringFromHType(htype));
goto err_cleanup;
}
if (bm == NULL) {
bm = item->bm;
}
alloc[i] = item->ele;
if (do_unique_check) {
BM_elem_flag_enable(item->ele, BM_ELEM_INTERNAL_TAG);
}
}
if (do_unique_check) {
/* check for double verts! */
bool ok = true;
for (i = 0; i < seq_len; i++) {
if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_INTERNAL_TAG) == false)) {
ok = false;
}
/* ensure we don't leave this enabled */
BM_elem_flag_disable(alloc[i], BM_ELEM_INTERNAL_TAG);
}
if (ok == false) {
PyErr_Format(PyExc_ValueError,
"%s: found the same %.200s used multiple times",
error_prefix, BPy_BMElem_StringFromHType(htype));
goto err_cleanup;
}
}
*r_size = seq_len;
if (r_bm) *r_bm = bm;
return alloc;
err_cleanup:
PyMem_FREE(alloc);
return NULL;
}
void *BPy_BMElem_PySeq_As_Array(
BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
const char htype,
const bool do_unique_check, const bool do_bm_check,
const char *error_prefix)
{
BMesh *bm = (r_bm && *r_bm) ? *r_bm : NULL;
PyObject *seq_fast;
*r_size = 0;
PyObject *ret;
if (!(seq_fast = PySequence_Fast(seq, error_prefix))) {
return NULL;
}
else {
Py_ssize_t seq_len;
Py_ssize_t i;
BPy_BMElem *item;
BMElem **alloc;
ret = BPy_BMElem_PySeq_As_Array_FAST(
r_bm, seq_fast, min, max, r_size,
htype,
do_unique_check, do_bm_check,
error_prefix);
seq_len = PySequence_Fast_GET_SIZE(seq_fast);
if (seq_len < min || seq_len > max) {
PyErr_Format(PyExc_TypeError,
"%s: sequence incorrect size, expected [%d - %d], given %d",
error_prefix, min, max, seq_len);
return NULL;
}
/* from now on, use goto */
alloc = PyMem_MALLOC(seq_len * sizeof(BPy_BMElem **));
for (i = 0; i < seq_len; i++) {
item = (BPy_BMElem *)PySequence_Fast_GET_ITEM(seq_fast, i);
if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) {
PyErr_Format(PyExc_TypeError,
"%s: expected %.200s, not '%.200s'",
error_prefix, BPy_BMElem_StringFromHType(htype), Py_TYPE(item)->tp_name);
goto err_cleanup;
}
else if (!BPY_BM_IS_VALID(item)) {
PyErr_Format(PyExc_TypeError,
"%s: %d %s has been removed",
error_prefix, i, Py_TYPE(item)->tp_name);
goto err_cleanup;
}
/* trick so we can ensure all items have the same mesh,
* and allows us to pass the 'bm' as NULL. */
else if (do_bm_check && (bm && bm != item->bm)) {
PyErr_Format(PyExc_ValueError,
"%s: %d %s is from another mesh",
error_prefix, i, BPy_BMElem_StringFromHType(htype));
goto err_cleanup;
}
if (bm == NULL) {
bm = item->bm;
}
alloc[i] = item->ele;
if (do_unique_check) {
BM_elem_flag_enable(item->ele, BM_ELEM_INTERNAL_TAG);
}
}
if (do_unique_check) {
/* check for double verts! */
bool ok = true;
for (i = 0; i < seq_len; i++) {
if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_INTERNAL_TAG) == false)) {
ok = false;
}
/* ensure we don't leave this enabled */
BM_elem_flag_disable(alloc[i], BM_ELEM_INTERNAL_TAG);
}
if (ok == false) {
PyErr_Format(PyExc_ValueError,
"%s: found the same %.200s used multiple times",
error_prefix, BPy_BMElem_StringFromHType(htype));
goto err_cleanup;
}
}
Py_DECREF(seq_fast);
*r_size = seq_len;
if (r_bm) *r_bm = bm;
return alloc;
err_cleanup:
Py_DECREF(seq_fast);
PyMem_FREE(alloc);
return NULL;
}
Py_DECREF(seq_fast);
return ret;
}
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len)
{
Py_ssize_t i;

View File

@ -158,6 +158,11 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele); /* just checks type and creates v/e/f/l */
void *BPy_BMElem_PySeq_As_Array_FAST(
BMesh **r_bm, PyObject *seq_fast, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
const char htype,
const bool do_unique_check, const bool do_bm_check,
const char *error_prefix);
void *BPy_BMElem_PySeq_As_Array(
BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
const char htype,