Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenlib/BLI_virtual_array.hh
| Show First 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | public: | ||||
| /** | /** | ||||
| * Copy values from the virtual array into the provided span. Contrary to #materialize, the index | * Copy values from the virtual array into the provided span. Contrary to #materialize, the index | ||||
| * in virtual array is not the same as the index in the output span. Instead, the span is filled | * in virtual array is not the same as the index in the output span. Instead, the span is filled | ||||
| * without gaps. | * without gaps. | ||||
| */ | */ | ||||
| virtual void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const | virtual void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const | ||||
| { | { | ||||
| BLI_assert(mask.size() == r_span.size()); | BLI_assert(mask.size() == r_span.size()); | ||||
| /* Optimize for a few different common cases. */ | |||||
| const CommonVArrayInfo info = this->common_info(); | |||||
JacquesLucke: I actually meant to do the opposite at some point: Removing the special cases from `VArrayImpl`… | |||||
HooglyBooglyAuthorUnsubmitted Done Inline ActionsNope! Only consistency, but I agree it would be better like you suggested. I can implement that here if you'd like HooglyBoogly: Nope! Only consistency, but I agree it would be better like you suggested. I can implement that… | |||||
JacquesLuckeUnsubmitted Done Inline ActionsSounds good. JacquesLucke: Sounds good. | |||||
| switch (info.type) { | |||||
| case CommonVArrayInfo::Type::Any: { | |||||
| mask.to_best_mask_type([&](auto best_mask) { | mask.to_best_mask_type([&](auto best_mask) { | ||||
| for (const int64_t i : IndexRange(best_mask.size())) { | for (const int64_t i : IndexRange(best_mask.size())) { | ||||
| r_span[i] = this->get(best_mask[i]); | r_span[i] = this->get(best_mask[i]); | ||||
| } | } | ||||
| }); | }); | ||||
| break; | |||||
| } | |||||
| case CommonVArrayInfo::Type::Span: { | |||||
| const T *src = static_cast<const T *>(info.data); | |||||
| mask.to_best_mask_type([&](auto best_mask) { | |||||
| for (const int64_t i : IndexRange(best_mask.size())) { | |||||
| r_span[i] = src[best_mask[i]]; | |||||
| } | |||||
| }); | |||||
| break; | |||||
| } | |||||
| case CommonVArrayInfo::Type::Single: { | |||||
| const T single = *static_cast<const T *>(info.data); | |||||
| r_span.fill(single); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * Same as #materialize_compressed but #r_span is expected to be uninitialized. | * Same as #materialize_compressed but #r_span is expected to be uninitialized. | ||||
| */ | */ | ||||
| virtual void materialize_compressed_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const | virtual void materialize_compressed_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const | ||||
| { | { | ||||
| BLI_assert(mask.size() == r_span.size()); | BLI_assert(mask.size() == r_span.size()); | ||||
| /* Optimize for a few different common cases. */ | |||||
| const CommonVArrayInfo info = this->common_info(); | |||||
| T *dst = r_span.data(); | T *dst = r_span.data(); | ||||
| switch (info.type) { | |||||
| case CommonVArrayInfo::Type::Any: { | |||||
| mask.to_best_mask_type([&](auto best_mask) { | mask.to_best_mask_type([&](auto best_mask) { | ||||
| for (const int64_t i : IndexRange(best_mask.size())) { | for (const int64_t i : IndexRange(best_mask.size())) { | ||||
| new (dst + i) T(this->get(best_mask[i])); | new (dst + i) T(this->get(best_mask[i])); | ||||
| } | } | ||||
| }); | }); | ||||
| break; | |||||
| } | |||||
| case CommonVArrayInfo::Type::Span: { | |||||
| const T *src = static_cast<const T *>(info.data); | |||||
| mask.to_best_mask_type([&](auto best_mask) { | |||||
| for (const int64_t i : IndexRange(best_mask.size())) { | |||||
| new (dst + i) T(src[best_mask[i]]); | |||||
| } | |||||
| }); | |||||
| break; | |||||
| } | |||||
| case CommonVArrayInfo::Type::Single: { | |||||
| const T single = *static_cast<const T *>(info.data); | |||||
| uninitialized_fill_n(dst, r_span.size(), single); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * If this virtual wraps another #GVArray, this method should assign the wrapped array to the | * If this virtual wraps another #GVArray, this method should assign the wrapped array to the | ||||
| * provided reference. This allows losslessly converting between generic and typed virtual | * provided reference. This allows losslessly converting between generic and typed virtual | ||||
| * arrays in all cases. | * arrays in all cases. | ||||
| * Return true when the virtual array was assigned and false when nothing was done. | * Return true when the virtual array was assigned and false when nothing was done. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the | * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the | ||||
| * #may_have_ownership method. | * #may_have_ownership method. | ||||
| */ | */ | ||||
| template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> { | template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> { | ||||
| public: | public: | ||||
| using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; | using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; | ||||
| VArrayImpl_For_Span_final(const Span<T> data) | |||||
| /* Cast const away, because the virtual array implementation for const and non const spans | |||||
| * is shared. */ | |||||
| : VArrayImpl_For_Span<T>({const_cast<T *>(data.data()), data.size()}) | |||||
| { | |||||
| } | |||||
| private: | private: | ||||
| CommonVArrayInfo common_info() const final | CommonVArrayInfo common_info() const final | ||||
| { | { | ||||
| return CommonVArrayInfo(CommonVArrayInfo::Type::Span, false, this->data_); | return CommonVArrayInfo(CommonVArrayInfo::Type::Span, false, this->data_); | ||||
| } | } | ||||
| }; | }; | ||||
| template<typename T> | template<typename T> | ||||
| Show All 38 Lines | protected: | ||||
| { | { | ||||
| return value_; | return value_; | ||||
| } | } | ||||
| CommonVArrayInfo common_info() const override | CommonVArrayInfo common_info() const override | ||||
| { | { | ||||
| return CommonVArrayInfo(CommonVArrayInfo::Type::Single, true, &value_); | return CommonVArrayInfo(CommonVArrayInfo::Type::Single, true, &value_); | ||||
| } | } | ||||
| void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const override | |||||
| { | |||||
| BLI_assert(mask.size() == r_span.size()); | |||||
| UNUSED_VARS_NDEBUG(mask); | |||||
| r_span.fill(value_); | |||||
| } | |||||
| void materialize_compressed_to_uninitialized(IndexMask mask, | |||||
| MutableSpan<T> r_span) const override | |||||
| { | |||||
| BLI_assert(mask.size() == r_span.size()); | |||||
| uninitialized_fill_n(r_span.data(), mask.size(), value_); | |||||
| } | |||||
| }; | }; | ||||
| template<typename T> | template<typename T> | ||||
| inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Single<T>> = is_trivial_extended_v<T>; | inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Single<T>> = is_trivial_extended_v<T>; | ||||
| /** | /** | ||||
| * This class makes it easy to create a virtual array for an existing function or lambda. The | * This class makes it easy to create a virtual array for an existing function or lambda. The | ||||
| * `GetFunc` should take a single `index` argument and return the value at that index. | * `GetFunc` should take a single `index` argument and return the value at that index. | ||||
| ▲ Show 20 Lines • Show All 499 Lines • ▼ Show 20 Lines | public: | ||||
| } | } | ||||
| VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl)) | VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl)) | ||||
| { | { | ||||
| } | } | ||||
| VArray(varray_tag::span /* tag */, Span<T> span) | VArray(varray_tag::span /* tag */, Span<T> span) | ||||
| { | { | ||||
| /* Cast const away, because the virtual array implementation for const and non const spans is | this->template emplace<VArrayImpl_For_Span_final<T>>(span); | ||||
| * shared. */ | |||||
| MutableSpan<T> mutable_span{const_cast<T *>(span.data()), span.size()}; | |||||
| this->template emplace<VArrayImpl_For_Span_final<T>>(mutable_span); | |||||
| } | } | ||||
| VArray(varray_tag::single /* tag */, T value, const int64_t size) | VArray(varray_tag::single /* tag */, T value, const int64_t size) | ||||
| { | { | ||||
| this->template emplace<VArrayImpl_For_Single<T>>(std::move(value), size); | this->template emplace<VArrayImpl_For_Single<T>>(std::move(value), size); | ||||
| } | } | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 397 Lines • Show Last 20 Lines | |||||
I actually meant to do the opposite at some point: Removing the special cases from VArrayImpl and only implementing them in the corresponding subclasses. Do you see a strong reason for having everything in the base class?