RNA: Add missing raw types for DNA types #115761

Merged
Brecht Van Lommel merged 7 commits from Mysteryem/blender:fix_missing_raw_types_pr into main 2024-01-10 18:19:33 +01:00
6 changed files with 173 additions and 17 deletions

View File

@ -446,6 +446,11 @@ enum RawPropertyType {
PROP_RAW_BOOLEAN,
PROP_RAW_DOUBLE,
PROP_RAW_FLOAT,
PROP_RAW_UINT8,
PROP_RAW_UINT16,
PROP_RAW_INT64,
PROP_RAW_UINT64,
PROP_RAW_INT8,
};
struct RawArray {

View File

@ -1967,10 +1967,22 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop)
prop->rawtype = PROP_RAW_CHAR;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "int8_t")) {
prop->rawtype = PROP_RAW_INT8;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "uchar")) {
prop->rawtype = PROP_RAW_UINT8;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "short")) {
prop->rawtype = PROP_RAW_SHORT;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "ushort")) {
prop->rawtype = PROP_RAW_UINT16;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "int")) {
prop->rawtype = PROP_RAW_INT;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
@ -1983,6 +1995,14 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop)
prop->rawtype = PROP_RAW_DOUBLE;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "int64_t")) {
prop->rawtype = PROP_RAW_INT64;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "uint64_t")) {
prop->rawtype = PROP_RAW_UINT64;
prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
}
static void rna_set_raw_offset(FILE *f, StructRNA *srna, PropertyRNA *prop)

View File

