[Bf-blender-cvs] [aaef6e6e3af] functions: comment on tuple

Jacques Lucke noreply at git.blender.org
Tue Jul 2 18:39:16 CEST 2019


Commit: aaef6e6e3af5484ab922d1c55b1eb7ccd5080625
Author: Jacques Lucke
Date:   Tue Jul 2 18:38:06 2019 +0200
Branches: functions
https://developer.blender.org/rBaaef6e6e3af5484ab922d1c55b1eb7ccd5080625

comment on tuple

===================================================================

M	source/blender/functions/backends/tuple/tuple.cpp
M	source/blender/functions/backends/tuple/tuple.hpp

===================================================================

diff --git a/source/blender/functions/backends/tuple/tuple.cpp b/source/blender/functions/backends/tuple/tuple.cpp
index 98dabd1de89..805ff2246dc 100644
--- a/source/blender/functions/backends/tuple/tuple.cpp
+++ b/source/blender/functions/backends/tuple/tuple.cpp
@@ -2,6 +2,24 @@
 
 namespace FN {
 
+TupleMeta::TupleMeta(ArrayRef<SharedType> types) : m_types(types)
+{
+  m_all_trivially_destructible = true;
+  m_size__data = 0;
+  for (const SharedType &type : types) {
+    CPPTypeInfo *info = type->extension<CPPTypeInfo>();
+    m_offsets.append(m_size__data);
+    m_type_info.append(info);
+    m_size__data += info->size_of_type();
+    if (!info->trivially_destructible()) {
+      m_all_trivially_destructible = false;
+    }
+  }
+  m_offsets.append(m_size__data);
+
+  m_size__data_and_init = m_size__data + this->element_amount();
+}
+
 void Tuple::print_initialized(std::string name)
 {
   std::cout << "Tuple: " << name << std::endl;
diff --git a/source/blender/functions/backends/tuple/tuple.hpp b/source/blender/functions/backends/tuple/tuple.hpp
index f66c121e54a..7818c25f9f3 100644
--- a/source/blender/functions/backends/tuple/tuple.hpp
+++ b/source/blender/functions/backends/tuple/tuple.hpp
@@ -1,5 +1,36 @@
 #pragma once
 
+/**
+ * A tuple is an array that can hold values of different types. It is the primary way to store
+ * values of C++ types that you don't know the exact type from.
+ *
+ * Every tuple links to a TupleMeta instance which contains meta-information about the tuple. Among
+ * others it knows which types are stored in the tuple and at which offsets. Furthermore, it owns
+ * references to the types. The assumption here is that tuples are much more often created than
+ * meta objects. Doing reference counting every time a tuple is created would result in lot of
+ * synchronization overhead.
+ *
+ * Currently, tuples only have normal pointers to their meta objects. So it can be invalidated when
+ * it outlives the meta object. In the future it might be necessary to allow tuples to optionally
+ * own the tuple meta object, so that it cannot be removed as long as it exists.
+ *
+ * Tuples can be allocated entirely on the stack to avoid heap allocations. However, due to their
+ * dynamic nature, the required memory can differ. There is a macro to simplify the process of
+ * allocating a tuple on the stack.
+ *
+ * A tuple can own the array containing the objects or not, depending on the use case.
+ *
+ * Every element in the tuple is either initialized or uninitialized. It is explicitely tracked
+ * what is the case.
+ *
+ * The accessors to the tuple fall into two categories:
+ *   - Dynamic: When the caller does not know statically which types the tuple contains, it has to
+ *       use generic methods. This is less efficient since there might be multiple virtual function
+ *       calls.
+ *   - Static: Sometimes, the caller knows exactly, which types are at every index in the tuple. In
+ *       that case, this information can be used to increase performance and to get a nicer API.
+ */
+
 #include "cpp_types.hpp"
 
 namespace FN {
@@ -14,54 +45,59 @@ class TupleMeta : public RefCountedBase {
   bool m_all_trivially_destructible;
 
  public:
-  TupleMeta(ArrayRef<SharedType> types = {}) : m_types(types)
-  {
-    m_all_trivially_destructible = true;
-    m_size__data = 0;
-    for (const SharedType &type : types) {
-      CPPTypeInfo *info = type->extension<CPPTypeInfo>();
-      m_offsets.append(m_size__data);
-      m_type_info.append(info);
-      m_size__data += info->size_of_type();
-      if (!info->trivially_destructible()) {
-        m_all_trivially_destructible = false;
-      }
-    }
-    m_offsets.append(m_size__data);
-
-    m_size__data_and_init = m_size__data + this->element_amount();
-  }
+  TupleMeta(ArrayRef<SharedType> types = {});
 
+  /**
+   * Get an array containing the types of tuples using the meta object.
+   */
   const ArrayRef<SharedType> types() const
   {
     return m_types;
   }
 
+  /**
+   * Get an array containing the CPPTypeInfo instances of all types.
+   */
   const ArrayRef<CPPTypeInfo *> type_infos() const
   {
     return m_type_info;
   }
 
+  /**
+   * Get an array containing the byte offsets of every element in the array.
+   */
   const ArrayRef<uint> offsets() const
   {
     return m_offsets;
   }
 
+  /**
+   * Get the required byte size to store all values in the tuple.
+   */
   uint size_of_data() const
   {
     return m_size__data;
   }
 
+  /**
+   * Get the size of the boolean buffer that tracks which elements are initialized.
+   */
   uint size_of_init() const
   {
     return m_size__data_and_init - m_size__data;
   }
 
+  /**
+   * Get the size of the data and initialize buffers combined.
+   */
   uint size_of_data_and_init() const
   {
     return m_size__data_and_init;
   }
 
+  /**
+   * Get the buffer size that is required to construct the entire tuple in.
+   */
   inline uint size_of_full_tuple() const;
 
   uint element_amount() const
@@ -69,11 +105,18 @@ class TupleMeta : public RefCountedBase {
     return m_types.size();
   }
 
+  /**
+   * Get the byte size of a specific element.
+   */
   uint element_size(uint index) const
   {
     return m_offsets[index + 1] - m_offsets[index];
   }
 
+  /**
+   * Return when all types are trivially destructible. Otherwise false.
+   * When all types are destructible, no deallocation loop has to run.
+   */
   bool all_trivially_destructible() const
   {
     return m_all_trivially_destructible;
@@ -114,6 +157,10 @@ class Tuple {
   {
   }
 
+  /**
+   * Build a new tuple in the prepared buffer. The memory in the buffer is expected to be
+   * uninitialized. Furthermore, the buffer must be large enough to hold the entire tuple.
+   */
   static Tuple &ConstructInBuffer(TupleMeta &meta, void *buffer)
   {
     Tuple *tuple = new (buffer) Tuple(meta, (char *)buffer + sizeof(Tuple));
@@ -134,16 +181,20 @@ class Tuple {
     }
   }
 
+  /**
+   * Copy a value of type T to the given index. The caller is expected to know that T actually
+   * belongs to this type.
+   */
   template<typename T> inline void copy_in(uint index, const T &value)
   {
     BLI_assert(index < m_meta->element_amount());
     BLI_assert(sizeof(T) == m_meta->element_size(index));
 
+    T *dst = (T *)this->element_ptr(index);
     if (std::is_trivial<T>::value) {
-      std::memcpy(this->element_ptr(index), &value, sizeof(T));
+      std::memcpy(dst, &value, sizeof(T));
     }
     else {
-      T *dst = (T *)this->element_ptr(index);
 
       if (m_initialized[index]) {
         std::copy_n(&value, 1, dst);
@@ -156,6 +207,9 @@ class Tuple {
     m_initialized[index] = true;
   }
 
+  /**
+   * Copy a value from src to the given index in the tuple.
+   */
   inline void copy_in__dynamic(uint index, void *src)
   {
     BLI_assert(index < m_meta->element_amount());
@@ -173,6 +227,11 @@ class Tuple {
     }
   }
 
+  /**
+   * Move a value of type T into the tuple. Note, that the destructor on the original object will
+   * not be called, because this will usually be done automatically when it goes out of scope.
+   * The caller is expected to know that the type T actually belongs to this index.
+   */
   template<typename T> inline void move_in(uint index, T &value)
   {
     BLI_assert(index < m_meta->element_amount());
@@ -189,6 +248,9 @@ class Tuple {
     }
   }
 
+  /**
+   * Copy the value from src into the tuple and destroy the original value at src.
+   */
   inline void relocate_in__dynamic(uint index, void *src)
   {
     BLI_assert(index < m_meta->element_amount());
@@ -206,12 +268,20 @@ class Tuple {
     }
   }
 
+  /**
+   * Copy the value to the given index. This method only works with trivial types.
+   */
   template<typename T> inline void set(uint index, const T &value)
   {
     static_assert(std::is_trivial<T>::value, "this method can be used with trivial types only");
     this->copy_in<T>(index, value);
   }
 
+  /**
+   * Return a copy of the value at the given index. The caller is expected to know that the index
+   * actually contains a value of type T.
+   * Asserts when the value was not initialized.
+   */
   template<typename T> inline T copy_out(uint index) const
   {
     BLI_assert(index < m_meta->element_amount());
@@ -221,6 +291,12 @@ class Tuple {
     return *(T *)this->element_ptr(index);
   }
 
+  /**
+   * Return the value at the given index and destroy the value in the tuple. Afterwards, this index
+   * will contain uininitialized memory. The caller is expected to know that T is the correct type
+   * for that index.
+   * Asserts when the value was not initialized.
+   */
   template<typename T> inline T relocate_out(uint index) const
   {
     BLI_assert(index < m_meta->element_amount());
@@ -235,6 +311,10 @@ class Tuple {
     return tmp;
   }
 
+  /**
+   * Copy the value from the tuple into the dst buffer.
+   * Asserts when the value was not initialized.
+   */
   inline void relocate_out__dynamic(uint index, void *dst) const
   {
     BLI_assert(index < m_meta->element_amount());
@@ -249,12 +329,21 @@ class Tuple {
     m_initialized[index] = false;
   }
 
+  /**
+   * Return a copy of the value in the tuple at the given index. This only works with trivial
+   * types.
+   * Asserts when the value was not initialized.
+   */
   template<typename T> inline T get(uint index) const
   {
     static_assert(std::is_trivial<T>::value, "this method can be used with trivial types only");
     return this->copy_out<T>(index);
   }
 
+  /**
+   * Return a reference to a value in the tuple.
+   * Asserts when the value is not initialized.
+   */
   template<typename T> inline T &get_ref(uint index) const
   {
     BLI_assert(index < m_meta->element_amount());
@@ -262,12 +351,19 @@ class Tuple {
     return this->element_ref<T>(index);
   }
 
+  /**
+   * Return true when the value at the given index is initialized, otherwise false.
+   */
   inline bool is_initialized(uint index) const
   {
     BLI_assert(index < m_meta->element_amount());
     return m_initialized[index];
   }
 
+  /**
+   * Copy a value between two different location in different tuples.
+   * Asserts when the source value is not initialized

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list