Attributes: Integrate implicit sharing with the attribute API #107059

Merged
Jacques Lucke merged 8 commits from HooglyBoogly/blender:implicit-sharing-attribute-api into main 2023-04-19 11:21:21 +02:00
14 changed files with 63 additions and 35 deletions
Showing only changes of commit 80f09db120 - Show all commits

View File

@ -338,12 +338,11 @@ GAttributeReader BuiltinCustomDataLayerProvider::try_get_for_read(const void *ow
}
/* When the number of elements is zero, layers might have null data but still exist. */
const CPPType &type = *custom_data_type_to_cpp_type(data_type_);
const int element_num = custom_data_access_.get_element_num(owner);
if (element_num == 0) {
if (this->layer_exists(*custom_data)) {
return {GVArray::ForSingle(*custom_data_type_to_cpp_type(data_type_), 0, nullptr),
domain_,
nullptr};
return {GVArray::ForSpan({type, nullptr, 0}), domain_, nullptr};
}
return {};
}
@ -359,9 +358,7 @@ GAttributeReader BuiltinCustomDataLayerProvider::try_get_for_read(const void *ow
return {};
}
const CustomDataLayer &layer = custom_data->layers[index];
return {GVArray::ForSpan({*custom_data_type_to_cpp_type(data_type_), layer.data, element_num}),
domain_,
layer.sharing_info};
return {GVArray::ForSpan({type, layer.data, element_num}), domain_, layer.sharing_info};
}
GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
@ -386,21 +383,18 @@ GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner)
return {};
}
int index;
void *data = nullptr;
if (stored_as_named_attribute_) {
index = CustomData_get_named_layer_index(custom_data, stored_type_, name_.c_str());
data = CustomData_get_layer_named_for_write(
custom_data, stored_type_, name_.c_str(), element_num);
}
else {
index = CustomData_get_layer_index(custom_data, stored_type_);
data = CustomData_get_layer_for_write(custom_data, stored_type_, element_num);
}
if (index == -1) {
if (data == nullptr) {
return {};
}
CustomDataLayer &layer = custom_data->layers[index];
return {GVMutableArray::ForSpan({type, layer.data, element_num}),
domain_,
std::move(tag_modified_fn)};
return {GVMutableArray::ForSpan({type, data, element_num}), domain_, std::move(tag_modified_fn)};
}
bool BuiltinCustomDataLayerProvider::try_delete(void *owner) const

View File

@ -171,8 +171,6 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
* if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GAttributeReader (*)(const void *data, int element_num);
using AsWriteAttribute = GVMutableArray (*)(void *data, int element_num);
using UpdateOnRead = void (*)(const void *owner);
using UpdateOnChange = void (*)(void *owner);
const eCustomDataType stored_type_;

View File

