Blender V5.0
attribute_storage_test.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 "testing/testing.h"
6
7#include "BKE_attribute.hh"
9
10namespace blender::bke::tests {
11
12TEST(attribute_storage, Empty)
13{
14 AttributeStorage storage;
15 int count = 0;
16 storage.foreach([&](const Attribute & /*attribute*/) { count++; });
17 EXPECT_EQ(count, 0);
18}
19
20TEST(attribute_storage, Single)
21{
22 AttributeStorage storage;
23
24 auto *sharing_info = new ImplicitSharedValue<Array<float>>(Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
26 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
27 data.data = sharing_info->data.data();
28 data.size = 4;
29 storage.add("foo", AttrDomain::Corner, AttrType::Float, std::move(data));
30
31 EXPECT_TRUE(storage.lookup("foo"));
32 EXPECT_EQ(storage.lookup("foo")->domain(), AttrDomain::Corner);
33 EXPECT_EQ(storage.lookup("foo")->data_type(), AttrType::Float);
34 {
35 const auto &data = std::get<Attribute::ArrayData>(storage.lookup("foo")->data());
36 EXPECT_EQ(data.data, sharing_info->data.data());
37 }
38
39 int count = 0;
40 storage.foreach([&](const Attribute & /*attribute*/) { count++; });
41 EXPECT_EQ(count, 1);
42}
43
44TEST(attribute_storage, GetForWrite)
45{
46 AttributeStorage storage;
47
48 auto *sharing_info = new ImplicitSharedValue<Array<float>>(Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
50 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
51 data.data = sharing_info->data.data();
52 data.size = 4;
53 storage.add("foo", AttrDomain::Corner, AttrType::Float, std::move(data));
54 {
55 const auto &data = std::get<Attribute::ArrayData>(storage.lookup("foo")->data_for_write());
56 EXPECT_EQ(data.data, sharing_info->data.data());
57 }
58 {
59 sharing_info->add_user();
60 const auto &data = std::get<Attribute::ArrayData>(storage.lookup("foo")->data_for_write());
61 EXPECT_NE(data.data, sharing_info->data.data());
62 const float *data_ptr = static_cast<const float *>(data.data);
63 EXPECT_EQ(data_ptr[0], 1.5f);
64 EXPECT_EQ(data_ptr[1], 1.2f);
65 EXPECT_EQ(data_ptr[2], 1.1f);
66 EXPECT_EQ(data_ptr[3], 1.0f);
67 sharing_info->remove_user_and_delete_if_last();
68 }
69 {
70 const auto &data = std::get<Attribute::ArrayData>(storage.lookup("foo")->data_for_write());
71 const float *data_ptr = static_cast<const float *>(data.data);
72 EXPECT_EQ(data_ptr[0], 1.5f);
73 EXPECT_EQ(data_ptr[1], 1.2f);
74 EXPECT_EQ(data_ptr[2], 1.1f);
75 EXPECT_EQ(data_ptr[3], 1.0f);
76 }
77}
78
79TEST(attribute_storage, MultipleShared)
80{
81 AttributeStorage storage;
82
83 auto *sharing_info = new ImplicitSharedValue<Array<float>>(Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
85 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
86 data.data = sharing_info->data.data();
87 data.size = 4;
89 storage.add("need", AttrDomain::Point, AttrType::Float, data);
90 storage.add("more", AttrDomain::Face, AttrType::Float, data);
91 storage.add("data", AttrDomain::Edge, AttrType::Float, data);
92
93 /* The same data is shared among 4 attributes (as well as the original `data`). */
94 EXPECT_EQ(sharing_info->strong_users(), 5);
95 storage.add("final!", AttrDomain::Edge, AttrType::Float, std::move(data));
96 EXPECT_EQ(sharing_info->strong_users(), 5);
97
98 {
99 const auto &data = std::get<Attribute::ArrayData>(storage.lookup("more")->data_for_write());
100 const float *data_ptr = static_cast<const float *>(data.data);
101 EXPECT_EQ(data_ptr[0], 1.5f);
102 EXPECT_EQ(data_ptr[1], 1.2f);
103 EXPECT_EQ(data_ptr[2], 1.1f);
104 EXPECT_EQ(data_ptr[3], 1.0f);
105 }
106
107 int count = 0;
108 storage.foreach([&](const Attribute & /*attribute*/) { count++; });
109 EXPECT_EQ(count, 5);
110}
111
112TEST(attribute_storage, CopyConstruct)
113{
114 AttributeStorage storage;
115
116 auto *sharing_info = new ImplicitSharedValue<Array<float>>(Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
118 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
119 data.data = sharing_info->data.data();
120 data.size = 4;
121 storage.add("foo", AttrDomain::Corner, AttrType::Float, std::move(data));
122
123 AttributeStorage copy{storage};
124
125 EXPECT_TRUE(copy.lookup("foo"));
126 EXPECT_EQ(copy.lookup("foo")->domain(), AttrDomain::Corner);
127 EXPECT_EQ(copy.lookup("foo")->data_type(), AttrType::Float);
128 {
129 const auto &data = std::get<Attribute::ArrayData>(copy.lookup("foo")->data());
130 /* The data is shared, so it should be the same as the original. */
131 EXPECT_EQ(data.data, sharing_info->data.data());
132 }
133}
134
135TEST(attribute_storage, MoveConstruct)
136{
137 AttributeStorage storage;
138
139 auto *sharing_info = new ImplicitSharedValue<Array<float>>(Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
141 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
142 data.data = sharing_info->data.data();
143 data.size = 4;
144 storage.add("foo", AttrDomain::Corner, AttrType::Float, std::move(data));
145
146 AttributeStorage copy{std::move(storage)};
147
148 EXPECT_TRUE(copy.lookup("foo"));
149 EXPECT_EQ(copy.lookup("foo")->domain(), AttrDomain::Corner);
150 EXPECT_EQ(copy.lookup("foo")->data_type(), AttrType::Float);
151 {
152 const auto &data = std::get<Attribute::ArrayData>(copy.lookup("foo")->data());
153 /* The data is shared, so it should be the same as the original. */
154 EXPECT_EQ(data.data, sharing_info->data.data());
155 }
156}
157
158TEST(attribute_storage, UniqueNames)
159{
160 AttributeStorage storage;
161
162 auto create_array_data = []() {
163 auto *sharing_info = new ImplicitSharedValue<Array<float>>(
164 Span<float>{1.5f, 1.2f, 1.1f, 1.0f});
166 data.sharing_info = ImplicitSharingPtr<>(sharing_info);
167 data.data = sharing_info->data.data();
168 data.size = 4;
169 return data;
170 };
171
172 storage.add("foo", AttrDomain::Corner, AttrType::Float, create_array_data());
173 storage.add("foo_2", AttrDomain::Face, AttrType::Float, create_array_data());
174 storage.add("foo_3", AttrDomain::Point, AttrType::Float, create_array_data());
175 storage.add(
176 storage.unique_name_calc("foo"), AttrDomain::Edge, AttrType::Float, create_array_data());
177 storage.add(
178 storage.unique_name_calc("foo"), AttrDomain::Corner, AttrType::Float, create_array_data());
179 storage.add(
180 storage.unique_name_calc("foo_2"), AttrDomain::Point, AttrType::Float, create_array_data());
181
182 int count = 0;
183 storage.foreach([&](const Attribute & /*attribute*/) { count++; });
184 EXPECT_EQ(count, 6);
185}
186
187} // namespace blender::bke::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
BMesh const char void * data
Attribute & add(std::string name, bke::AttrDomain domain, bke::AttrType data_type, Attribute::DataVariant data)
Attribute * lookup(StringRef name)
void foreach(FunctionRef< void(Attribute &)> fn)
std::string unique_name_calc(StringRef name) const
const DataVariant & data() const
int count
TEST(action_groups, ReconstructGroupsWithReordering)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)