Blender V5.0
attribute_storage.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "CLG_log.h"
6
7#include "BLI_assert.h"
8#include "BLI_color_types.hh"
10#include "BLI_memory_counter.hh"
11#include "BLI_resource_scope.hh"
12#include "BLI_string_utils.hh"
13#include "BLI_vector_set.hh"
14
15#include "BLO_read_write.hh"
16
17#include "DNA_attribute_types.h"
18#include "DNA_meshdata_types.h"
19#include "DNA_userdef_types.h"
20
21#include "BKE_attribute.hh"
25#include "BKE_idtype.hh"
26
27static CLG_LogRef LOG = {"geom.attribute"};
28
29namespace blender::bke {
30
32 private:
33 void *data_;
34 int64_t size_;
35 const CPPType &type_;
36 /* This struct could also store caches about the array data, like the min and max values. */
37
38 public:
40 : ImplicitSharingInfo(), data_(data), size_(size), type_(type)
41 {
42 }
43
44 private:
45 void delete_self_with_data() override
46 {
47 if (data_ != nullptr) {
48 type_.destruct_n(data_, size_);
49 MEM_freeN(data_);
50 }
51 MEM_delete(this);
52 }
53
54 void delete_data_only() override
55 {
56 type_.destruct_n(data_, size_);
57 MEM_freeN(data_);
58 data_ = nullptr;
59 size_ = 0;
60 }
61};
62
64 const int64_t domain_size)
65{
67 const CPPType &type = *value.type();
68 const void *value_ptr = value.get();
69
70 /* Prefer `calloc` to zeroing after allocation since it is faster. */
71 if (BLI_memory_is_zero(value_ptr, type.size)) {
72 data.data = MEM_calloc_arrayN_aligned(domain_size, type.size, type.alignment, __func__);
73 }
74 else {
75 data.data = MEM_malloc_arrayN_aligned(domain_size, type.size, type.alignment, __func__);
76 type.fill_construct_n(value_ptr, data.data, domain_size);
77 }
78
79 data.size = domain_size;
82 return data;
83}
84
86 const int64_t domain_size)
87{
88 return from_value(GPointer(type, type.default_value()), domain_size);
89}
90
92 const int64_t domain_size)
93{
95 data.data = MEM_malloc_arrayN_aligned(domain_size, type.size, type.alignment, __func__);
96 data.size = domain_size;
99 return data;
100}
101
103 const int64_t domain_size)
104{
106 type.default_construct_n(data.data, domain_size);
107 return data;
108}
109
111{
113 const CPPType &type = *value.type();
114 data.value = MEM_mallocN_aligned(type.size, type.alignment, __func__);
115 type.copy_construct(value.get(), data.value);
118 return data;
119}
120
125
127{
128 for (const std::unique_ptr<Attribute> &attribute : this->runtime->attributes) {
129 fn(*attribute);
130 }
131}
133{
134 for (const std::unique_ptr<Attribute> &attribute : this->runtime->attributes) {
135 fn(*attribute);
136 }
137}
138
140{
141 for (const std::unique_ptr<Attribute> &attribute : this->runtime->attributes) {
142 if (!fn(*attribute)) {
143 break;
144 }
145 }
146}
148{
149 for (const std::unique_ptr<Attribute> &attribute : this->runtime->attributes) {
150 if (!fn(*attribute)) {
151 break;
152 }
153 }
154}
155
157{
158 if (std::get_if<Attribute::ArrayData>(&data_)) {
160 }
161 if (std::get_if<Attribute::SingleData>(&data_)) {
163 }
166}
167
169{
170 if (auto *data = std::get_if<Attribute::ArrayData>(&data_)) {
171 if (!data->sharing_info) {
172 BLI_assert(data->size == 0);
173 return data_;
174 }
175 if (data->sharing_info->is_mutable()) {
176 data->sharing_info->tag_ensured_mutable();
177 return data_;
178 }
179 const CPPType &type = attribute_type_to_cpp_type(type_);
180 ArrayData new_data = ArrayData::from_uninitialized(type, data->size);
181 type.copy_construct_n(data->data, new_data.data, data->size);
182 *data = std::move(new_data);
183 }
184 else if (auto *data = std::get_if<Attribute::SingleData>(&data_)) {
185 if (data->sharing_info->is_mutable()) {
186 data->sharing_info->tag_ensured_mutable();
187 return data_;
188 }
189 const CPPType &type = attribute_type_to_cpp_type(type_);
190 *data = SingleData::from_value(GPointer(type, data->value));
191 }
192 return data_;
193}
194
196{
197 this->dna_attributes = nullptr;
198 this->dna_attributes_num = 0;
199 memset(this->_pad, 0, sizeof(this->_pad));
200 this->runtime = MEM_new<AttributeStorageRuntime>(__func__);
201}
202
204{
205 this->dna_attributes = nullptr;
206 this->dna_attributes_num = 0;
207 this->runtime = MEM_new<AttributeStorageRuntime>(__func__);
208 this->runtime->attributes.reserve(other.runtime->attributes.size());
209 other.foreach([&](const Attribute &attribute) {
210 this->runtime->attributes.add_new(std::make_unique<Attribute>(attribute));
211 });
212}
213
215{
216 if (this == &other) {
217 return *this;
218 }
219 std::destroy_at(this);
220 new (this) AttributeStorage(other);
221 return *this;
222}
223
225{
226 this->dna_attributes = nullptr;
227 this->dna_attributes_num = 0;
228 this->runtime = MEM_new<AttributeStorageRuntime>(__func__, std::move(*other.runtime));
229}
230
232{
233 if (this == &other) {
234 return *this;
235 }
236 std::destroy_at(this);
237 new (this) AttributeStorage(std::move(other));
238 return *this;
239}
240
242{
243 MEM_delete(this->runtime);
244}
245
247{
248 return this->runtime->attributes.size();
249}
250
252{
253 return *this->runtime->attributes[index];
254}
256{
257 return *this->runtime->attributes[index];
258}
259
261{
262 return this->runtime->attributes.index_of_try_as(name);
263}
264
266{
267 const std::unique_ptr<blender::bke::Attribute> *attribute =
268 this->runtime->attributes.lookup_key_ptr_as(name);
269 if (!attribute) {
270 return nullptr;
271 }
272 return attribute->get();
273}
274
276{
277 const std::unique_ptr<blender::bke::Attribute> *attribute =
278 this->runtime->attributes.lookup_key_ptr_as(name);
279 if (!attribute) {
280 return nullptr;
281 }
282 return attribute->get();
283}
284
286 const AttrDomain domain,
287 const AttrType data_type,
289{
290 BLI_assert(!this->lookup(name));
291 std::unique_ptr<Attribute> ptr = std::make_unique<Attribute>();
292 Attribute &attribute = *ptr;
293 attribute.name_ = std::move(name);
294 attribute.domain_ = domain;
295 attribute.type_ = data_type;
296 attribute.data_ = std::move(data);
297 this->runtime->attributes.add_new(std::move(ptr));
298 return attribute;
299}
300
302{
303 return this->runtime->attributes.remove_as(name);
304}
305
307{
308 return BLI_uniquename_cb(
309 [&](const StringRef check_name) { return this->lookup(check_name) != nullptr; }, '.', name);
310}
311
312void AttributeStorage::rename(const StringRef old_name, std::string new_name)
313{
314 /* The VectorSet must be rebuilt from scratch because the data used to create the hash is
315 * changed. */
316 const int index = this->runtime->attributes.index_of_try_as(old_name);
317 Vector<std::unique_ptr<Attribute>> old_vector = this->runtime->attributes.extract_vector();
318 old_vector[index]->name_ = std::move(new_name);
319 this->runtime->attributes.reserve(old_vector.size());
320 for (std::unique_ptr<Attribute> &attribute : old_vector) {
321 this->runtime->attributes.add_new(std::move(attribute));
322 }
323}
324
326{
327 this->foreach([&](Attribute &attr) {
328 if (attr.domain() != domain) {
329 return;
330 }
331 const CPPType &type = attribute_type_to_cpp_type(attr.data_type());
332 switch (attr.storage_type()) {
334 const auto &data = std::get<bke::Attribute::ArrayData>(attr.data());
335 const int64_t old_size = data.size;
336
337 auto new_data = bke::Attribute::ArrayData::from_uninitialized(type, new_size);
338 type.copy_construct_n(data.data, new_data.data, std::min(old_size, new_size));
339 if (old_size < new_size) {
340 type.default_construct_n(POINTER_OFFSET(new_data.data, type.size * old_size),
341 new_size - old_size);
342 }
343
344 attr.assign_data(std::move(new_data));
345 }
347 return;
348 }
349 }
350 });
351}
352
354 const int8_t dna_attr_type,
355 const int64_t size,
356 void **data)
357{
358 switch (dna_attr_type) {
359 case int8_t(AttrType::Bool):
360 static_assert(sizeof(bool) == sizeof(int8_t));
361 BLO_read_int8_array(&reader, size, reinterpret_cast<int8_t **>(data));
362 return;
363 case int8_t(AttrType::Int8):
364 BLO_read_int8_array(&reader, size, reinterpret_cast<int8_t **>(data));
365 return;
366 case int8_t(AttrType::Int16_2D):
367 BLO_read_int16_array(&reader, size * 2, reinterpret_cast<int16_t **>(data));
368 return;
369 case int8_t(AttrType::Int32):
370 BLO_read_int32_array(&reader, size, reinterpret_cast<int32_t **>(data));
371 return;
372 case int8_t(AttrType::Int32_2D):
373 BLO_read_int32_array(&reader, size * 2, reinterpret_cast<int32_t **>(data));
374 return;
375 case int8_t(AttrType::Float):
376 BLO_read_float_array(&reader, size, reinterpret_cast<float **>(data));
377 return;
378 case int8_t(AttrType::Float2):
379 BLO_read_float_array(&reader, size * 2, reinterpret_cast<float **>(data));
380 return;
381 case int8_t(AttrType::Float3):
382 BLO_read_float3_array(&reader, size, reinterpret_cast<float **>(data));
383 return;
384 case int8_t(AttrType::Float4x4):
385 BLO_read_float_array(&reader, size * 16, reinterpret_cast<float **>(data));
386 return;
387 case int8_t(AttrType::ColorByte):
388 BLO_read_uint8_array(&reader, size * 4, reinterpret_cast<uint8_t **>(data));
389 return;
390 case int8_t(AttrType::ColorFloat):
391 BLO_read_float_array(&reader, size * 4, reinterpret_cast<float **>(data));
392 return;
393 case int8_t(AttrType::Quaternion):
394 BLO_read_float_array(&reader, size * 4, reinterpret_cast<float **>(data));
395 return;
396 case int8_t(AttrType::String):
398 &reader, MStringProperty, size, reinterpret_cast<MStringProperty **>(data));
399 return;
400 default:
401 *data = nullptr;
402 return;
403 }
404}
405
407 const int8_t dna_attr_type,
408 const int64_t size,
409 void **data,
410 const ImplicitSharingInfo **sharing_info)
411{
412 const char *func = __func__;
413 *sharing_info = BLO_read_shared(&reader, data, [&]() -> const ImplicitSharingInfo * {
414 read_array_data(reader, dna_attr_type, size, data);
415 if (*data == nullptr) {
416 return nullptr;
417 }
418 const CPPType &cpp_type = attribute_type_to_cpp_type(AttrType(dna_attr_type));
419 return MEM_new<ArrayDataImplicitSharing>(func, *data, size, cpp_type);
420 });
421}
422
423static std::optional<Attribute::DataVariant> read_attr_data(BlendDataReader &reader,
424 const int8_t dna_storage_type,
425 const int8_t dna_attr_type,
426 ::Attribute &dna_attr)
427{
428 switch (dna_storage_type) {
429 case int8_t(AttrStorageType::Array): {
430 BLO_read_struct(&reader, AttributeArray, &dna_attr.data);
431 auto &data = *static_cast<::AttributeArray *>(dna_attr.data);
432 read_shared_array(reader, dna_attr_type, data.size, &data.data, &data.sharing_info);
433 if (data.size != 0 && !data.data) {
434 return std::nullopt;
435 }
436 return Attribute::ArrayData{data.data, data.size, ImplicitSharingPtr<>(data.sharing_info)};
437 }
438 case int8_t(AttrStorageType::Single): {
439 BLO_read_struct(&reader, AttributeSingle, &dna_attr.data);
440 auto &data = *static_cast<::AttributeSingle *>(dna_attr.data);
441 read_shared_array(reader, dna_attr_type, 1, &data.data, &data.sharing_info);
442 if (!data.data) {
443 return std::nullopt;
444 }
445 return Attribute::SingleData{data.data, ImplicitSharingPtr<>(data.sharing_info)};
446 }
447 default:
448 return std::nullopt;
449 }
450}
451
453{
454 for (const std::unique_ptr<Attribute> &attr : this->runtime->attributes) {
455 const CPPType &type = attribute_type_to_cpp_type(attr->data_type());
456 if (const auto *data = std::get_if<Attribute::ArrayData>(&attr->data())) {
457 memory.add_shared(data->sharing_info.get(), [&](MemoryCounter &shared_memory) {
458 shared_memory.add(data->size * type.size);
459 });
460 }
461 else if (const auto *data = std::get_if<Attribute::SingleData>(&attr->data())) {
462 memory.add_shared(data->sharing_info.get(),
463 [&](MemoryCounter &shared_memory) { shared_memory.add(type.size); });
464 }
465 }
466}
467
468static std::optional<AttrDomain> read_attr_domain(const int8_t dna_domain)
469{
470 switch (dna_domain) {
471 case int8_t(AttrDomain::Point):
472 case int8_t(AttrDomain::Edge):
473 case int8_t(AttrDomain::Face):
474 case int8_t(AttrDomain::Corner):
475 case int8_t(AttrDomain::Curve):
476 case int8_t(AttrDomain::Instance):
477 case int8_t(AttrDomain::Layer):
478 return AttrDomain(dna_domain);
479 default:
480 return std::nullopt;
481 }
482}
483
485{
486 this->runtime = MEM_new<AttributeStorageRuntime>(__func__);
487 this->runtime->attributes.reserve(this->dna_attributes_num);
488
490 for (const int i : IndexRange(this->dna_attributes_num)) {
491 ::Attribute &dna_attr = this->dna_attributes[i];
492 BLO_read_string(&reader, &dna_attr.name);
493 BLI_SCOPED_DEFER([&]() { MEM_SAFE_FREE(dna_attr.name); });
494
495 const std::optional<AttrDomain> domain = read_attr_domain(dna_attr.domain);
496 if (!domain) {
497 continue;
498 }
499
500 std::optional<Attribute::DataVariant> data = read_attr_data(
501 reader, dna_attr.storage_type, dna_attr.data_type, dna_attr);
502 BLI_SCOPED_DEFER([&]() { MEM_SAFE_FREE(dna_attr.data); });
503 if (!data) {
504 continue;
505 }
506
507 std::unique_ptr<Attribute> attribute = std::make_unique<Attribute>();
508 attribute->name_ = dna_attr.name;
509 attribute->domain_ = *domain;
510 attribute->type_ = AttrType(dna_attr.data_type);
511 attribute->data_ = std::move(*data);
512
513 if (!this->runtime->attributes.add(std::move(attribute))) {
514 CLOG_ERROR(&LOG, "Ignoring attribute with duplicate name: \"%s\"", dna_attr.name);
515 }
516 }
517
518 /* These fields are not used at runtime. */
520 this->dna_attributes_num = 0;
521}
522
523static void write_array_data(BlendWriter &writer,
524 const AttrType data_type,
525 const void *data,
526 const int64_t size)
527{
528 switch (data_type) {
529 case AttrType::Bool:
530 static_assert(sizeof(bool) == sizeof(int8_t));
531 BLO_write_int8_array(&writer, size, static_cast<const int8_t *>(data));
532 break;
533 case AttrType::Int8:
534 BLO_write_int8_array(&writer, size, static_cast<const int8_t *>(data));
535 break;
537 BLO_write_int16_array(&writer, size * 2, static_cast<const int16_t *>(data));
538 break;
539 case AttrType::Int32:
540 BLO_write_int32_array(&writer, size, static_cast<const int32_t *>(data));
541 break;
543 BLO_write_int32_array(&writer, size * 2, static_cast<const int32_t *>(data));
544 break;
545 case AttrType::Float:
546 BLO_write_float_array(&writer, size, static_cast<const float *>(data));
547 break;
548 case AttrType::Float2:
549 BLO_write_float_array(&writer, size * 2, static_cast<const float *>(data));
550 break;
551 case AttrType::Float3:
552 BLO_write_float3_array(&writer, size, static_cast<const float *>(data));
553 break;
555 BLO_write_float_array(&writer, size * 16, static_cast<const float *>(data));
556 break;
558 BLO_write_uint8_array(&writer, size * 4, static_cast<const uint8_t *>(data));
559 break;
561 BLO_write_float_array(&writer, size * 4, static_cast<const float *>(data));
562 break;
564 BLO_write_float_array(&writer, size * 4, static_cast<const float *>(data));
565 break;
566 case AttrType::String:
568 &writer, MStringProperty, size, static_cast<const MStringProperty *>(data));
569 break;
570 }
571}
572
575{
576 data.foreach([&](Attribute &attr) {
577 ::Attribute attribute_dna{};
578 attribute_dna.name = attr.name().c_str();
579 attribute_dna.data_type = int16_t(attr.data_type());
580 attribute_dna.domain = int8_t(attr.domain());
581 attribute_dna.storage_type = int8_t(attr.storage_type());
582
583 /* The idea is to use a separate DNA struct for each #AttrStorageType. They each need to have a
584 * unique address (while writing a specific ID anyway) in order to be identified when
585 * reading the file, so we add them to the resource scope which outlives this function call.
586 * Using a #ResourceScope is a simple way to get pointer stability when adding every new data
587 * struct without the cost of many small allocations or unnecessary overhead of storing a full
588 * array for every storage type. */
589
590 if (const auto *data = std::get_if<Attribute::ArrayData>(&attr.data())) {
591 auto &array_dna = write_data.scope.construct<::AttributeArray>();
592 array_dna.data = data->data;
593 array_dna.sharing_info = data->sharing_info.get();
594 array_dna.size = data->size;
595 attribute_dna.data = &array_dna;
596 }
597 else if (const auto *data = std::get_if<Attribute::SingleData>(&attr.data())) {
598 auto &single_dna = write_data.scope.construct<::AttributeSingle>();
599 single_dna.data = data->value;
600 single_dna.sharing_info = data->sharing_info.get();
601 attribute_dna.data = &single_dna;
602 }
603
604 write_data.attributes.append(attribute_dna);
605 });
606 data.runtime = nullptr;
607}
608
609static void write_shared_array(BlendWriter &writer,
610 const AttrType data_type,
611 const void *data,
612 const int64_t size,
613 const ImplicitSharingInfo *sharing_info)
614{
616 BLO_write_shared(&writer, data, cpp_type.size * size, sharing_info, [&]() {
617 write_array_data(writer, data_type, data, size);
618 });
619}
620
625
627 const AttributeStorage::BlendWriteData &write_data)
628{
629 /* Use string argument to avoid confusion with the C++ class with the same name. */
631 &writer, "Attribute", write_data.attributes.size(), write_data.attributes.data());
632 for (const ::Attribute &attr_dna : write_data.attributes) {
633 BLO_write_string(&writer, attr_dna.name);
634 switch (AttrStorageType(attr_dna.storage_type)) {
636 ::AttributeSingle *single_dna = static_cast<::AttributeSingle *>(attr_dna.data);
638 writer, AttrType(attr_dna.data_type), single_dna->data, 1, single_dna->sharing_info);
639 BLO_write_struct(&writer, AttributeSingle, single_dna);
640 break;
641 }
643 ::AttributeArray *array_dna = static_cast<::AttributeArray *>(attr_dna.data);
644 write_shared_array(writer,
645 AttrType(attr_dna.data_type),
646 array_dna->data,
647 array_dna->size,
648 array_dna->sharing_info);
649 BLO_write_struct(&writer, AttributeArray, array_dna);
650 break;
651 }
652 }
653 }
654
655 this->dna_attributes = nullptr;
656 this->dna_attributes_num = 0;
657}
658
660{
661 for (const std::unique_ptr<Attribute> &attribute : this->runtime->attributes) {
662 if (attribute->type_ == blender::bke::AttrType::ColorFloat) {
663 if (auto *data = std::get_if<Attribute::ArrayData>(&attribute->data_)) {
664 fn.implicit_sharing_array(
665 data->sharing_info, reinterpret_cast<ColorGeometry4f *&>(data->data), data->size);
666 }
667 else if (auto *data = std::get_if<Attribute::SingleData>(&attribute->data_)) {
668 fn.implicit_sharing_array(
669 data->sharing_info, reinterpret_cast<ColorGeometry4f *&>(data->value), 1);
670 }
671 }
672 /* Byte colors are always Rec.709 sRGB, no conversion needed. */
673 };
674}
675
676} // namespace blender::bke
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
bool BLI_memory_is_zero(const void *arr, size_t size)
#define BLI_SCOPED_DEFER(function_to_defer)
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
#define POINTER_OFFSET(v, ofs)
void BLO_write_float_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_read_uint8_array(BlendDataReader *reader, int64_t array_size, uint8_t **ptr_p)
Definition readfile.cc:5776
void BLO_read_float3_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5816
void BLO_write_int32_array(BlendWriter *writer, int64_t num, const int32_t *data_ptr)
void BLO_write_struct_array_by_name(BlendWriter *writer, const char *struct_name, int64_t array_size, const void *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5809
void BLO_read_int32_array(BlendDataReader *reader, int64_t array_size, int32_t **ptr_p)
Definition readfile.cc:5795
void BLO_write_uint8_array(BlendWriter *writer, int64_t num, const uint8_t *data_ptr)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_write_float3_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_read_int16_array(BlendDataReader *reader, const int64_t array_size, int16_t **ptr_p)
Definition readfile.cc:5788
void BLO_write_int8_array(BlendWriter *writer, int64_t num, const int8_t *data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
void BLO_read_int8_array(BlendDataReader *reader, int64_t array_size, int8_t **ptr_p)
Definition readfile.cc:5782
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_int16_array(BlendWriter *writer, int64_t num, const int16_t *data_ptr)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define MEM_SAFE_FREE(v)
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void copy_construct_n(const void *src, void *dst, int64_t n) const
void default_construct_n(void *ptr, int64_t n) const
void destruct_n(void *ptr, int64_t n) const
void fill_construct_n(const void *value, void *dst, int64_t n) const
void copy_construct(const void *src, void *dst) const
const void * default_value() const
const CPPType * type() const
const void * get() const
T & construct(Args &&...args)
constexpr const char * c_str() const
int64_t size() const
ArrayDataImplicitSharing(void *data, const int64_t size, const CPPType &type)
void rename(StringRef old_name, std::string new_name)
Attribute & add(std::string name, bke::AttrDomain domain, bke::AttrType data_type, Attribute::DataVariant data)
void count_memory(MemoryCounter &memory) const
Attribute * lookup(StringRef name)
void foreach(FunctionRef< void(Attribute &)> fn)
void blend_read(BlendDataReader &reader)
void blend_write(BlendWriter &writer, const BlendWriteData &write_data)
std::string unique_name_calc(StringRef name) const
void foreach_working_space_color(const IDTypeForeachColorFunctionCallback &fn)
void resize(AttrDomain domain, int64_t new_size)
int index_of(StringRef name) const
void foreach_with_stop(FunctionRef< bool(Attribute &)> fn)
AttributeStorage & operator=(const AttributeStorage &other)
AttrStorageType storage_type() const
const DataVariant & data() const
std::variant< ArrayData, SingleData > DataVariant
void assign_data(DataVariant &&data)
void add_shared(const ImplicitSharingInfo *sharing_info, const FunctionRef< void(MemoryCounter &shared_memory)> count_fn)
#define LOG(level)
Definition log.h:97
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void *(* MEM_calloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str)
Definition mallocn.cc:59
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void *(* MEM_malloc_arrayN_aligned)(size_t len, size_t size, size_t alignment, const char *str)
Definition mallocn.cc:55
static std::optional< Attribute::DataVariant > read_attr_data(BlendDataReader &reader, const int8_t dna_storage_type, const int8_t dna_attr_type, ::Attribute &dna_attr)
static std::optional< AttrDomain > read_attr_domain(const int8_t dna_domain)
void attribute_storage_blend_write_prepare(AttributeStorage &data, AttributeStorage::BlendWriteData &write_data)
static void write_array_data(BlendWriter &writer, const AttrType data_type, const void *data, const int64_t size)
static void read_shared_array(BlendDataReader &reader, const int8_t dna_attr_type, const int64_t size, void **data, const ImplicitSharingInfo **sharing_info)
static void write_shared_array(BlendWriter &writer, const AttrType data_type, const void *data, const int64_t size, const ImplicitSharingInfo *sharing_info)
static void read_array_data(BlendDataReader &reader, const int8_t dna_attr_type, const int64_t size, void **data)
const CPPType & attribute_type_to_cpp_type(AttrType type)
const ImplicitSharingInfo * info_for_mem_free(void *data)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
const char * name
const ImplicitSharingInfoHandle * sharing_info
const ImplicitSharingInfoHandle * sharing_info
AttributeStorageRuntimeHandle * runtime
struct Attribute * dna_attributes
const char * name
static ArrayData from_uninitialized(const CPPType &type, int64_t domain_size)
static ArrayData from_default_value(const CPPType &type, int64_t domain_size)
static ArrayData from_value(const GPointer &value, int64_t domain_size)
static ArrayData from_constructed(const CPPType &type, int64_t domain_size)
static SingleData from_value(const GPointer &value)
static SingleData from_default_value(const CPPType &type)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238