| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef __FN_ATTRIBUTES_REF_HH__
 | 
					
						
							|  |  |  | #define __FN_ATTRIBUTES_REF_HH__
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup fn | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name | 
					
						
							|  |  |  |  * and index. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 14:29:05 +02:00
										 |  |  | #include <optional>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | #include "FN_spans.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_linear_allocator.hh"
 | 
					
						
							|  |  |  | #include "BLI_map.hh"
 | 
					
						
							|  |  |  | #include "BLI_utility_mixins.hh"
 | 
					
						
							|  |  |  | #include "BLI_vector_set.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | namespace blender::fn { | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class AttributesInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AttributesInfoBuilder : NonCopyable, NonMovable { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   LinearAllocator<> allocator_; | 
					
						
							|  |  |  |   VectorSet<std::string> names_; | 
					
						
							|  |  |  |   Vector<const CPPType *> types_; | 
					
						
							|  |  |  |   Vector<void *> defaults_; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   friend AttributesInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   AttributesInfoBuilder() = default; | 
					
						
							|  |  |  |   ~AttributesInfoBuilder(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> void add(StringRef name, const T &default_value) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     this->add(name, CPPType::get<T>(), (const void *)&default_value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void add(StringRef name, const CPPType &type, const void *default_value = nullptr); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique | 
					
						
							|  |  |  |  * name, a type and a default value. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class AttributesInfo : NonCopyable, NonMovable { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   LinearAllocator<> allocator_; | 
					
						
							|  |  |  |   Map<StringRefNull, uint> index_by_name_; | 
					
						
							|  |  |  |   Vector<StringRefNull> name_by_index_; | 
					
						
							|  |  |  |   Vector<const CPPType *> type_by_index_; | 
					
						
							|  |  |  |   Vector<void *> defaults_; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   AttributesInfo() = default; | 
					
						
							|  |  |  |   AttributesInfo(const AttributesInfoBuilder &builder); | 
					
						
							|  |  |  |   ~AttributesInfo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint size() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return name_by_index_.size(); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   IndexRange index_range() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return name_by_index_.index_range(); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   StringRefNull name_of(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return name_by_index_[index]; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint index_of(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return index_by_name_.lookup_as(name); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const void *default_of(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return defaults_[index]; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const void *default_of(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->default_of(this->index_of(name)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> const T &default_of(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(type_by_index_[index]->is<T>()); | 
					
						
							|  |  |  |     return *(T *)defaults_[index]; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> const T &default_of(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->default_of<T>(this->index_of(name)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const CPPType &type_of(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return *type_by_index_[index]; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const CPPType &type_of(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->type_of(this->index_of(name)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool has_attribute(StringRef name, const CPPType &type) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->try_index_of(name, type) >= 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int try_index_of(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return (int)index_by_name_.lookup_default_as(name, -1); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int try_index_of(StringRef name, const CPPType &type) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int index = this->try_index_of(name); | 
					
						
							|  |  |  |     if (index == -1) { | 
					
						
							|  |  |  |       return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (this->type_of((uint)index) == type) { | 
					
						
							|  |  |  |       return index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * References multiple arrays that match the description of an AttributesInfo instance. This class | 
					
						
							|  |  |  |  * is supposed to be relatively cheap to copy. It does not own any of the arrays itself. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class MutableAttributesRef { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   const AttributesInfo *info_; | 
					
						
							|  |  |  |   Span<void *> buffers_; | 
					
						
							|  |  |  |   IndexRange range_; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 17:05:40 +02:00
										 |  |  |   friend class AttributesRef; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |  public: | 
					
						
							|  |  |  |   MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, uint size) | 
					
						
							|  |  |  |       : MutableAttributesRef(info, buffers, IndexRange(size)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, IndexRange range) | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |       : info_(&info), buffers_(buffers), range_(range) | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint size() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return range_.size(); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const AttributesInfo &info() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return *info_; | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GMutableSpan get(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     const CPPType &type = info_->type_of(index); | 
					
						
							|  |  |  |     void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); | 
					
						
							|  |  |  |     return GMutableSpan(type, ptr, range_.size()); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GMutableSpan get(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return this->get(info_->index_of(name)); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> MutableSpan<T> get(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(info_->type_of(index).is<T>()); | 
					
						
							|  |  |  |     return MutableSpan<T>((T *)buffers_[index] + range_.start(), range_.size()); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> MutableSpan<T> get(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return this->get<T>(info_->index_of(name)); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 14:29:05 +02:00
										 |  |  |   std::optional<GMutableSpan> try_get(StringRef name, const CPPType &type) const | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     int index = info_->try_index_of(name, type); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |     if (index == -1) { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       return this->get((uint)index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 14:29:05 +02:00
										 |  |  |   template<typename T> std::optional<MutableSpan<T>> try_get(StringRef name) const | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     int index = info_->try_index_of(name); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |     if (index == -1) { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     else if (info_->type_of((uint)index).is<T>()) { | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |       return this->get<T>((uint)index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MutableAttributesRef slice(IndexRange range) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->slice(range.start(), range.size()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MutableAttributesRef slice(uint start, uint size) const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return MutableAttributesRef(*info_, buffers_, range_.slice(start, size)); | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 17:05:40 +02:00
										 |  |  | class AttributesRef { | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   const AttributesInfo *info_; | 
					
						
							|  |  |  |   Span<const void *> buffers_; | 
					
						
							|  |  |  |   IndexRange range_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   AttributesRef(const AttributesInfo &info, Span<const void *> buffers, uint size) | 
					
						
							|  |  |  |       : AttributesRef(info, buffers, IndexRange(size)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   AttributesRef(const AttributesInfo &info, Span<const void *> buffers, IndexRange range) | 
					
						
							|  |  |  |       : info_(&info), buffers_(buffers), range_(range) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   AttributesRef(MutableAttributesRef attributes) | 
					
						
							|  |  |  |       : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint size() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return range_.size(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const AttributesInfo &info() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return *info_; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GSpan get(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const CPPType &type = info_->type_of(index); | 
					
						
							|  |  |  |     const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); | 
					
						
							|  |  |  |     return GSpan(type, ptr, range_.size()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GSpan get(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->get(info_->index_of(name)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> Span<T> get(uint index) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     BLI_assert(info_->type_of(index).is<T>()); | 
					
						
							|  |  |  |     return Span<T>((T *)buffers_[index] + range_.start(), range_.size()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> Span<T> get(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->get<T>(info_->index_of(name)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::optional<GSpan> try_get(StringRef name, const CPPType &type) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int index = info_->try_index_of(name, type); | 
					
						
							|  |  |  |     if (index == -1) { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       return this->get((uint)index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> std::optional<Span<T>> try_get(StringRef name) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int index = info_->try_index_of(name); | 
					
						
							|  |  |  |     if (index == -1) { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (info_->type_of((uint)index).is<T>()) { | 
					
						
							|  |  |  |       return this->get<T>((uint)index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   AttributesRef slice(IndexRange range) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return this->slice(range.start(), range.size()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   AttributesRef slice(uint start, uint size) const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return AttributesRef(*info_, buffers_, range_.slice(start, size)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | }  // namespace blender::fn
 | 
					
						
							| 
									
										
										
										
											2020-06-27 20:58:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif /* __FN_ATTRIBUTES_REF_HH__ */
 |