| 
									
										
										
										
											2020-06-16 16:35:57 +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_GENERIC_VECTOR_ARRAY_HH__
 | 
					
						
							|  |  |  | #define __FN_GENERIC_VECTOR_ARRAY_HH__
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup fn | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * A `GVectorArray` is a container for a fixed amount of dynamically growing arrays with a generic | 
					
						
							|  |  |  |  * type. Its main use case is to store many small vectors with few separate allocations. Using this | 
					
						
							|  |  |  |  * structure is generally more efficient than allocating each small vector separately. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * `GVectorArrayRef<T>` is a typed reference to a GVectorArray and makes it easier and safer to | 
					
						
							|  |  |  |  * work with the class when the type is known at compile time. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "FN_array_spans.hh"
 | 
					
						
							|  |  |  | #include "FN_cpp_type.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_array.hh"
 | 
					
						
							|  |  |  | #include "BLI_linear_allocator.hh"
 | 
					
						
							|  |  |  | #include "BLI_utility_mixins.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | namespace blender::fn { | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | template<typename T> class GVectorArrayRef; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GVectorArray : NonCopyable, NonMovable { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   const CPPType &type_; | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   int64_t element_size_; | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   Array<void *, 1> starts_; | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   Array<int64_t, 1> lengths_; | 
					
						
							|  |  |  |   Array<int64_t, 1> capacities_; | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   LinearAllocator<> allocator_; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   template<typename T> friend class GVectorArrayRef; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   GVectorArray() = delete; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   GVectorArray(const CPPType &type, int64_t array_size) | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |       : type_(type), | 
					
						
							|  |  |  |         element_size_(type.size()), | 
					
						
							|  |  |  |         starts_(array_size), | 
					
						
							|  |  |  |         lengths_(array_size), | 
					
						
							|  |  |  |         capacities_(array_size) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     starts_.as_mutable_span().fill(nullptr); | 
					
						
							|  |  |  |     lengths_.as_mutable_span().fill(0); | 
					
						
							|  |  |  |     capacities_.as_mutable_span().fill(0); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ~GVectorArray() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     if (type_.is_trivially_destructible()) { | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     for (int64_t i : starts_.index_range()) { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |       type_.destruct_n(starts_[i], lengths_[i]); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   operator GVArraySpan() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-08 22:29:10 +02:00
										 |  |  |     return GVArraySpan(type_, starts_, lengths_); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool is_empty() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return starts_.size() == 0; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   int64_t size() const | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return starts_.size(); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const CPPType &type() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return type_; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Span<const void *> starts() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-08 22:29:10 +02:00
										 |  |  |     return starts_; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   Span<int64_t> lengths() const | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return lengths_; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void append(int64_t index, const void *src) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     int64_t old_length = lengths_[index]; | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     if (old_length == capacities_[index]) { | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |       this->grow_at_least_one(index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     void *dst = POINTER_OFFSET(starts_[index], element_size_ * old_length); | 
					
						
							|  |  |  |     type_.copy_to_uninitialized(src, dst); | 
					
						
							|  |  |  |     lengths_[index]++; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void extend(int64_t index, GVSpan span) | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(type_ == span.type()); | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     for (int64_t i = 0; i < span.size(); i++) { | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |       this->append(index, span[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void extend(IndexMask mask, GVArraySpan array_span) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(type_ == array_span.type()); | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |     BLI_assert(mask.min_array_size() <= array_span.size()); | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     for (int64_t i : mask) { | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |       this->extend(i, array_span[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   GMutableSpan operator[](int64_t index) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(index < starts_.size()); | 
					
						
							|  |  |  |     return GMutableSpan(type_, starts_[index], lengths_[index]); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   template<typename T> GVectorArrayRef<T> typed() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return GVectorArrayRef<T>(*this); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void grow_at_least_one(int64_t index) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(lengths_[index] == capacities_[index]); | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |     int64_t new_capacity = lengths_[index] * 2 + 1; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     void *new_buffer = allocator_.allocate(element_size_ * new_capacity, type_.alignment()); | 
					
						
							|  |  |  |     type_.relocate_to_uninitialized_n(starts_[index], new_buffer, lengths_[index]); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     starts_[index] = new_buffer; | 
					
						
							|  |  |  |     capacities_[index] = new_capacity; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> class GVectorArrayRef { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   GVectorArray *vector_array_; | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   GVectorArrayRef(GVectorArray &vector_array) : vector_array_(&vector_array) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(vector_array.type_.is<T>()); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void append(int64_t index, const T &value) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     vector_array_->append(index, &value); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void extend(int64_t index, Span<T> values) | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     vector_array_->extend(index, values); | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   void extend(int64_t index, VSpan<T> values) | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     vector_array_->extend(index, GVSpan(values)); | 
					
						
							| 
									
										
										
										
											2020-06-22 15:48:08 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   MutableSpan<T> operator[](int64_t index) | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     BLI_assert(index < vector_array_->starts_.size()); | 
					
						
							|  |  |  |     return MutableSpan<T>((T *)vector_array_->starts_[index], vector_array_->lengths_[index]); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   int64_t size() const | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return vector_array_->size(); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool is_empty() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     return vector_array_->is_empty(); | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | }  // namespace blender::fn
 | 
					
						
							| 
									
										
										
										
											2020-06-16 16:35:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif /* __FN_GENERIC_VECTOR_ARRAY_HH__ */
 |