/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli */ #include "BLI_cpp_type.hh" #include "BLI_span.hh" namespace blender { /** * A generic span. It behaves just like a blender::Span, but the type is only known at run-time. */ class GSpan { protected: const CPPType *type_ = nullptr; const void *data_ = nullptr; int64_t size_ = 0; public: GSpan() = default; GSpan(const CPPType *type, const void *buffer, int64_t size) : type_(type), data_(buffer), size_(size) { BLI_assert(size >= 0); BLI_assert(buffer != nullptr || size == 0); BLI_assert(size == 0 || type != nullptr); BLI_assert(type == nullptr || type->pointer_has_valid_alignment(buffer)); } GSpan(const CPPType &type, const void *buffer, int64_t size) : GSpan(&type, buffer, size) { } GSpan(const CPPType &type) : type_(&type) { } GSpan(const CPPType *type) : type_(type) { } template GSpan(Span array) : GSpan(CPPType::get(), static_cast(array.data()), array.size()) { } const CPPType &type() const { BLI_assert(type_ != nullptr); return *type_; } const CPPType *type_ptr() const { return type_; } bool is_empty() const { return size_ == 0; } int64_t size() const { return size_; } const void *data() const { return data_; } const void *operator[](int64_t index) const { BLI_assert(index < size_); return POINTER_OFFSET(data_, type_->size() * index); } template Span typed() const { BLI_assert(type_->is()); return Span(static_cast(data_), size_); } GSpan slice(const int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); const int64_t new_size = std::max(0, std::min(size, size_ - start)); return GSpan(type_, POINTER_OFFSET(data_, type_->size() * start), new_size); } GSpan slice(const IndexRange range) const { return this->slice(range.start(), range.size()); } }; /** * A generic mutable span. It behaves just like a blender::MutableSpan, but the type is only * known at run-time. */ class GMutableSpan { protected: const CPPType *type_ = nullptr; void *data_ = nullptr; int64_t size_ = 0; public: GMutableSpan() = default; GMutableSpan(const CPPType *type, void *buffer, int64_t size) : type_(type), data_(buffer), size_(size) { BLI_assert(size >= 0); BLI_assert(buffer != nullptr || size == 0); BLI_assert(size == 0 || type != nullptr); BLI_assert(type == nullptr || type->pointer_has_valid_alignment(buffer)); } GMutableSpan(const CPPType &type, void *buffer, int64_t size) : GMutableSpan(&type, buffer, size) { } GMutableSpan(const CPPType &type) : type_(&type) { } GMutableSpan(const CPPType *type) : type_(type) { } template GMutableSpan(MutableSpan array) : GMutableSpan(CPPType::get(), static_cast(array.begin()), array.size()) { } operator GSpan() const { return GSpan(type_, data_, size_); } const CPPType &type() const { BLI_assert(type_ != nullptr); return *type_; } const CPPType *type_ptr() const { return type_; } bool is_empty() const { return size_ == 0; } int64_t size() const { return size_; } void *data() const { return data_; } void *operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); return POINTER_OFFSET(data_, type_->size() * index); } template MutableSpan typed() const { BLI_assert(type_->is()); return MutableSpan(static_cast(data_), size_); } GMutableSpan slice(const int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); const int64_t new_size = std::max(0, std::min(size, size_ - start)); return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size); } GMutableSpan slice(IndexRange range) const { return this->slice(range.start(), range.size()); } /** * Copy all values from another span into this span. This invokes undefined behavior when the * destination contains uninitialized data and T is not trivially copy constructible. * The size of both spans is expected to be the same. */ void copy_from(GSpan values) { BLI_assert(type_ == &values.type()); BLI_assert(size_ == values.size()); type_->copy_assign_n(values.data(), data_, size_); } }; } // namespace blender