/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once /** \file * \ingroup fn */ #include "BLI_span.hh" #include "FN_cpp_type.hh" namespace blender::fn { /** * 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_; const void *data_; int64_t size_; public: 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(type.pointer_has_valid_alignment(buffer)); } GSpan(const CPPType &type) : GSpan(type, nullptr, 0) { } template GSpan(Span array) : GSpan(CPPType::get(), static_cast(array.data()), array.size()) { } const CPPType &type() 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_; void *data_; int64_t size_; public: 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(type.pointer_has_valid_alignment(buffer)); } GMutableSpan(const CPPType &type) : GMutableSpan(type, nullptr, 0) { } 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 { 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()); } }; } // namespace blender::fn