@ -4502,9 +4502,18 @@ int RNA_property_collection_raw_array(
case PROP_RAW_CHAR: \
var = (dtype)((char *)raw.array)[a]; \
break; \
case PROP_RAW_INT8: \
var = (dtype)((int8_t *)raw.array)[a]; \
break; \
case PROP_RAW_UINT8: \
var = (dtype)((uint8_t *)raw.array)[a]; \
break; \
case PROP_RAW_SHORT: \
var = (dtype)((short *)raw.array)[a]; \
break; \
case PROP_RAW_UINT16: \
var = (dtype)((uint16_t *)raw.array)[a]; \
break; \
case PROP_RAW_INT: \
var = (dtype)((int *)raw.array)[a]; \
break; \
@ -4517,6 +4526,12 @@ int RNA_property_collection_raw_array(
case PROP_RAW_DOUBLE: \
var = (dtype)((double *)raw.array)[a]; \
break; \
case PROP_RAW_INT64: \
var = (dtype)((int64_t *)raw.array)[a]; \
break; \
case PROP_RAW_UINT64: \
var = (dtype)((uint64_t *)raw.array)[a]; \
break; \
default: \
var = (dtype)0; \
} \
@ -4529,9 +4544,18 @@ int RNA_property_collection_raw_array(
case PROP_RAW_CHAR: \
((char *)raw.array)[a] = char(var); \
break; \
case PROP_RAW_INT8: \
((int8_t *)raw.array)[a] = int8_t(var); \
break; \
case PROP_RAW_UINT8: \
((uint8_t *)raw.array)[a] = uint8_t(var); \
break; \
case PROP_RAW_SHORT: \
((short *)raw.array)[a] = short(var); \
break; \
case PROP_RAW_UINT16: \
((uint16_t *)raw.array)[a] = uint16_t(var); \
break; \
case PROP_RAW_INT: \
((int *)raw.array)[a] = int(var); \
break; \
@ -4544,6 +4568,12 @@ int RNA_property_collection_raw_array(
case PROP_RAW_DOUBLE: \
((double *)raw.array)[a] = double(var); \
break; \
case PROP_RAW_INT64: \
((int64_t *)raw.array)[a] = int64_t(var); \
break; \
case PROP_RAW_UINT64: \
((uint64_t *)raw.array)[a] = uint64_t(var); \
break; \
default: \
break; \
} \
@ -4555,8 +4585,14 @@ int RNA_raw_type_sizeof(RawPropertyType type)
switch (type) {
case PROP_RAW_CHAR:
return sizeof(char);
case PROP_RAW_INT8:
return sizeof(int8_t);
case PROP_RAW_UINT8:
return sizeof(uint8_t);
case PROP_RAW_SHORT:
return sizeof(short);
case PROP_RAW_UINT16:
return sizeof(uint16_t);
case PROP_RAW_INT:
return sizeof(int);
case PROP_RAW_BOOLEAN:
@ -4565,6 +4601,10 @@ int RNA_raw_type_sizeof(RawPropertyType type)
return sizeof(float);
case PROP_RAW_DOUBLE:
return sizeof(double);
case PROP_RAW_INT64:
return sizeof(int64_t);
case PROP_RAW_UINT64:
return sizeof(uint64_t);
default:
return 0;
}

View File

@ -1636,6 +1636,32 @@ bool PyC_RunString_AsString(const char *imports[],
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
/* #PyLong_AsUnsignedLong, unlike #PyLong_AsLong, does not fall back to calling #PyNumber_Index
* when its argument is not a `PyLongObject` instance. To match parsing signed integer types with
* #PyLong_AsLong, this function performs the #PyNumber_Index fallback, if necessary, before
* calling #PyLong_AsUnsignedLong. */
static ulong pyc_Long_AsUnsignedLong(PyObject *value)
{
if (value == nullptr) {
/* Let PyLong_AsUnsignedLong handle error raising. */
return PyLong_AsUnsignedLong(value);
}
if (PyLong_Check(value)) {
return PyLong_AsUnsignedLong(value);
}
/* Call `__index__` like PyLong_AsLong. */
PyObject *value_converted = PyNumber_Index(value);
if (value_converted == nullptr) {
/* A `TypeError` will have been raised. */
return ulong(-1);
}
ulong to_return = PyLong_AsUnsignedLong(value_converted);
Py_DECREF(value_converted);
return to_return;
}
int PyC_Long_AsBool(PyObject *value)
{
const int test = _PyLong_AsInt(value);
@ -1682,7 +1708,7 @@ int16_t PyC_Long_AsI16(PyObject *value)
uint8_t PyC_Long_AsU8(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
const ulong test = pyc_Long_AsUnsignedLong(value);
if (UNLIKELY(test == ulong(-1) && PyErr_Occurred())) {
return uint8_t(-1);
}
@ -1695,7 +1721,7 @@ uint8_t PyC_Long_AsU8(PyObject *value)
uint16_t PyC_Long_AsU16(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
const ulong test = pyc_Long_AsUnsignedLong(value);
if (UNLIKELY(test == ulong(-1) && PyErr_Occurred())) {
return uint16_t(-1);
}
@ -1708,7 +1734,7 @@ uint16_t PyC_Long_AsU16(PyObject *value)
uint32_t PyC_Long_AsU32(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
const ulong test = pyc_Long_AsUnsignedLong(value);
if (UNLIKELY(test == ulong(-1) && PyErr_Occurred())) {
return uint32_t(-1);
}
@ -1719,9 +1745,32 @@ uint32_t PyC_Long_AsU32(PyObject *value)
return uint32_t(test);
}
/* Inlined in header:
* PyC_Long_AsU64
*/
/* #PyLong_AsUnsignedLongLong, unlike #PyLong_AsLongLong, does not fall back to calling
* #PyNumber_Index when its argument is not a `PyLongObject` instance. To match parsing signed
* integer types with #PyLong_AsLongLong, this function performs the #PyNumber_Index fallback, if
* necessary, before calling #PyLong_AsUnsignedLongLong. */
uint64_t PyC_Long_AsU64(PyObject *value)
{
if (value == nullptr) {
/* Let PyLong_AsUnsignedLongLong handle error raising. */
return uint64_t(PyLong_AsUnsignedLongLong(value));
}
if (PyLong_Check(value)) {
return uint64_t(PyLong_AsUnsignedLongLong(value));
}
/* Call `__index__` like PyLong_AsLongLong. */
PyObject *value_converted = PyNumber_Index(value);
if (value_converted == nullptr) {
/* A `TypeError` will have been raised. */
return uint64_t(-1);
}
uint64_t to_return = uint64_t(PyLong_AsUnsignedLongLong(value_converted));
Py_DECREF(value_converted);
return to_return;
}
#ifdef __GNUC__
# pragma warning(pop)

View File

@ -302,12 +302,14 @@ int32_t PyC_Long_AsI32(PyObject *value);
int64_t PyC_Long_AsI64(PyObject *value);
#endif
/* Unlike Python's #PyLong_AsUnsignedLong and #PyLong_AsUnsignedLongLong, these unsigned integer
* parsing functions fall back to calling #PyNumber_Index when their argument is not a
* `PyLongObject`. This matches Python's signed integer parsing functions which also fall back to
* calling #PyNumber_Index. */
uint8_t PyC_Long_AsU8(PyObject *value);
uint16_t PyC_Long_AsU16(PyObject *value);
uint32_t PyC_Long_AsU32(PyObject *value);
#if 0 /* inline */
uint64_t PyC_Long_AsU64(PyObject *value);
#endif
/* inline so type signatures match as expected */
Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value)
@ -318,10 +320,6 @@ Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value)
{
return (int64_t)PyLong_AsLongLong(value);
}
Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value)
{
return (uint64_t)PyLong_AsUnsignedLongLong(value);
}
/* utils for format string in `struct` module style syntax */
char PyC_StructFmt_type_from_str(const char *typestr);

View File

@ -5390,13 +5390,16 @@ static bool foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, con
const char f = format ? *format : 'B'; /* B is assumed when not set */
switch (raw_type) {
case PROP_RAW_CHAR:
case PROP_RAW_INT8:
if (attr_signed) {
return (f == 'b') ? true : false;
}
else {
return (f == 'B') ? true : false;
}
case PROP_RAW_CHAR:
case PROP_RAW_UINT8:
return (f == 'B') ? true : false;
case PROP_RAW_SHORT:
if (attr_signed) {
return (f == 'h') ? true : false;
@ -5404,6 +5407,8 @@ static bool foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, con
else {
return (f == 'H') ? true : false;
}
case PROP_RAW_UINT16:
return (f == 'H') ? true : false;
case PROP_RAW_INT:
if (attr_signed) {
return (f == 'i') ? true : false;
@ -5417,6 +5422,15 @@ static bool foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, con
return (f == 'f') ? true : false;
case PROP_RAW_DOUBLE:
return (f == 'd') ? true : false;
case PROP_RAW_INT64:
if (attr_signed) {
return (f == 'q') ? true : false;
}
else {
return (f == 'Q') ? true : false;
}
case PROP_RAW_UINT64:
return (f == 'Q') ? true : false;
case PROP_RAW_UNSET:
return false;
}
@ -5487,16 +5501,25 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
item = PySequence_GetItem(seq, i);
switch (raw_type) {
case PROP_RAW_CHAR:
((char *)array)[i] = char(PyLong_AsLong(item));
((char *)array)[i] = char(PyC_Long_AsU8(item));
break;
case PROP_RAW_INT8:
((int8_t *)array)[i] = PyC_Long_AsI8(item);
break;
case PROP_RAW_UINT8:
((uint8_t *)array)[i] = PyC_Long_AsU8(item);
break;
case PROP_RAW_SHORT:
((short *)array)[i] = short(PyLong_AsLong(item));
((short *)array)[i] = short(PyC_Long_AsI16(item));
break;
case PROP_RAW_UINT16:
((uint16_t *)array)[i] = PyC_Long_AsU16(item);
break;
case PROP_RAW_INT:
((int *)array)[i] = int(PyLong_AsLong(item));
((int *)array)[i] = int(PyC_Long_AsI32(item));
break;
case PROP_RAW_BOOLEAN:
((bool *)array)[i] = int(PyLong_AsLong(item)) != 0;
((bool *)array)[i] = bool(PyC_Long_AsBool(item));
Review

I think it may be better to revert the change to bool parsing here because there is the py_capi_utils.h#PyC_AsArray() function, which is a good candidate for replacing the conversion from Python sequence to array here, and its bool parsing matches the existing int(PyLong_AsLong(item)) != 0 rather than using #PyC_Long_AsBool(). Reverting this change to bool parsing should make any future transition to using #PyC_AsArray() easier.

Edit: Or maybe not. While #PyC_AsArray() is faster for List/Tuple inputs, it appears to be slower for other sequences, such as NumPy ndarray, array.array and memoryview.

I think it may be better to revert the change to bool parsing here because there is the `py_capi_utils.h#PyC_AsArray()` function, which is a good candidate for replacing the conversion from Python sequence to array here, and its bool parsing matches the existing `int(PyLong_AsLong(item)) != 0` rather than using `#PyC_Long_AsBool()`. Reverting this change to bool parsing should make any future transition to using `#PyC_AsArray()` easier. Edit: Or maybe not. While `#PyC_AsArray()` is faster for `List`/`Tuple` inputs, it appears to be slower for other sequences, such as NumPy ndarray, array.array and memoryview.
break;
case PROP_RAW_FLOAT:
((float *)array)[i] = float(PyFloat_AsDouble(item));
@ -5504,6 +5527,12 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
case PROP_RAW_DOUBLE:
((double *)array)[i] = double(PyFloat_AsDouble(item));
break;
case PROP_RAW_INT64:
((int64_t *)array)[i] = PyC_Long_AsI64(item);
break;
case PROP_RAW_UINT64:
((uint64_t *)array)[i] = PyC_Long_AsU64(item);
break;
case PROP_RAW_UNSET:
/* Should never happen. */
BLI_assert_msg(0, "Invalid array type - set");
@ -5558,9 +5587,18 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
case PROP_RAW_CHAR:
item = PyLong_FromLong(long(((char *)array)[i]));
break;
case PROP_RAW_INT8:
item = PyLong_FromLong(long(((int8_t *)array)[i]));
break;
case PROP_RAW_UINT8:
item = PyLong_FromLong(long(((uint8_t *)array)[i]));
break;
case PROP_RAW_SHORT:
item = PyLong_FromLong(long(((short *)array)[i]));
break;
case PROP_RAW_UINT16:
item = PyLong_FromLong(long(((uint16_t *)array)[i]));
break;
case PROP_RAW_INT:
item = PyLong_FromLong(long(((int *)array)[i]));
break;
@ -5573,6 +5611,12 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
case PROP_RAW_BOOLEAN:
item = PyBool_FromLong(long(((bool *)array)[i]));
break;
case PROP_RAW_INT64:
item = PyLong_FromLongLong(((int64_t *)array)[i]);
break;
case PROP_RAW_UINT64:
item = PyLong_FromUnsignedLongLong(((uint64_t *)array)[i]);
break;
default: /* PROP_RAW_UNSET */
/* Should never happen. */
BLI_assert_msg(0, "Invalid array type - get");