Blender V5.0
outliner_treehash.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 <cstdlib>
12#include <cstring>
13
14#include "BLI_mempool.h"
15#include "BLI_utildefines.h"
16#include "BLI_vector.hh"
17
18#include "DNA_outliner_types.h"
19
21
23
24/* -------------------------------------------------------------------- */
27
28class TseGroup {
29 public:
31 /* Index of last used #TreeStoreElem item, to speed up search for another one. */
32 int lastused = 0;
33 /* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused
34 * item is exponential and becomes critically slow when there are a lot of items in the group. */
36
37 void add_element(TreeStoreElem &elem);
38 void remove_element(TreeStoreElem &elem);
39};
40
41/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */
42#define TSEGROUP_LASTUSED_RESET_VALUE 10000
43
45{
46 const int64_t idx = elems.append_and_get_index(&elem);
47 lastused = idx;
48}
49
51{
52 const int64_t idx = elems.first_index_of(&elem);
53 elems.remove(idx);
54}
55
57
58/* -------------------------------------------------------------------- */
61
63 : id(elem.id), type(elem.type), nr(elem.nr)
64{
65}
66
68
70{
71 return get_default_hash(id, type, nr);
72}
73
75{
76 return (a.id == b.id) && (a.type == b.type) && (a.nr == b.nr);
77}
78
80
81/* -------------------------------------------------------------------- */
84
85TreeHash::~TreeHash() = default;
86
87std::unique_ptr<TreeHash> TreeHash::create_from_treestore(BLI_mempool &treestore)
88{
89 /* Can't use `make_unique()` here because of private constructor. */
90 std::unique_ptr<TreeHash> tree_hash{new TreeHash()};
91 tree_hash->fill_treehash(treestore);
92
93 return tree_hash;
94}
95
96void TreeHash::fill_treehash(BLI_mempool &treestore)
97{
98 TreeStoreElem *tselem;
100 BLI_mempool_iternew(&treestore, &iter);
101
102 while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
103 add_element(*tselem);
104 }
105}
106
108{
109 for (auto &group : elem_groups_.values()) {
110 group->lastused = 0;
111 group->lastused_reset_count = 0;
112 }
113}
114
116{
117 elem_groups_.clear();
118 fill_treehash(treestore);
119}
120
122{
123 std::unique_ptr<TseGroup> &group = elem_groups_.lookup_or_add_cb(
124 TreeStoreElemKey(elem), []() { return std::make_unique<TseGroup>(); });
125 group->add_element(elem);
126}
127
129{
130 TseGroup *group = lookup_group(elem);
131 BLI_assert(group != nullptr);
132
133 if (group->elems.size() <= 1) {
134 /* One element -> remove group completely. */
135 elem_groups_.remove(TreeStoreElemKey(elem));
136 }
137 else {
138 group->remove_element(elem);
139 }
140}
141
142TseGroup *TreeHash::lookup_group(const TreeStoreElemKey &key) const
143{
144 const auto *group = elem_groups_.lookup_ptr(key);
145 if (group) {
146 return group->get();
147 }
148 return nullptr;
149}
150
151TseGroup *TreeHash::lookup_group(const TreeStoreElem &elem) const
152{
153 return lookup_group(TreeStoreElemKey(elem));
154}
155
156TseGroup *TreeHash::lookup_group(const short type, const short nr, ID *id) const
157{
158 TreeStoreElemKey key(id, type, nr);
159 if (type == TSE_SOME_ID) {
160 key.nr = 0; /* we're picky! :) */
161 }
162 return lookup_group(key);
163}
164
165TreeStoreElem *TreeHash::lookup_unused(const short type, const short nr, ID *id) const
166{
167 TseGroup *group = lookup_group(type, nr, id);
168 if (!group) {
169 return nullptr;
170 }
171
172 /* Find unused element, with optimization to start from previously
173 * found element assuming we do repeated lookups. */
174 const int size = group->elems.size();
175 int offset = group->lastused;
176
177 for (int i = 0; i < size; i++, offset++) {
178 /* Once at the end of the array of items, in most cases it just means that all items are
179 * used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */
180 if (offset >= size) {
182 group->lastused_reset_count++;
183 group->lastused = group->elems.size() - 1;
184 break;
185 }
186 group->lastused_reset_count = 0;
187 offset = 0;
188 }
189
190 if (!group->elems[offset]->used) {
191 group->lastused = offset;
192 return group->elems[offset];
193 }
194 }
195 return nullptr;
196}
197
198TreeStoreElem *TreeHash::lookup_any(const short type, const short nr, ID *id) const
199{
200 const TseGroup *group = lookup_group(type, nr, id);
201 return group ? group->elems[0] : nullptr;
202}
203
205
206} // namespace blender::bke::outliner::treehash
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LIKELY(x)
@ TSE_SOME_ID
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
int64_t size() const
void rebuild_from_treestore(BLI_mempool &treestore)
TreeStoreElem * lookup_unused(short type, short nr, ID *id) const
TreeStoreElem * lookup_any(short type, short nr, ID *id) const
static std::unique_ptr< TreeHash > create_from_treestore(BLI_mempool &treestore)
blender::Vector< TreeStoreElem * > elems
bool operator==(const TreeStoreElemKey &a, const TreeStoreElemKey &b)
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
#define TSEGROUP_LASTUSED_RESET_VALUE
Definition DNA_ID.h:414
i
Definition text_draw.cc:230