@ -885,12 +885,14 @@ class Map {
}
/**
* Remove all key-value-pairs for that the given predicate is true.
* Remove all key-value-pairs for that the given predicate is true and return the number of
* removed pairs.
*
* This is similar to std::erase_if.
*/
template<typename Predicate> void remove_if(Predicate &&predicate)
template<typename Predicate> int64_t remove_if(Predicate &&predicate)
{
const int64_t prev_size = this->size();
for (Slot &slot : slots_) {
if (slot.is_occupied()) {
const Key &key = *slot.key();
@ -901,6 +903,7 @@ class Map {
}
}
}
return prev_size - this->size();
}
/**

View File

@ -489,12 +489,14 @@ class Set {
}
/**
* Remove all values for which the given predicate is true.
* Remove all values for which the given predicate is true and return the number of removed
* values.
*
* This is similar to std::erase_if.
*/
template<typename Predicate> void remove_if(Predicate &&predicate)
template<typename Predicate> int64_t remove_if(Predicate &&predicate)
{
const int64_t prev_size = this->size();
for (Slot &slot : slots_) {
if (slot.is_occupied()) {
const Key &key = *slot.key();
@ -504,6 +506,7 @@ class Set {
}
}
}
return prev_size - this->size();
}
/**

View File

@ -816,14 +816,17 @@ class Vector {
}
/**
* Remove all values for which the given predicate is true.
* Remove all values for which the given predicate is true and return the number of values
* removed.
*
* This is similar to std::erase_if.
*/
template<typename Predicate> void remove_if(Predicate &&predicate)
template<typename Predicate> int64_t remove_if(Predicate &&predicate)
{
const T *prev_end = this->end();
end_ = std::remove_if(this->begin(), this->end(), predicate);
UPDATE_VECTOR_SIZE(this);
return int64_t(prev_end - end_);
}
/**

View File

@ -347,13 +347,14 @@ class VectorSet {
}
/**
* Remove all values for which the given predicate is true. This may change the order of elements
* in the vector.
* Remove all values for which the given predicate is true and return the number or values
* removed. This may change the order of elements in the vector.
*
* This is similar to std::erase_if.
*/
template<typename Predicate> void remove_if(Predicate &&predicate)
template<typename Predicate> int64_t remove_if(Predicate &&predicate)
{
const int64_t prev_size = this->size();
for (Slot &slot : slots_) {
if (slot.is_occupied()) {
const int64_t index = slot.index();
@ -363,6 +364,7 @@ class VectorSet {
}
}
}
return prev_size - this->size();
}
/**

View File

@ -646,8 +646,8 @@ TEST(map, RemoveIf)
for (const int64_t i : IndexRange(100)) {
map.add(i * i, i);
}
map.remove_if([](auto item) { return item.key > 100; });
EXPECT_EQ(map.size(), 11);
const int64_t removed = map.remove_if([](auto item) { return item.key > 100; });
EXPECT_EQ(map.size() + removed, 100);
for (const int64_t i : IndexRange(100)) {
if (i <= 10) {
EXPECT_EQ(map.lookup(i * i), i);

View File

@ -582,8 +582,8 @@ TEST(set, RemoveIf)
for (const int64_t i : IndexRange(100)) {
set.add(i * i);
}
set.remove_if([](const int64_t key) { return key > 100; });
EXPECT_EQ(set.size(), 11);
const int64_t removed = set.remove_if([](const int64_t key) { return key > 100; });
EXPECT_EQ(set.size() + removed, 100);
for (const int64_t i : IndexRange(100)) {
EXPECT_EQ(set.contains(i * i), i <= 10);
}

View File

@ -134,8 +134,8 @@ TEST(vector_set, RemoveIf)
for (const int64_t i : IndexRange(100)) {
set.add(i * i);
}
set.remove_if([](const int64_t key) { return key % 2 == 0; });
EXPECT_EQ(set.size(), 50);
const int64_t removed = set.remove_if([](const int64_t key) { return key % 2 == 0; });
EXPECT_EQ(set.size() + removed, 100);
for (const int64_t i : IndexRange(100)) {
EXPECT_EQ(set.contains(i * i), i % 2 == 1);
}

View File

@ -422,7 +422,8 @@ TEST(vector, Remove)
TEST(vector, RemoveIf)
{
Vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8};
vec.remove_if([](const int x) { return x % 2 == 0; });
const int64_t removed = vec.remove_if([](const int x) { return x % 2 == 0; });
EXPECT_EQ(vec.size() + removed, 8);
const Vector<int> expected_vec = {1, 3, 5, 7};
EXPECT_EQ(vec.size(), expected_vec.size());
EXPECT_EQ_ARRAY(vec.data(), expected_vec.data(), size_t(vec.size()));

View File

@ -1840,8 +1840,14 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
* - Modifications of evaluated IDs from a Python handler.
* Such modifications are not fully integrated in the dependency graph evaluation as it
* has issues with copy-on-write tagging and the fact that relations are defined by the
* original main database status. */
if (target_id != variable_exit_key.ptr.owner_id) {
* original main database status.
*
* The original report for this is #98618.
*
* The not-so-obvious part is that we don't do such relation for the context properties.
* They are resolved at the graph build time and do not change at runtime (#107081).
*/
if (target_id != variable_exit_key.ptr.owner_id && dvar->type != DVAR_TYPE_CONTEXT_PROP) {
if (deg_copy_on_write_is_needed(GS(target_id->name))) {
ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE);
add_relation(target_id_key, driver_key, "Target ID -> Driver");

View File

@ -280,6 +280,9 @@ void WM_OT_alembic_export(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.abc", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_int(ot->srna,
"start",
INT_MIN,
@ -673,6 +676,9 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.abc", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_float(
ot->srna,
"scale",

View File

@ -454,6 +454,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.dae", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_enum(ot->srna,
"prop_bc_export_ui_section",
prop_bc_export_ui_section,
@ -776,6 +779,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.dae", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_boolean(ot->srna,
"import_units",
0,

View File

@ -258,6 +258,9 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.usd", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_boolean(ot->srna,
"selected_objects_only",
false,
@ -557,6 +560,9 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.usd", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_float(
ot->srna,
"scale",