Blender V5.0
BLI_map_slots.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
24
25#include "BLI_hash_tables.hh"
26#include "BLI_memory_utils.hh"
27
28namespace blender {
29
30template<typename Src1, typename Src2, typename Dst1, typename Dst2>
31void initialize_pointer_pair(Src1 &&src1, Src2 &&src2, Dst1 *dst1, Dst2 *dst2)
32{
33 new ((void *)dst1) Dst1(std::forward<Src1>(src1));
34 try {
35 new ((void *)dst2) Dst2(std::forward<Src2>(src2));
36 }
37 catch (...) {
38 dst1->~Dst1();
39 throw;
40 }
41}
42
48template<typename Key, typename Value> class SimpleMapSlot {
49 private:
50 enum State : uint8_t {
51 Empty = 0,
52 Occupied = 1,
53 Removed = 2,
54 };
55
56 State state_;
57 TypedBuffer<Key> key_buffer_;
58 TypedBuffer<Value> value_buffer_;
59
60 public:
65 {
66 state_ = Empty;
67 }
68
73 {
74 if (state_ == Occupied) {
75 key_buffer_.ref().~Key();
76 value_buffer_.ref().~Value();
77 }
78 }
79
85 {
86 state_ = other.state_;
87 if (other.state_ == Occupied) {
88 initialize_pointer_pair(other.key_buffer_.ref(),
89 other.value_buffer_.ref(),
90 key_buffer_.ptr(),
91 value_buffer_.ptr());
92 }
93 }
94
100 SimpleMapSlot(SimpleMapSlot &&other) noexcept(std::is_nothrow_move_constructible_v<Key> &&
101 std::is_nothrow_move_constructible_v<Value>)
102 {
103 state_ = other.state_;
104 if (other.state_ == Occupied) {
105 initialize_pointer_pair(std::move(other.key_buffer_.ref()),
106 std::move(other.value_buffer_.ref()),
107 key_buffer_.ptr(),
108 value_buffer_.ptr());
109 }
110 }
111
116 {
117 return key_buffer_;
118 }
119
123 const Key *key() const
124 {
125 return key_buffer_;
126 }
127
131 Value *value()
132 {
133 return value_buffer_;
134 }
135
139 const Value *value() const
140 {
141 return value_buffer_;
142 }
143
147 bool is_occupied() const
148 {
149 return state_ == Occupied;
150 }
151
155 bool is_empty() const
156 {
157 return state_ == Empty;
158 }
159
164 template<typename Hash> uint64_t get_hash(const Hash &hash)
165 {
166 BLI_assert(this->is_occupied());
167 return hash(*key_buffer_);
168 }
169
174 template<typename ForwardKey, typename IsEqual>
175 bool contains(const ForwardKey &key, const IsEqual &is_equal, uint64_t /*hash*/) const
176 {
177 if (state_ == Occupied) {
178 return is_equal(key, *key_buffer_);
179 }
180 return false;
181 }
182
187 template<typename ForwardKey, typename... ForwardValue>
188 void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
189 {
190 BLI_assert(!this->is_occupied());
191 new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
192 this->occupy_no_value(std::forward<ForwardKey>(key), hash);
193 state_ = Occupied;
194 }
195
200 template<typename ForwardKey> void occupy_no_value(ForwardKey &&key, uint64_t /*hash*/)
201 {
202 BLI_assert(!this->is_occupied());
203 try {
204 new (&key_buffer_) Key(std::forward<ForwardKey>(key));
205 }
206 catch (...) {
207 /* The value is assumed to be constructed already, so it has to be destructed as well. */
208 value_buffer_.ref().~Value();
209 throw;
210 }
211 state_ = Occupied;
212 }
213
218 void remove()
219 {
220 BLI_assert(this->is_occupied());
221 key_buffer_.ref().~Key();
222 value_buffer_.ref().~Value();
223 state_ = Removed;
224 }
225};
226
235template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot {
236 private:
237 Key key_ = KeyInfo::get_empty();
238 TypedBuffer<Value> value_buffer_;
239
240 public:
241 IntrusiveMapSlot() = default;
242
244 {
245 if (KeyInfo::is_not_empty_or_removed(key_)) {
246 value_buffer_.ref().~Value();
247 }
248 }
249
250 IntrusiveMapSlot(const IntrusiveMapSlot &other) : key_(other.key_)
251 {
252 if (KeyInfo::is_not_empty_or_removed(key_)) {
253 new (&value_buffer_) Value(*other.value_buffer_);
254 }
255 }
256
257 IntrusiveMapSlot(IntrusiveMapSlot &&other) noexcept : key_(other.key_)
258 {
259 if (KeyInfo::is_not_empty_or_removed(key_)) {
260 new (&value_buffer_) Value(std::move(*other.value_buffer_));
261 }
262 }
263
265 {
266 return &key_;
267 }
268
269 const Key *key() const
270 {
271 return &key_;
272 }
273
274 Value *value()
275 {
276 return value_buffer_;
277 }
278
279 const Value *value() const
280 {
281 return value_buffer_;
282 }
283
284 bool is_occupied() const
285 {
286 return KeyInfo::is_not_empty_or_removed(key_);
287 }
288
289 bool is_empty() const
290 {
291 return KeyInfo::is_empty(key_);
292 }
293
294 template<typename Hash> uint64_t get_hash(const Hash &hash)
295 {
296 BLI_assert(this->is_occupied());
297 return hash(key_);
298 }
299
300 template<typename ForwardKey, typename IsEqual>
301 bool contains(const ForwardKey &key, const IsEqual &is_equal, uint64_t /*hash*/) const
302 {
303 BLI_assert(KeyInfo::is_not_empty_or_removed(key));
304 return is_equal(key, key_);
305 }
306
307 template<typename ForwardKey, typename... ForwardValue>
308 void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
309 {
310 BLI_assert(!this->is_occupied());
311 BLI_assert(KeyInfo::is_not_empty_or_removed(key));
312 new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
313 this->occupy_no_value(std::forward<ForwardKey>(key), hash);
314 }
315
316 template<typename ForwardKey> void occupy_no_value(ForwardKey &&key, uint64_t /*hash*/)
317 {
318 BLI_assert(!this->is_occupied());
319 BLI_assert(KeyInfo::is_not_empty_or_removed(key));
320 try {
321 key_ = std::forward<ForwardKey>(key);
322 }
323 catch (...) {
324 value_buffer_.ref().~Value();
325 throw;
326 }
327 }
328
329 void remove()
330 {
331 BLI_assert(this->is_occupied());
332 value_buffer_.ref().~Value();
333 KeyInfo::remove(key_);
334 }
335};
336
337template<typename Key, typename Value> struct DefaultMapSlot;
338
342template<typename Key, typename Value> struct DefaultMapSlot {
344};
345
350template<typename Key, typename Value> struct DefaultMapSlot<Key *, Value> {
352};
353
354} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
struct Key Key
unsigned long long int uint64_t
const Key * key() const
void occupy_no_value(ForwardKey &&key, uint64_t)
const Value * value() const
IntrusiveMapSlot(IntrusiveMapSlot &&other) noexcept
bool contains(const ForwardKey &key, const IsEqual &is_equal, uint64_t) const
IntrusiveMapSlot(const IntrusiveMapSlot &other)
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
uint64_t get_hash(const Hash &hash)
SimpleMapSlot(const SimpleMapSlot &other)
const Key * key() const
SimpleMapSlot(SimpleMapSlot &&other) noexcept(std::is_nothrow_move_constructible_v< Key > &&std::is_nothrow_move_constructible_v< Value >)
const Value * value() const
uint64_t get_hash(const Hash &hash)
bool contains(const ForwardKey &key, const IsEqual &is_equal, uint64_t) const
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
void occupy_no_value(ForwardKey &&key, uint64_t)
void initialize_pointer_pair(Src1 &&src1, Src2 &&src2, Dst1 *dst1, Dst2 *dst2)
#define hash
Definition noise_c.cc:154
IntrusiveMapSlot< Key *, Value, PointerKeyInfo< Key * > > type
SimpleMapSlot< Key, Value > type