Blender V5.0
bpy_rna_array.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <Python.h>
12
13#include "CLG_log.h"
14
15#include "BLI_utildefines.h"
16
17#include "RNA_types.hh"
18
19#include "bpy_rna.hh"
20
21#include "MEM_guardedalloc.h"
22
23#include "RNA_access.hh"
24
25#include "BPY_extern_clog.hh"
26
28
29#define USE_MATHUTILS
30
31#ifdef USE_MATHUTILS
32# include "../mathutils/mathutils.hh" /* so we can have mathutils callbacks */
33#endif
34
35#define MAX_ARRAY_DIMENSION 10
36
38
39using ItemConvertFunc = void (*)(const ItemConvertArgData *arg, PyObject *py_data, char *data);
40using ItemTypeCheckFunc = int (*)(PyObject *py_data);
41using RNA_SetArrayFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, const char *data);
42using RNA_SetIndexFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int index, void *data_item);
43
45 union {
46 struct {
47 int range[2];
49 struct {
50 float range[2];
52 };
53};
54
62
63/*
64 * arr[3][4][5]
65 * 0 1 2 <- dimension index
66 */
67
68/*
69 * arr[2] = x
70 *
71 * py_to_array_index(arraydim=0, arrayoffset=0, index=2)
72 * validate_array(lvalue_dim=0)
73 * ... make real index ...
74 */
75
76/* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
77/* Ensures that a python sequence has expected number of
78 * items/sub-items and items are of desired type. */
79static int validate_array_type(PyObject *seq,
80 int dim,
81 int totdim,
82 int dimsize[],
83 const bool is_dynamic,
84 ItemTypeCheckFunc check_item_type,
85 const char *item_type_str,
86 const char *error_prefix)
87{
88 Py_ssize_t i;
89
90 /* not the last dimension */
91 if (dim + 1 < totdim) {
92 /* check that a sequence contains dimsize[dim] items */
93 const int seq_size = PySequence_Size(seq);
94 if (seq_size == -1) {
95 PyErr_Format(PyExc_ValueError,
96 "%s sequence expected at dimension %d, not '%s'",
97 error_prefix,
98 dim + 1,
99 Py_TYPE(seq)->tp_name);
100 return -1;
101 }
102 for (i = 0; i < seq_size; i++) {
103 Py_ssize_t item_seq_size;
104 PyObject *item;
105 bool ok = true;
106 item = PySequence_GetItem(seq, i);
107
108 if (item == nullptr) {
109 PyErr_Format(PyExc_TypeError,
110 "%s sequence type '%s' failed to retrieve index %d",
111 error_prefix,
112 Py_TYPE(seq)->tp_name,
113 i);
114 ok = false;
115 }
116 else if ((item_seq_size = PySequence_Size(item)) == -1) {
117 PyErr_Format(PyExc_TypeError,
118 "%s expected a sequence of %s, not %s",
119 error_prefix,
120 item_type_str,
121 Py_TYPE(item)->tp_name);
122 ok = false;
123 }
124 /* arr[3][4][5]
125 * dimsize[1] = 4
126 * dimsize[2] = 5
127 *
128 * dim = 0 */
129 else if (item_seq_size != dimsize[dim + 1]) {
130 PyErr_Format(PyExc_ValueError,
131 "%s sequences of dimension %d should contain %d items, not %d",
132 error_prefix,
133 dim + 1,
134 dimsize[dim + 1],
135 item_seq_size);
136 ok = false;
137 }
138 else if (validate_array_type(item,
139 dim + 1,
140 totdim,
141 dimsize,
142 is_dynamic,
143 check_item_type,
144 item_type_str,
145 error_prefix) == -1)
146 {
147 ok = false;
148 }
149
150 Py_XDECREF(item);
151
152 if (!ok) {
153 return -1;
154 }
155 }
156 }
157 else {
158 /* check that items are of correct type */
159 const int seq_size = PySequence_Size(seq);
160 if (seq_size == -1) {
161 PyErr_Format(PyExc_ValueError,
162 "%s sequence expected at dimension %d, not '%s'",
163 error_prefix,
164 dim + 1,
165 Py_TYPE(seq)->tp_name);
166 return -1;
167 }
168 if ((seq_size != dimsize[dim]) && (is_dynamic == false)) {
169 PyErr_Format(PyExc_ValueError,
170 "%s sequences of dimension %d should contain %d items, not %d",
171 error_prefix,
172 dim,
173 dimsize[dim],
174 seq_size);
175 return -1;
176 }
177
178 for (i = 0; i < seq_size; i++) {
179 PyObject *item = PySequence_GetItem(seq, i);
180
181 if (item == nullptr) {
182 PyErr_Format(PyExc_TypeError,
183 "%s sequence type '%s' failed to retrieve index %d",
184 error_prefix,
185 Py_TYPE(seq)->tp_name,
186 i);
187 return -1;
188 }
189 if (!check_item_type(item)) {
190 Py_DECREF(item);
191 PyErr_Format(PyExc_TypeError,
192 "%s expected sequence items of type %s, not %s",
193 error_prefix,
194 item_type_str,
195 Py_TYPE(item)->tp_name);
196 return -1;
197 }
198
199 Py_DECREF(item);
200 }
201 }
202
203 return 0; /* ok */
204}
205
206/* Returns the number of items in a single- or multi-dimensional sequence. */
207static int count_items(PyObject *seq, int dim)
208{
209 int totitem = 0;
210
211 if (dim > 1) {
212 const Py_ssize_t seq_size = PySequence_Size(seq);
213 Py_ssize_t i;
214 for (i = 0; i < seq_size; i++) {
215 PyObject *item = PySequence_GetItem(seq, i);
216 if (item) {
217 const int tot = count_items(item, dim - 1);
218 Py_DECREF(item);
219 if (tot != -1) {
220 totitem += tot;
221 }
222 else {
223 totitem = -1;
224 break;
225 }
226 }
227 else {
228 totitem = -1;
229 break;
230 }
231 }
232 }
233 else {
234 totitem = PySequence_Size(seq);
235 }
236
237 return totitem;
238}
239
240/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
241static int validate_array_length(PyObject *rvalue,
243 PropertyRNA *prop,
244 const bool prop_is_param_dyn_alloc,
245 int lvalue_dim,
246 int *r_totitem,
247 const char *error_prefix)
248{
249 int dimsize[MAX_ARRAY_DIMENSION];
250 int tot, totdim, len;
251
252 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
253 tot = count_items(rvalue, totdim - lvalue_dim);
254
255 if (tot == -1) {
256 PyErr_Format(PyExc_ValueError,
257 "%s %.200s.%.200s, error validating the sequence length",
258 error_prefix,
261 return -1;
262 }
263 if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
264 const int tot_expected = RNA_property_array_length(ptr, prop);
265 if (tot_expected != tot) {
266 *r_totitem = tot;
267 if (!prop_is_param_dyn_alloc) {
268 PyErr_Format(PyExc_ValueError,
269 "%s %s.%s: array length cannot be changed to %d (expected %d)",
270 error_prefix,
273 tot,
274 tot_expected);
275 return -1;
276 }
277 return 0;
278 }
279
280 len = tot;
281 }
282 else {
283 /* length is a constraint */
284 if (!lvalue_dim) {
286 }
287 /* array item assignment */
288 else {
289 int i;
290
291 len = 1;
292
293 /* arr[3][4][5]
294 *
295 * arr[2] = x
296 * dimsize = {4, 5}
297 * dimsize[1] = 4
298 * dimsize[2] = 5
299 * lvalue_dim = 0, totdim = 3
300 *
301 * arr[2][3] = x
302 * lvalue_dim = 1
303 *
304 * arr[2][3][4] = x
305 * lvalue_dim = 2 */
306 for (i = lvalue_dim; i < totdim; i++) {
307 len *= dimsize[i];
308 }
309 }
310
311 if (tot != len) {
312 PyErr_Format(PyExc_ValueError,
313 "%s %.200s.%.200s, sequence must have %d items total, not %d",
314 error_prefix,
317 len,
318 tot);
319 return -1;
320 }
321 }
322
323 *r_totitem = len;
324
325 return 0;
326}
327
328static int validate_array(PyObject *rvalue,
330 PropertyRNA *prop,
331 const bool prop_is_param_dyn_alloc,
332 int lvalue_dim,
333 ItemTypeCheckFunc check_item_type,
334 const char *item_type_str,
335 int *r_totitem,
336 const char *error_prefix)
337{
338 int dimsize[MAX_ARRAY_DIMENSION];
339 const int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
340
341 /* validate type first because length validation may modify property array length */
342
343#ifdef USE_MATHUTILS
344 if (lvalue_dim == 0) { /* only valid for first level array */
345 if (MatrixObject_Check(rvalue)) {
346 MatrixObject *pymat = (MatrixObject *)rvalue;
347
348 if (BaseMath_ReadCallback(pymat) == -1) {
349 return -1;
350 }
351
352 if (RNA_property_type(prop) != PROP_FLOAT) {
353 PyErr_Format(PyExc_ValueError,
354 "%s %.200s.%.200s, matrix assign to non float array",
355 error_prefix,
358 return -1;
359 }
360 if (totdim != 2) {
361 PyErr_Format(PyExc_ValueError,
362 "%s %.200s.%.200s, matrix assign array with %d dimensions",
363 error_prefix,
366 totdim);
367 return -1;
368 }
369 if (pymat->col_num != dimsize[0] || pymat->row_num != dimsize[1]) {
370 PyErr_Format(PyExc_ValueError,
371 "%s %.200s.%.200s, matrix assign dimension size mismatch, "
372 "is %dx%d, expected be %dx%d",
373 error_prefix,
376 pymat->col_num,
377 pymat->row_num,
378 dimsize[0],
379 dimsize[1]);
380 return -1;
381 }
382
383 *r_totitem = dimsize[0] * dimsize[1];
384 return 0;
385 }
386 }
387#endif /* USE_MATHUTILS */
388
389 {
390 const int prop_flag = RNA_property_flag(prop);
391 if (validate_array_type(rvalue,
392 lvalue_dim,
393 totdim,
394 dimsize,
395 (prop_flag & PROP_DYNAMIC) != 0,
396 check_item_type,
397 item_type_str,
398 error_prefix) == -1)
399 {
400 return -1;
401 }
402
404 rvalue, ptr, prop, prop_is_param_dyn_alloc, lvalue_dim, r_totitem, error_prefix);
405 }
406}
407
408static char *copy_value_single(PyObject *item,
410 PropertyRNA *prop,
411 char *data,
412 uint item_size,
413 int *index,
414 const ItemConvert_FuncArg *convert_item,
415 RNA_SetIndexFunc rna_set_index)
416{
417 if (!data) {
418 union {
419 float fl;
420 int i;
421 } value_buf;
422 char *value = static_cast<char *>((void *)&value_buf);
423
424 convert_item->func(&convert_item->arg, item, value);
425 rna_set_index(ptr, prop, *index, value);
426 (*index) += 1;
427 }
428 else {
429 convert_item->func(&convert_item->arg, item, data);
430 data += item_size;
431 }
432
433 return data;
434}
435
439static char *copy_values(PyObject *seq,
441 PropertyRNA *prop,
442 int dim,
443 char *data,
444 uint item_size,
445 int *index,
446 const ItemConvert_FuncArg *convert_item,
447 RNA_SetIndexFunc rna_set_index)
448{
449 const int totdim = RNA_property_array_dimension(ptr, prop, nullptr);
450 const Py_ssize_t seq_size = PySequence_Size(seq);
451 Py_ssize_t i;
452
453 /* Regarding PySequence_GetItem() failing.
454 *
455 * This should never be nullptr since we validated it, _but_ some tricky python
456 * developer could write their own sequence type which succeeds on
457 * validating but fails later somehow, so include checks for safety.
458 */
459
460 if (seq_size == -1) {
461 return nullptr;
462 }
463
464#ifdef USE_MATHUTILS
465 if (dim == 0) {
466 if (MatrixObject_Check(seq)) {
467 MatrixObject *pymat = (MatrixObject *)seq;
468 const size_t allocsize = pymat->col_num * pymat->row_num * sizeof(float);
469
470 /* read callback already done by validate */
471 /* since this is the first iteration we can assume data is allocated */
472 memcpy(data, pymat->matrix, allocsize);
473
474 /* not really needed but do for completeness */
475 data += allocsize;
476
477 return data;
478 }
479 }
480#endif /* USE_MATHUTILS */
481
482 for (i = 0; i < seq_size; i++) {
483 PyObject *item = PySequence_GetItem(seq, i);
484 if (item) {
485 if (dim + 1 < totdim) {
487 item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
488 }
489 else {
491 item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
492 }
493
494 Py_DECREF(item);
495
496 /* data may be nullptr, but the for loop checks */
497 }
498 else {
499 return nullptr;
500 }
501 }
502
503 return data;
504}
505
506static int py_to_array(PyObject *seq,
508 PropertyRNA *prop,
509 char *param_data,
510 ItemTypeCheckFunc check_item_type,
511 const char *item_type_str,
512 int item_size,
513 const ItemConvert_FuncArg *convert_item,
514 RNA_SetArrayFunc rna_set_array,
515 const char *error_prefix)
516{
517 // int totdim, dim_size[MAX_ARRAY_DIMENSION];
518 int totitem;
519 char *data = nullptr;
520
521 // totdim = RNA_property_array_dimension(ptr, prop, dim_size); /* UNUSED */
522 const int flag = RNA_property_flag(prop);
523
524 /* Use #ParameterDynAlloc which defines its own array length. */
525 const bool prop_is_param_dyn_alloc = param_data && (flag & PROP_DYNAMIC);
526
527 if (validate_array(seq,
528 ptr,
529 prop,
530 prop_is_param_dyn_alloc,
531 0,
532 check_item_type,
533 item_type_str,
534 &totitem,
535 error_prefix) == -1)
536 {
537 return -1;
538 }
539
540 if (totitem) {
541 /* NOTE: this code is confusing. */
542 if (prop_is_param_dyn_alloc) {
543 /* not freeing allocated mem, RNA_parameter_list_free() will do this */
544 ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data;
545 param_alloc->array_tot = totitem;
546
547 /* freeing param list will free */
548 param_alloc->array = MEM_callocN(item_size * totitem, "py_to_array dyn");
549
550 data = static_cast<char *>(param_alloc->array);
551 }
552 else if (param_data) {
553 data = param_data;
554 }
555 else {
556 data = static_cast<char *>(PyMem_MALLOC(item_size * totitem));
557 }
558
559 /* will only fail in very rare cases since we already validated the
560 * python data, the check here is mainly for completeness. */
561 if (copy_values(seq, ptr, prop, 0, data, item_size, nullptr, convert_item, nullptr) != nullptr)
562 {
563 if (param_data == nullptr) {
564 /* nullptr can only pass through in case RNA property array-length is 0 (impossible?) */
565 rna_set_array(ptr, prop, data);
566 PyMem_FREE(data);
567 }
568 }
569 else {
570 if (param_data == nullptr) {
571 PyMem_FREE(data);
572 }
573
574 PyErr_Format(PyExc_TypeError,
575 "%s internal error parsing sequence of type '%s' after successful validation",
576 error_prefix,
577 Py_TYPE(seq)->tp_name);
578 return -1;
579 }
580 }
581
582 return 0;
583}
584
585static int py_to_array_index(PyObject *py,
587 PropertyRNA *prop,
588 int lvalue_dim,
589 int arrayoffset,
590 int index,
591 ItemTypeCheckFunc check_item_type,
592 const char *item_type_str,
593 const ItemConvert_FuncArg *convert_item,
594 RNA_SetIndexFunc rna_set_index,
595 const char *error_prefix)
596{
597 int totdim, dimsize[MAX_ARRAY_DIMENSION];
598 int totitem, i;
599
600 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
601
602 /* convert index */
603
604 /* arr[3][4][5]
605 *
606 * arr[2] = x
607 * lvalue_dim = 0, index = 0 + 2 * 4 * 5
608 *
609 * arr[2][3] = x
610 * lvalue_dim = 1, index = 40 + 3 * 5 */
611
612 lvalue_dim++;
613
614 for (i = lvalue_dim; i < totdim; i++) {
615 index *= dimsize[i];
616 }
617
618 index += arrayoffset;
619
620 if (lvalue_dim == totdim) { /* single item, assign directly */
621 if (!check_item_type(py)) {
622 PyErr_Format(PyExc_TypeError,
623 "%s %.200s.%.200s, expected a %s type, not %s",
624 error_prefix,
627 item_type_str,
628 Py_TYPE(py)->tp_name);
629 return -1;
630 }
631 copy_value_single(py, ptr, prop, nullptr, 0, &index, convert_item, rna_set_index);
632 }
633 else {
634 const bool prop_is_param_dyn_alloc = false;
635 if (validate_array(py,
636 ptr,
637 prop,
638 prop_is_param_dyn_alloc,
639 lvalue_dim,
640 check_item_type,
641 item_type_str,
642 &totitem,
643 error_prefix) == -1)
644 {
645 return -1;
646 }
647
648 if (totitem) {
649 copy_values(py, ptr, prop, lvalue_dim, nullptr, 0, &index, convert_item, rna_set_index);
650 }
651 }
652 return 0;
653}
654
655static void py_to_float(const ItemConvertArgData *arg, PyObject *py, char *data)
656{
657 const float *range = arg->float_data.range;
658 float value = float(PyFloat_AsDouble(py));
659 CLAMP(value, range[0], range[1]);
660 *(float *)data = value;
661}
662
663static void py_to_int(const ItemConvertArgData *arg, PyObject *py, char *data)
664{
665 const int *range = arg->int_data.range;
666 int value = PyC_Long_AsI32(py);
667 CLAMP(value, range[0], range[1]);
668 *(int *)data = value;
669}
670
671static void py_to_bool(const ItemConvertArgData * /*arg*/, PyObject *py, char *data)
672{
673 *(bool *)data = bool(PyObject_IsTrue(py));
674}
675
676static int py_float_check(PyObject *py)
677{
678 /* accept both floats and integers */
679 return PyNumber_Check(py);
680}
681
682static int py_int_check(PyObject *py)
683{
684 /* accept only integers */
685 return PyLong_Check(py);
686}
687
688static int py_bool_check(PyObject *py)
689{
690 return PyBool_Check(py);
691}
692
693static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
694{
695 RNA_property_float_set_index(ptr, prop, index, *(float *)value);
696}
697
698static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
699{
700 RNA_property_int_set_index(ptr, prop, index, *(int *)value);
701}
702
703static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
704{
705 RNA_property_boolean_set_index(ptr, prop, index, *(bool *)value);
706}
707
709 PropertyRNA *prop,
710 ItemConvert_FuncArg *convert_item)
711{
712 float *range = convert_item->arg.float_data.range;
713 convert_item->func = py_to_float;
714 RNA_property_float_range(ptr, prop, &range[0], &range[1]);
715}
716
718 PropertyRNA *prop,
719 ItemConvert_FuncArg *convert_item)
720{
721 int *range = convert_item->arg.int_data.range;
722 convert_item->func = py_to_int;
723 RNA_property_int_range(ptr, prop, &range[0], &range[1]);
724}
725
726static void convert_item_init_bool(PointerRNA * /*ptr*/,
727 PropertyRNA * /*prop*/,
728 ItemConvert_FuncArg *convert_item)
729{
730 convert_item->func = py_to_bool;
731}
732
734 PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
735{
736 int ret;
737 switch (RNA_property_type(prop)) {
738 case PROP_FLOAT: {
739 ItemConvert_FuncArg convert_item;
740 convert_item_init_float(ptr, prop, &convert_item);
741
742 ret = py_to_array(py,
743 ptr,
744 prop,
745 param_data,
747 "float",
748 sizeof(float),
749 &convert_item,
751 error_prefix);
752 break;
753 }
754 case PROP_INT: {
755 ItemConvert_FuncArg convert_item;
756 convert_item_init_int(ptr, prop, &convert_item);
757
758 ret = py_to_array(py,
759 ptr,
760 prop,
761 param_data,
763 "int",
764 sizeof(int),
765 &convert_item,
767 error_prefix);
768 break;
769 }
770 case PROP_BOOLEAN: {
771 ItemConvert_FuncArg convert_item;
772 convert_item_init_bool(ptr, prop, &convert_item);
773
774 ret = py_to_array(py,
775 ptr,
776 prop,
777 param_data,
779 "boolean",
780 sizeof(bool),
781 &convert_item,
783 error_prefix);
784 break;
785 }
786 default: {
787 PyErr_SetString(PyExc_TypeError, "not an array type");
788 ret = -1;
789 break;
790 }
791 }
792
793 return ret;
794}
795
797 PropertyRNA *prop,
798 int arraydim,
799 int arrayoffset,
800 int index,
801 PyObject *py,
802 const char *error_prefix)
803{
804 int ret;
805 switch (RNA_property_type(prop)) {
806 case PROP_FLOAT: {
807 ItemConvert_FuncArg convert_item;
808 convert_item_init_float(ptr, prop, &convert_item);
809
811 ptr,
812 prop,
813 arraydim,
814 arrayoffset,
815 index,
817 "float",
818 &convert_item,
820 error_prefix);
821 break;
822 }
823 case PROP_INT: {
824 ItemConvert_FuncArg convert_item;
825 convert_item_init_int(ptr, prop, &convert_item);
826
828 ptr,
829 prop,
830 arraydim,
831 arrayoffset,
832 index,
834 "int",
835 &convert_item,
837 error_prefix);
838 break;
839 }
840 case PROP_BOOLEAN: {
841 ItemConvert_FuncArg convert_item;
842 convert_item_init_bool(ptr, prop, &convert_item);
843
845 ptr,
846 prop,
847 arraydim,
848 arrayoffset,
849 index,
851 "boolean",
852 &convert_item,
854 error_prefix);
855 break;
856 }
857 default: {
858 PyErr_SetString(PyExc_TypeError, "not an array type");
859 ret = -1;
860 break;
861 }
862 }
863
864 return ret;
865}
866
867PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
868{
869 PyObject *item;
870
871 switch (RNA_property_type(prop)) {
872 case PROP_FLOAT:
873 item = PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
874 break;
875 case PROP_BOOLEAN:
876 item = PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
877 break;
878 case PROP_INT:
879 item = PyLong_FromLong(RNA_property_int_get_index(ptr, prop, index));
880 break;
881 default:
882 PyErr_SetString(PyExc_TypeError, "not an array type");
883 item = nullptr;
884 break;
885 }
886
887 return item;
888}
889
890#if 0
891/* XXX this is not used (and never will?) */
892/* Given an array property, creates an N-dimensional tuple of values. */
893static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr,
894 PropertyRNA *prop,
895 int dim,
896 int *index)
897{
898 PyObject *tuple;
899 int i, len;
900 int totdim = RNA_property_array_dimension(ptr, prop, nullptr);
901
903
904 tuple = PyTuple_New(len);
905
906 for (i = 0; i < len; i++) {
907 PyObject *item;
908
909 if (dim + 1 < totdim) {
910 item = pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
911 }
912 else {
913 item = pyrna_array_index(ptr, prop, *index);
914 *index = *index + 1;
915 }
916
917 if (!item) {
918 Py_DECREF(tuple);
919 return nullptr;
920 }
921
922 PyTuple_SET_ITEM(tuple, i, item);
923 }
924
925 return tuple;
926}
927#endif
928
931 PropertyRNA *prop,
932 int index)
933{
934 int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
935 BPy_PropertyArrayRNA *ret = nullptr;
936
937 arraydim = self ? self->arraydim : 0;
938 arrayoffset = self ? self->arrayoffset : 0;
939
940 /* just in case check */
941 len = RNA_property_multi_array_length(ptr, prop, arraydim);
942 if (index >= len || index < 0) {
943 /* This shouldn't happen because higher level functions must check for invalid index. */
944 CLOG_WARN(BPY_LOG_RNA, "invalid index %d for array with length=%d", index, len);
945
946 PyErr_SetString(PyExc_IndexError, "out of range");
947 return nullptr;
948 }
949
950 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
951
952 if (arraydim + 1 < totdim) {
954 ret->arraydim = arraydim + 1;
955
956 /* arr[3][4][5]
957 *
958 * x = arr[2]
959 * index = 0 + 2 * 4 * 5
960 *
961 * x = arr[2][3]
962 * index = offset + 3 * 5 */
963
964 for (i = arraydim + 1; i < totdim; i++) {
965 index *= dimsize[i];
966 }
967
968 ret->arrayoffset = arrayoffset + index;
969 }
970 else {
971 index = arrayoffset + index;
973 }
974
975 return (PyObject *)ret;
976}
977
979{
980 PyObject *ret;
981
983
984 /* Is this a math object? */
985 if (ret) {
986 return ret;
987 }
988
989 return pyrna_prop_CreatePyObject(ptr, prop);
990}
991
993{
994 /* TODO: multi-dimensional arrays. */
995
996 const int len = RNA_property_array_length(ptr, prop);
997 int type;
998 int i;
999
1000 if (len == 0) {
1001 /* possible with dynamic arrays */
1002 return 0;
1003 }
1004
1005 if (RNA_property_array_dimension(ptr, prop, nullptr) > 1) {
1006 PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
1007 return -1;
1008 }
1009
1010 type = RNA_property_type(prop);
1011
1012 switch (type) {
1013 case PROP_FLOAT: {
1014 const float value_f = PyFloat_AsDouble(value);
1015 if (value_f == -1 && PyErr_Occurred()) {
1016 PyErr_Clear();
1017 return 0;
1018 }
1019
1020 float tmp[32];
1021 float *tmp_arr;
1022
1023 if (len * sizeof(float) > sizeof(tmp)) {
1024 tmp_arr = static_cast<float *>(PyMem_MALLOC(len * sizeof(float)));
1025 }
1026 else {
1027 tmp_arr = tmp;
1028 }
1029
1030 RNA_property_float_get_array(ptr, prop, tmp_arr);
1031
1032 for (i = 0; i < len; i++) {
1033 if (tmp_arr[i] == value_f) {
1034 break;
1035 }
1036 }
1037
1038 if (tmp_arr != tmp) {
1039 PyMem_FREE(tmp_arr);
1040 }
1041
1042 return i < len ? 1 : 0;
1043 }
1044 case PROP_INT: {
1045 const int value_i = PyC_Long_AsI32(value);
1046 if (value_i == -1 && PyErr_Occurred()) {
1047 PyErr_Clear();
1048 return 0;
1049 }
1050
1051 int tmp[32];
1052 int *tmp_arr;
1053
1054 if (len * sizeof(int) > sizeof(tmp)) {
1055 tmp_arr = static_cast<int *>(PyMem_MALLOC(len * sizeof(int)));
1056 }
1057 else {
1058 tmp_arr = tmp;
1059 }
1060
1061 RNA_property_int_get_array(ptr, prop, tmp_arr);
1062
1063 for (i = 0; i < len; i++) {
1064 if (tmp_arr[i] == value_i) {
1065 break;
1066 }
1067 }
1068
1069 if (tmp_arr != tmp) {
1070 PyMem_FREE(tmp_arr);
1071 }
1072
1073 return i < len ? 1 : 0;
1074 }
1075 case PROP_BOOLEAN: {
1076 const int value_i = PyC_Long_AsBool(value);
1077 if (value_i == -1 && PyErr_Occurred()) {
1078 PyErr_Clear();
1079 return 0;
1080 }
1081
1082 bool tmp[32];
1083 bool *tmp_arr;
1084
1085 if (len * sizeof(bool) > sizeof(tmp)) {
1086 tmp_arr = static_cast<bool *>(PyMem_MALLOC(len * sizeof(bool)));
1087 }
1088 else {
1089 tmp_arr = tmp;
1090 }
1091
1092 RNA_property_boolean_get_array(ptr, prop, tmp_arr);
1093
1094 for (i = 0; i < len; i++) {
1095 if (tmp_arr[i] == bool(value_i)) {
1096 break;
1097 }
1098 }
1099
1100 if (tmp_arr != tmp) {
1101 PyMem_FREE(tmp_arr);
1102 }
1103
1104 return i < len ? 1 : 0;
1105 }
1106 }
1107
1108 /* should never reach this */
1109 PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
1110 return -1;
1111}
unsigned int uint
#define CLAMP(a, b, c)
struct CLG_LogRef * BPY_LOG_RNA
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:164
@ PROP_BOOLEAN
Definition RNA_types.hh:162
@ PROP_INT
Definition RNA_types.hh:163
@ PROP_DYNAMIC
Definition RNA_types.hh:428
BMesh const char void * data
PyObject * self
PyObject * pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
Definition bpy_rna.cc:748
PyObject * pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
Definition bpy_rna.cc:8553
static void py_to_float(const ItemConvertArgData *arg, PyObject *py, char *data)
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
static void convert_item_init_bool(PointerRNA *, PropertyRNA *, ItemConvert_FuncArg *convert_item)
static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
#define MAX_ARRAY_DIMENSION
static void py_to_bool(const ItemConvertArgData *, PyObject *py, char *data)
static void convert_item_init_int(PointerRNA *ptr, PropertyRNA *prop, ItemConvert_FuncArg *convert_item)
PyObject * pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void(*)(PointerRNA *ptr, PropertyRNA *prop, const char *data) RNA_SetArrayFunc
static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic, ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
static int py_float_check(PyObject *py)
static int py_int_check(PyObject *py)
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, const bool prop_is_param_dyn_alloc, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *r_totitem, const char *error_prefix)
static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
int(*)(PyObject *py_data) ItemTypeCheckFunc
static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
static int count_items(PyObject *seq, int dim)
static char * copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, uint item_size, int *index, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
static void convert_item_init_float(PointerRNA *ptr, PropertyRNA *prop, ItemConvert_FuncArg *convert_item)
static void py_to_int(const ItemConvertArgData *arg, PyObject *py, char *data)
static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, const ItemConvert_FuncArg *convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
void(*)(const ItemConvertArgData *arg, PyObject *py_data, char *data) ItemConvertFunc
static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, const bool prop_is_param_dyn_alloc, int lvalue_dim, int *r_totitem, const char *error_prefix)
static int py_bool_check(PyObject *py)
PyObject * pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
void(*)(PointerRNA *ptr, PropertyRNA *prop, int index, void *data_item) RNA_SetIndexFunc
static char * copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, char *data, uint item_size, int *index, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
PyObject * pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
nullptr float
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:141
#define MatrixObject_Check(v)
int PyC_Long_AsBool(PyObject *value)
Py_DECREF(oname)
return ret
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension)
void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin, float *hardmax)
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
PropertyType RNA_property_type(PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
int RNA_property_flag(PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
void RNA_property_int_range(PointerRNA *ptr, PropertyRNA *prop, int *hardmin, int *hardmax)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
const char * RNA_property_identifier(const PropertyRNA *prop)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
struct ItemConvertArgData::@316277031275127263372054374375144332075330175013::@213047110356052136111304134164253307351055121222 int_data
struct ItemConvertArgData::@316277031275127263372054374375144332075330175013::@317046063310311204040345346052142055330051031367 float_data
ItemConvertFunc func
ItemConvertArgData arg
i
Definition text_draw.cc:230
uint len
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145