Blender V5.0
generic_virtual_array.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
8
9#include <iostream>
10
12
13namespace blender {
14
15/* -------------------------------------------------------------------- */
18
20 void *dst,
21 const bool dst_is_uninitialized) const
22{
23 if (dst_is_uninitialized) {
24 mask.foreach_index_optimized<int64_t>([&](const int64_t i) {
25 void *elem_dst = POINTER_OFFSET(dst, type_->size * i);
26 this->get_to_uninitialized(i, elem_dst);
27 });
28 }
29 else {
30 mask.foreach_index_optimized<int64_t>([&](const int64_t i) {
31 void *elem_dst = POINTER_OFFSET(dst, type_->size * i);
32 this->get(i, elem_dst);
33 });
34 }
35}
36
38 void *dst,
39 const bool dst_is_uninitialized) const
40{
41 if (dst_is_uninitialized) {
42 mask.foreach_index_optimized<int64_t>([&](const int64_t i, const int64_t pos) {
43 void *elem_dst = POINTER_OFFSET(dst, type_->size * pos);
44 this->get_to_uninitialized(i, elem_dst);
45 });
46 }
47 else {
48 mask.foreach_index_optimized<int64_t>([&](const int64_t i, const int64_t pos) {
49 void *elem_dst = POINTER_OFFSET(dst, type_->size * pos);
50 this->get(i, elem_dst);
51 });
52 }
53}
54
55void GVArrayImpl::get(const int64_t index, void *r_value) const
56{
57 type_->destruct(r_value);
58 this->get_to_uninitialized(index, r_value);
59}
60
62{
63 return {};
64}
65
66bool GVArrayImpl::try_assign_VArray(void * /*varray*/) const
67{
68 return false;
69}
70
72
73/* -------------------------------------------------------------------- */
76
77void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value)
78{
80 type_->copy_construct(value, buffer);
81 this->set_by_move(index, buffer);
82 type_->destruct(buffer);
83}
84
85void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value)
86{
87 this->set_by_move(index, value);
88 type_->destruct(value);
89}
90
91void GVMutableArrayImpl::set_all(const void *src)
92{
93 const CommonVArrayInfo info = this->common_info();
95 type_->copy_assign_n(src, const_cast<void *>(info.data), size_);
96 }
97 else {
98 for (int64_t i : IndexRange(size_)) {
99 this->set_by_copy(i, POINTER_OFFSET(src, type_->size * i));
100 }
101 }
102}
103
104void GVMutableArray::fill(const void *value)
105{
106 const CommonVArrayInfo info = this->common_info();
108 this->type().fill_assign_n(value, const_cast<void *>(info.data), this->size());
109 }
110 else {
111 for (int64_t i : IndexRange(this->size())) {
112 this->set_by_copy(i, value);
113 }
114 }
115}
116
118{
119 return false;
120}
121
123
124/* -------------------------------------------------------------------- */
127
128void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
129{
130 type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
131}
132
133void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
134{
135 type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
136}
137
138void GVArrayImpl_For_GSpan::set_by_copy(const int64_t index, const void *value)
139{
140 type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index));
141}
142
143void GVArrayImpl_For_GSpan::set_by_move(const int64_t index, void *value)
144{
145 type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index));
146}
147
149{
150 type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
151}
152
157
159 void *dst,
160 const bool dst_is_uninitialized) const
161{
162 if (dst_is_uninitialized) {
163 type_->copy_construct_indices(data_, dst, mask);
164 }
165 else {
166 type_->copy_assign_indices(data_, dst, mask);
167 }
168}
169
171 void *dst,
172 const bool dst_is_uninitialized) const
173{
174 if (dst_is_uninitialized) {
175 type_->copy_construct_compressed(data_, dst, mask);
176 }
177 else {
178 type_->copy_assign_compressed(data_, dst, mask);
179 }
180}
181
183
184/* -------------------------------------------------------------------- */
187
188/* Generic virtual array where each element has the same value. The value is not owned. */
189
190void GVArrayImpl_For_SingleValueRef::get(const int64_t /*index*/, void *r_value) const
191{
192 type_->copy_assign(value_, r_value);
193}
195 void *r_value) const
196{
197 type_->copy_construct(value_, r_value);
198}
199
204
206 void *dst,
207 const bool dst_is_uninitialized) const
208{
209 if (dst_is_uninitialized) {
210 type_->fill_construct_indices(value_, dst, mask);
211 }
212 else {
213 type_->fill_assign_indices(value_, dst, mask);
214 }
215}
216
218 void *dst,
219 const bool dst_is_uninitialized) const
220{
221 if (dst_is_uninitialized) {
222 type_->fill_construct_n(value_, dst, mask.size());
223 }
224 else {
225 type_->fill_assign_n(value_, dst, mask.size());
226 }
227}
228
230
231/* -------------------------------------------------------------------- */
234
235/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */
238 NonMovable {
239 public:
240 GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value)
242 {
243 value_ = MEM_mallocN_aligned(type.size, type.alignment, __func__);
244 type.copy_construct(value, (void *)value_);
245 }
246
248 {
249 type_->destruct(const_cast<void *>(value_));
250 MEM_freeN(const_cast<void *>(value_));
251 }
252};
253
255
256/* -------------------------------------------------------------------- */
259
264template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
265 private:
267
268 public:
270 const int64_t size,
271 const void *value)
273 {
274 BLI_assert(type.is_trivial);
275 BLI_assert(type.alignment <= 8);
276 BLI_assert(type.size <= BufferSize);
277 type.copy_construct(value, &buffer_);
278 }
279
280 private:
281 void get(const int64_t index, void *r_value) const final
282 {
283 this->get_to_uninitialized(index, r_value);
284 }
285 void get_to_uninitialized(const int64_t /*index*/, void *r_value) const final
286 {
287 memcpy(r_value, &buffer_, type_->size);
288 }
289
290 void materialize(const IndexMask &mask,
291 void *dst,
292 const bool /*dst_is_uninitialized*/) const final
293 {
294 type_->fill_construct_indices(buffer_, dst, mask);
295 }
296
297 void materialize_compressed(const IndexMask &mask,
298 void *dst,
299 const bool /*dst_is_uninitialized*/) const final
300 {
301 type_->fill_construct_n(buffer_, dst, mask.size());
302 }
303
304 CommonVArrayInfo common_info() const final
305 {
306 return CommonVArrayInfo{CommonVArrayInfo::Type::Single, true, &buffer_};
307 }
308};
309
311
312/* -------------------------------------------------------------------- */
315
316GVArraySpan::GVArraySpan() = default;
317
319 : GSpan(varray ? &varray.type() : nullptr), varray_(std::move(varray))
320{
321 if (!varray_) {
322 return;
323 }
324
325 size_ = varray_.size();
326 const CommonVArrayInfo info = varray_.common_info();
328 data_ = info.data;
329 }
330 else {
331 owned_data_ = MEM_mallocN_aligned(type_->size * size_, type_->alignment, __func__);
332 varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
333 data_ = owned_data_;
334 }
335}
336
338 : GSpan(other.type_ptr()), varray_(std::move(other.varray_)), owned_data_(other.owned_data_)
339{
340 if (!varray_) {
341 return;
342 }
343
344 size_ = varray_.size();
345 const CommonVArrayInfo info = varray_.common_info();
347 data_ = info.data;
348 }
349 else {
350 data_ = owned_data_;
351 }
352 other.owned_data_ = nullptr;
353 other.data_ = nullptr;
354 other.size_ = 0;
355}
356
358{
359 if (owned_data_ != nullptr) {
360 type_->destruct_n(owned_data_, size_);
361 MEM_freeN(owned_data_);
362 }
363}
364
366{
367 if (this == &other) {
368 return *this;
369 }
370 std::destroy_at(this);
371 new (this) GVArraySpan(std::move(other));
372 return *this;
373}
374
376
377/* -------------------------------------------------------------------- */
380
382
384 : GMutableSpan(varray ? &varray.type() : nullptr), varray_(std::move(varray))
385{
386 if (!varray_) {
387 return;
388 }
389 size_ = varray_.size();
390 const CommonVArrayInfo info = varray_.common_info();
392 data_ = const_cast<void *>(info.data);
393 }
394 else {
395 owned_data_ = MEM_mallocN_aligned(type_->size * size_, type_->alignment, __func__);
396 if (copy_values_to_span) {
397 varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
398 }
399 else {
400 type_->default_construct_n(owned_data_, size_);
401 }
402 data_ = owned_data_;
403 }
404}
405
407 : GMutableSpan(other.type_ptr()),
408 varray_(std::move(other.varray_)),
409 owned_data_(other.owned_data_),
410 show_not_saved_warning_(other.show_not_saved_warning_)
411{
412 if (!varray_) {
413 return;
414 }
415 size_ = varray_.size();
416 const CommonVArrayInfo info = varray_.common_info();
418 data_ = const_cast<void *>(info.data);
419 }
420 else {
421 data_ = owned_data_;
422 }
423 other.owned_data_ = nullptr;
424 other.data_ = nullptr;
425 other.size_ = 0;
426}
427
429{
430 if (varray_) {
431 if (show_not_saved_warning_) {
432 if (!save_has_been_called_) {
433 std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
434 }
435 }
436 }
437 if (owned_data_ != nullptr) {
438 type_->destruct_n(owned_data_, size_);
439 MEM_freeN(owned_data_);
440 }
441}
442
444{
445 if (this == &other) {
446 return *this;
447 }
448 std::destroy_at(this);
449 new (this) GMutableVArraySpan(std::move(other));
450 return *this;
451}
452
454{
455 save_has_been_called_ = true;
456 if (data_ != owned_data_) {
457 return;
458 }
459 varray_.set_all(owned_data_);
460}
461
463{
464 show_not_saved_warning_ = false;
465}
466
468{
469 return varray_;
470}
471
473
474/* -------------------------------------------------------------------- */
477
479 protected:
483
484 public:
486 : GVArrayImpl(varray.type(), slice.size()),
487 varray_(std::move(varray)),
488 offset_(slice.start()),
489 slice_(slice)
490 {
491 BLI_assert(slice.one_after_last() <= varray_.size());
492 }
493
494 void get(const int64_t index, void *r_value) const override
495 {
496 varray_.get(index + offset_, r_value);
497 }
498
499 void get_to_uninitialized(const int64_t index, void *r_value) const override
500 {
501 varray_.get_to_uninitialized(index + offset_, r_value);
502 }
503
505 {
506 const CommonVArrayInfo internal_info = varray_.common_info();
507 switch (internal_info.type) {
509 return {};
510 }
513 internal_info.may_have_ownership,
514 POINTER_OFFSET(internal_info.data, type_->size * offset_));
515 }
517 return internal_info;
518 }
519 }
521 return {};
522 }
523
524 void materialize(const IndexMask &mask, void *dst, const bool dst_is_uninitialized) const final
525 {
526 IndexMaskMemory memory;
527 const IndexMask shifted_mask = mask.shift(offset_, memory);
528 void *shifted_dst = POINTER_OFFSET(dst, -offset_ * type_->size);
529 varray_.get_implementation()->materialize(shifted_mask, shifted_dst, dst_is_uninitialized);
530 }
531
533 void *dst,
534 const bool dst_is_uninitialized) const final
535 {
536 IndexMaskMemory memory;
537 const IndexMask shifted_mask = mask.shift(offset_, memory);
538 varray_.get_implementation()->materialize_compressed(shifted_mask, dst, dst_is_uninitialized);
539 }
540};
541
543
544/* -------------------------------------------------------------------- */
547
552
553GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_))
554{
555 impl_ = this->impl_from_storage();
556 other.storage_.reset();
557 other.impl_ = nullptr;
558}
559
561{
562 storage_ = impl_;
563}
564
565GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get())
566{
567 if (impl) {
568 storage_ = std::move(impl);
569 }
570}
571
573
574void GVArrayCommon::materialize(void *dst) const
575{
576 this->materialize(IndexMask(impl_->size()), dst);
577}
578
579void GVArrayCommon::materialize(const IndexMask &mask, void *dst) const
580{
581 impl_->materialize(mask, dst, false);
582}
583
585{
586 this->materialize_to_uninitialized(IndexMask(impl_->size()), dst);
587}
588
590{
591 BLI_assert(mask.min_array_size() <= impl_->size());
592 impl_->materialize(mask, dst, true);
593}
594
596{
597 impl_->materialize_compressed(mask, dst, false);
598}
599
601{
602 impl_->materialize_compressed(mask, dst, true);
603}
604
606{
607 if (this == &other) {
608 return;
609 }
610 storage_ = other.storage_;
611 impl_ = this->impl_from_storage();
612}
613
615{
616 if (this == &other) {
617 return;
618 }
619 storage_ = std::move(other.storage_);
620 impl_ = this->impl_from_storage();
621 other.storage_.reset();
622 other.impl_ = nullptr;
623}
624
626{
627 const CommonVArrayInfo info = impl_->common_info();
628 return info.type == CommonVArrayInfo::Type::Span;
629}
630
632{
633 BLI_assert(this->is_span());
634 const CommonVArrayInfo info = impl_->common_info();
635 return GSpan(this->type(), info.data, this->size());
636}
637
639{
640 const CommonVArrayInfo info = impl_->common_info();
642}
643
644void GVArrayCommon::get_internal_single(void *r_value) const
645{
646 BLI_assert(this->is_single());
647 const CommonVArrayInfo info = impl_->common_info();
648 this->type().copy_assign(info.data, r_value);
649}
650
652{
653 impl_->type().default_construct(r_value);
654 this->get_internal_single(r_value);
655}
656
658{
659 if (!storage_.has_value()) {
660 return nullptr;
661 }
662 return storage_.extra_info().get_varray(storage_.get());
663}
664
666{
667 return IndexRange(this->size());
668}
669
671
672/* -------------------------------------------------------------------- */
675
676GVArray::GVArray(const GVArray &other) = default;
677
678GVArray::GVArray(GVArray &&other) noexcept = default;
679
681
682GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl)) {}
683
684GVArray::GVArray(varray_tag::single /*tag*/, const CPPType &type, int64_t size, const void *value)
685{
686 if (type.is_trivial && type.size <= 16 && type.alignment <= 8) {
688 }
689 else {
690 this->emplace<GVArrayImpl_For_SingleValue>(type, size, value);
691 }
692}
693
694GVArray GVArray::from_single(const CPPType &type, const int64_t size, const void *value)
695{
696 return GVArray(varray_tag::single{}, type, size, value);
697}
698
699GVArray GVArray::from_single_ref(const CPPType &type, const int64_t size, const void *value)
700{
701 return GVArray(varray_tag::single_ref{}, type, size, value);
702}
703
705{
706 return GVArray::from_single_ref(type, size, type.default_value());
707}
708
710{
711 return GVArray(varray_tag::span{}, span);
712}
713
715 protected:
717
718 public:
720 : GVArrayImpl_For_GSpan(array.as_mutable_span()), array_(std::move(array))
721 {
722 }
723};
724
729
734
736{
737 const CommonVArrayInfo info = this->common_info();
739 return GVArray::from_single(this->type(), slice.size(), info.data);
740 }
741 /* Need to check for ownership, because otherwise the referenced data can be destructed when
742 * #this is destructed. */
744 return GVArray::from_span(GSpan(this->type(), info.data, this->size()).slice(slice));
745 }
747}
748
750{
751 this->copy_from(other);
752 return *this;
753}
754
756{
757 this->move_from(std::move(other));
758 return *this;
759}
760
762
763/* -------------------------------------------------------------------- */
766
767GVMutableArray::GVMutableArray(const GVMutableArray &other) = default;
768GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default;
769
771
772GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl)
773 : GVArrayCommon(std::move(impl))
774{
775}
776
781
782GVMutableArray::operator GVArray() const &
783{
784 GVArray varray;
785 varray.copy_from(*this);
786 return varray;
787}
788
789GVMutableArray::operator GVArray() && noexcept
790{
791 GVArray varray;
792 varray.move_from(std::move(*this));
793 return varray;
794}
795
797{
798 this->copy_from(other);
799 return *this;
800}
801
803{
804 this->move_from(std::move(other));
805 return *this;
806}
807
809{
810 return this->get_impl();
811}
812
813void GVMutableArray::set_all(const void *src)
814{
815 this->get_impl()->set_all(src);
816}
817
819{
820 BLI_assert(this->is_span());
821 const CommonVArrayInfo info = impl_->common_info();
822 return GMutableSpan(this->type(), const_cast<void *>(info.data), this->size());
823}
824
826
828{
830}
831
833{
834 return CommonVArrayInfo(CommonVArrayInfo::Type::Single, false, value_);
835}
836
837} // namespace blender
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define final(a, b, c)
Definition BLI_hash.h:19
#define POINTER_OFFSET(v, ofs)
long long int int64_t
void fill_assign_n(const void *value, void *dst, int64_t n) const
void copy_assign(const void *src, void *dst) const
const CPPType * type_ptr() const
const CPPType & type() const
const GVMutableArray & varray() const
GMutableVArraySpan & operator=(GMutableVArraySpan &&other)
const CPPType * type_ptr() const
const CPPType & type() const
GSpan slice(const int64_t start, int64_t size) const
GSpan()=default
const CPPType * type_
CommonVArrayInfo common_info() const
void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const
const GVArrayImpl * impl_from_storage() const
void copy_from(const GVArrayCommon &other)
void move_from(GVArrayCommon &&other) noexcept
void materialize(void *dst) const
void get_internal_single_to_uninitialized(void *r_value) const
void materialize_to_uninitialized(void *dst) const
void get(int64_t index, void *r_value) const
void materialize_compressed(const IndexMask &mask, void *dst) const
void get_internal_single(void *r_value) const
void materialize(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const override
CommonVArrayInfo common_info() const override
void set_by_move(int64_t index, void *value) override
void get_to_uninitialized(int64_t index, void *r_value) const override
void set_by_relocate(int64_t index, void *value) override
void materialize_compressed(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const override
GVArrayImpl_For_GSpan(const GMutableSpan span)
void get(int64_t index, void *r_value) const override
void set_by_copy(int64_t index, const void *value) override
void get(const int64_t index, void *r_value) const override
void materialize_compressed(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const override
void get_to_uninitialized(const int64_t index, void *r_value) const override
CommonVArrayInfo common_info() const override
GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
void materialize(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const override
GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value)
CommonVArrayInfo common_info() const override
void materialize_compressed(const IndexMask &mask, void *dst, const bool dst_is_uninitialized) const final
void get(const int64_t index, void *r_value) const override
GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice)
void get_to_uninitialized(const int64_t index, void *r_value) const override
void materialize(const IndexMask &mask, void *dst, const bool dst_is_uninitialized) const final
GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type, const int64_t size, const void *value)
virtual void materialize(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const
virtual void get_to_uninitialized(int64_t index, void *r_value) const =0
virtual void get(int64_t index, void *r_value) const
virtual bool try_assign_VArray(void *varray) const
virtual void materialize_compressed(const IndexMask &mask, void *dst, bool dst_is_uninitialized) const
GVArrayImpl(const CPPType &type, int64_t size)
virtual CommonVArrayInfo common_info() const
const CPPType & type() const
GVArraySpan & operator=(GVArraySpan &&other)
GVArray slice(IndexRange slice) const
GVArray()=default
GVArray & operator=(const GVArray &other)
static GVArray from_empty(const CPPType &type)
static GVArray from(Args &&...args)
static GVArray from_single_default(const CPPType &type, int64_t size)
static GVArray from_garray(GArray<> array)
static GVArray from_single(const CPPType &type, int64_t size, const void *value)
static GVArray from_span(GSpan span)
static GVArray from_single_ref(const CPPType &type, int64_t size, const void *value)
virtual bool try_assign_VMutableArray(void *varray) const
virtual void set_all(const void *src)
virtual void set_by_copy(int64_t index, const void *value)
virtual void set_by_relocate(int64_t index, void *value)
virtual void set_by_move(int64_t index, void *value)=0
void set_all(const void *src)
void set_by_copy(int64_t index, const void *value)
GVMutableArrayImpl * get_implementation() const
static GVMutableArray from_span(GMutableSpan span)
GMutableSpan get_internal_span() const
GVMutableArray & operator=(const GVMutableArray &other)
void fill(const void *value)
static GVMutableArray from(Args &&...args)
constexpr int64_t one_after_last() const
constexpr int64_t size() const
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
uint pos
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
i
Definition text_draw.cc:230