Functions: Run-time type system and index mask

This adds a new `CPPType` that encapsulates information about how to handle
instances of a specific data type. This is necessary for the function evaluation
system, which will be used to evaluate most of the particle node trees.

Furthermore, this adds an `IndexMask` class which offers a surprisingly useful
abstraction over an array containing unsigned integers. It makes two assumptions
about the underlying integer array:
* The integers are in ascending order.
* There are no duplicates.

`IndexMask` will be used to "select" certain particles that will be
processed in a data-oriented way. Sometimes, operations don't have to
be applied to all particles, but only some, those that are in the indexed by
the `IndexMask`. The two limitations imposed by an `IndexMask` allow for
better performance.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D7957
This commit is contained in:
Jacques Lucke 2020-06-08 17:37:43 +02:00
parent b5846ebce7
commit 0a907657d4
12 changed files with 1448 additions and 0 deletions

View File

@ -114,6 +114,7 @@ add_subdirectory(modifiers)
add_subdirectory(gpencil_modifiers)
add_subdirectory(shader_fx)
add_subdirectory(io)
add_subdirectory(functions)
add_subdirectory(makesdna)
add_subdirectory(makesrna)

View File

@ -0,0 +1,212 @@
/*
* 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 __BLI_INDEX_MASK_HH__
#define __BLI_INDEX_MASK_HH__
/** \file
* \ingroup bli
*
* An IndexMask references an array of unsigned integers with the following property:
* The integers must be in ascending order and there must not be duplicates.
*
* Remember that the array is only referenced and not owned by an IndexMask instance.
*
* In most cases the integers in the array represent some indices into another array. So they
* "select" or "mask" a some elements in that array. Hence the name IndexMask.
*
* The invariant stated above has the nice property that it makes it easy to check if an integer
* array is an IndexRange, i.e. no indices are skipped. That allows functions to implement two code
* paths: One where it iterates over the index array and one where it iterates over the index
* range. The latter one is more efficient due to less memory reads and potential usage of SIMD
* instructions.
*
* The IndexMask.foreach_index method helps writing code that implements both code paths at the
* same time.
*/
#include "BLI_array_ref.hh"
#include "BLI_index_range.hh"
namespace BLI {
class IndexMask {
private:
/* The underlying reference to sorted integers. */
ArrayRef<uint> m_indices;
public:
/* Creates an IndexMask that contains no indices. */
IndexMask() = default;
/**
* Create an IndexMask using the given integer array.
* This constructor asserts that the given integers are in ascending order and that there are no
* duplicates.
*/
IndexMask(ArrayRef<uint> indices) : m_indices(indices)
{
#ifdef DEBUG
for (uint i = 1; i < indices.size(); i++) {
BLI_assert(indices[i - 1] < indices[i]);
}
#endif
}
/**
* Use this method when you know that no indices are skipped. It is more efficient than preparing
* an integer array all the time.
*/
IndexMask(IndexRange range) : m_indices(range.as_array_ref())
{
}
/**
* Construct an IndexMask from a sorted list of indices. Note, the created IndexMask is only
* valid as long as the initializer_list is valid.
*
* Don't do this:
* IndexMask mask = {3, 4, 5};
*
* Do this:
* do_something_with_an_index_mask({3, 4, 5});
*/
IndexMask(const std::initializer_list<uint> &indices) : IndexMask(ArrayRef<uint>(indices))
{
}
/**
* Creates an IndexMask that references the indices [0, n-1].
*/
explicit IndexMask(uint n) : IndexMask(IndexRange(n))
{
}
operator ArrayRef<uint>() const
{
return m_indices;
}
const uint *begin() const
{
return m_indices.begin();
}
const uint *end() const
{
return m_indices.end();
}
/**
* Returns the n-th index referenced by this IndexMask. The `index_mask` method returns an
* IndexRange containing all indices that can be used as parameter here.
*/
uint operator[](uint n) const
{
return m_indices[n];
}
/**
* Returns the minimum size an array has to have, if the integers in this IndexMask are going to
* be used as indices in that array.
*/
uint min_array_size() const
{
if (m_indices.size() == 0) {
return 0;
}
else {
return m_indices.last() + 1;
}
}
ArrayRef<uint> indices() const
{
return m_indices;
}
/**
* Returns true if this IndexMask does not skip any indices. This check requires O(1) time.
*/
bool is_range() const
{
return m_indices.size() > 0 && m_indices.last() - m_indices.first() == m_indices.size() - 1;
}
/**
* Returns the IndexRange referenced by this IndexMask. This method should only be called after
* the caller made sure that this IndexMask is actually a range.
*/
IndexRange as_range() const
{
BLI_assert(this->is_range());
return IndexRange{m_indices.first(), m_indices.size()};
}
/**
* Calls the given callback for every referenced index. The callback has to take one unsigned
* integer as parameter.
*
* This method implements different code paths for the cases when the IndexMask represents a
* range or not.
*/
template<typename CallbackT> void foreach_index(const CallbackT &callback) const
{
if (this->is_range()) {
IndexRange range = this->as_range();
for (uint i : range) {
callback(i);
}
}
else {
for (uint i : m_indices) {
callback(i);
}
}
}
/**
* Returns an IndexRange that can be used to index this IndexMask.
*
* The range is [0, number of indices - 1].
*
* This is not to be confused with the `as_range` method.
*/
IndexRange index_range() const
{
return m_indices.index_range();
}
/**
* Returns the largest index that is referenced by this IndexMask.
*/
uint last() const
{
return m_indices.last();
}
/**
* Returns the number of indices referenced by this IndexMask.
*/
uint size() const
{
return m_indices.size();
}
};
} // namespace BLI
#endif /* __BLI_INDEX_MASK_HH__ */

View File

@ -189,6 +189,7 @@ set(SRC
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
BLI_index_mask.hh
BLI_index_range.hh
BLI_iterator.h
BLI_jitter_2d.h

View File

@ -0,0 +1,40 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../blenlib
../makesdna
../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
intern/cpp_types.cc
FN_cpp_type.hh
FN_cpp_types.hh
)
set(LIB
bf_blenlib
)
blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -0,0 +1,726 @@
/*
* 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_CPP_TYPE_HH__
#define __FN_CPP_TYPE_HH__
/** \file
* \ingroup functions
*
* The CPPType class is the core of the runtime-type-system used by the functions system. An
* instance of this class can represent any C++ type, that is default-constructable, destructable,
* movable and copyable. Therefore it also works for all C types. This restrictions might need to
* be removed in the future, but for now every required type has these properties.
*
* Every type has a size and an alignment. Every function dealing with C++ types in a generic way,
* has to make sure that alignment rules are followed. The methods provided by a CPPType instance
* will check for correct alignment as well.
*
* Every type has a name that is for debugging purposes only. It should not be used as identifier.
*
* To check if two instances of CPPType represent the same type, only their pointers have to be
* compared. Any C++ type has at most one corresponding CPPType instance.
*
* A CPPType instance comes with many methods that allow dealing with types in a generic way. Most
* methods come in three variants. Using the construct-default methods as example:
* - construct_default(void *ptr):
* Constructs a single instance of that type at the given pointer.
* - construct_default_n(void *ptr, uint n):
* Constructs n instances of that type in an array that starts at the given pointer.
* - construct_default_indices(void *ptr, IndexMask index_mask):
* Constructs multiple instances of that type in an array that starts at the given pointer.
* Only the indices referenced by `index_mask` will by constructed.
*
* In some cases default-construction does nothing (e.g. for trivial types like int). The
* `default_value` method provides some default value anyway that can be copied instead. What the
* default value is, depends on the type. Usually it is something like 0 or an empty string.
*
*
* Implementation Considerations
* -----------------------------
*
* Concepts like inheritance are currently not captured by this system. This is not because it is
* not possible, but because it was not necessary to add this complexity yet.
*
* One could also implement CPPType itself using virtual inheritance. However, I found the approach
* used now with explicit function pointers to work better. Here are some reasons:
* - If CPPType would be inherited once for every used C++ type, we would get a lot of classes
* that would only be instanced once each.
* - Methods like `construct_default` that operate on a single instance have to be fast. Even this
* one necessary indirection using function pointers adds a lot of overhead. If all methods were
* virtual, there would be a second level of indirection that increases the overhead even more.
* - If it becomes necessary, we could pass the function pointers to C functions more easily than
* pointers to virtual member functions.
*/
#include "BLI_index_mask.hh"
#include "BLI_math_base.h"
#include "BLI_string_ref.hh"
namespace FN {
using BLI::IndexMask;
using BLI::StringRef;
using BLI::StringRefNull;
class CPPType {
public:
using ConstructDefaultF = void (*)(void *ptr);
using ConstructDefaultNF = void (*)(void *ptr, uint n);
using ConstructDefaultIndicesF = void (*)(void *ptr, IndexMask index_mask);
using DestructF = void (*)(void *ptr);
using DestructNF = void (*)(void *ptr, uint n);
using DestructIndicesF = void (*)(void *ptr, IndexMask index_mask);
using CopyToInitializedF = void (*)(const void *src, void *dst);
using CopyToInitializedNF = void (*)(const void *src, void *dst, uint n);
using CopyToInitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
using CopyToUninitializedF = void (*)(const void *src, void *dst);
using CopyToUninitializedNF = void (*)(const void *src, void *dst, uint n);
using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask index_mask);
using RelocateToInitializedF = void (*)(void *src, void *dst);
using RelocateToInitializedNF = void (*)(void *src, void *dst, uint n);
using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
using RelocateToUninitializedF = void (*)(void *src, void *dst);
using RelocateToUninitializedNF = void (*)(void *src, void *dst, uint n);
using RelocateToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask index_mask);
using FillInitializedF = void (*)(const void *value, void *dst, uint n);
using FillInitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
using FillUninitializedF = void (*)(const void *value, void *dst, uint n);
using FillUninitializedIndicesF = void (*)(const void *value, void *dst, IndexMask index_mask);
CPPType(std::string name,
uint size,
uint alignment,
bool is_trivially_destructible,
ConstructDefaultF construct_default,
ConstructDefaultNF construct_default_n,
ConstructDefaultIndicesF construct_default_indices,
DestructF destruct,
DestructNF destruct_n,
DestructIndicesF destruct_indices,
CopyToInitializedF copy_to_initialized,
CopyToInitializedNF copy_to_initialized_n,
CopyToInitializedIndicesF copy_to_initialized_indices,
CopyToUninitializedF copy_to_uninitialized,
CopyToUninitializedNF copy_to_uninitialized_n,
CopyToUninitializedIndicesF copy_to_uninitialized_indices,
RelocateToInitializedF relocate_to_initialized,
RelocateToInitializedNF relocate_to_initialized_n,
RelocateToInitializedIndicesF relocate_to_initialized_indices,
RelocateToUninitializedF relocate_to_uninitialized,
RelocateToUninitializedNF relocate_to_uninitialized_n,
RelocateToUninitializedIndicesF relocate_to_uninitialized_indices,
FillInitializedF fill_initialized,
FillInitializedIndicesF fill_initialized_indices,
FillUninitializedF fill_uninitialized,
FillUninitializedIndicesF fill_uninitialized_indices,
const void *default_value)
: m_size(size),
m_alignment(alignment),
m_is_trivially_destructible(is_trivially_destructible),
m_construct_default(construct_default),
m_construct_default_n(construct_default_n),
m_construct_default_indices(construct_default_indices),
m_destruct(destruct),
m_destruct_n(destruct_n),
m_destruct_indices(destruct_indices),
m_copy_to_initialized(copy_to_initialized),
m_copy_to_initialized_n(copy_to_initialized_n),
m_copy_to_initialized_indices(copy_to_initialized_indices),
m_copy_to_uninitialized(copy_to_uninitialized),
m_copy_to_uninitialized_n(copy_to_uninitialized_n),
m_copy_to_uninitialized_indices(copy_to_uninitialized_indices),
m_relocate_to_initialized(relocate_to_initialized),
m_relocate_to_initialized_n(relocate_to_initialized_n),
m_relocate_to_initialized_indices(relocate_to_initialized_indices),
m_relocate_to_uninitialized(relocate_to_uninitialized),
m_relocate_to_uninitialized_n(relocate_to_uninitialized_n),
m_relocate_to_uninitialized_indices(relocate_to_uninitialized_indices),
m_fill_initialized(fill_initialized),
m_fill_initialized_indices(fill_initialized_indices),
m_fill_uninitialized(fill_uninitialized),
m_fill_uninitialized_indices(fill_uninitialized_indices),
m_default_value(default_value),
m_name(name)
{
BLI_assert(is_power_of_2_i(m_alignment));
m_alignment_mask = (uintptr_t)m_alignment - (uintptr_t)1;
}
/**
* Returns the name of the type for debugging purposes. This name should not be used as
* identifier.
*/
StringRefNull name() const
{
return m_name;
}
/**
* Required memory in bytes for an instance of this type.
*
* C++ equivalent:
* sizeof(T);
*/
uint size() const
{
return m_size;
}
/**
* Required memory alignment for an instance of this type.
*
* C++ equivalent:
* alignof(T);
*/
uint alignment() const
{
return m_alignment;
}
/**
* When true, the destructor does not have to be called on this type. This can sometimes be used
* for optimization purposes.
*
* C++ equivalent:
* std::is_trivially_destructible<T>::value;
*/
bool is_trivially_destructible() const
{
return m_is_trivially_destructible;
}
/**
* Returns true, when the given pointer fullfills the alignment requirement of this type.
*/
bool pointer_has_valid_alignment(const void *ptr) const
{
return ((uintptr_t)ptr & m_alignment_mask) == 0;
}
bool pointer_can_point_to_instance(const void *ptr) const
{
return ptr != nullptr && pointer_has_valid_alignment(ptr);
}
/**
* Call the default constructor at the given memory location.
* The memory should be uninitialized before this method is called.
* For some trivial types (like int), this method does nothing.
*
* C++ equivalent:
* new (ptr) T;
*/
void construct_default(void *ptr) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_construct_default(ptr);
}
void construct_default_n(void *ptr, uint n) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_construct_default_n(ptr, n);
}
void construct_default_indices(void *ptr, IndexMask index_mask) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_construct_default_indices(ptr, index_mask);
}
/**
* Call the destructor on the given instance of this type. The pointer must not be nullptr.
*
* For some trivial types, this does nothing.
*
* C++ equivalent:
* ptr->~T();
*/
void destruct(void *ptr) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_destruct(ptr);
}
void destruct_n(void *ptr, uint n) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_destruct_n(ptr, n);
}
void destruct_indices(void *ptr, IndexMask index_mask) const
{
BLI_assert(this->pointer_can_point_to_instance(ptr));
m_destruct_indices(ptr, index_mask);
}
/**
* Copy an instance of this type from src to dst.
*
* C++ equivalent:
* dst = src;
*/
void copy_to_initialized(const void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_initialized(src, dst);
}
void copy_to_initialized_n(const void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_initialized_n(src, dst, n);
}
void copy_to_initialized_indices(const void *src, void *dst, IndexMask index_mask) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_initialized_indices(src, dst, index_mask);
}
/**
* Copy an instance of this type from src to dst.
*
* The memory pointed to by dst should be uninitialized.
*
* C++ equivalent:
* new (dst) T(src);
*/
void copy_to_uninitialized(const void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_uninitialized(src, dst);
}
void copy_to_uninitialized_n(const void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_uninitialized_n(src, dst, n);
}
void copy_to_uninitialized_indices(const void *src, void *dst, IndexMask index_mask) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_copy_to_uninitialized_indices(src, dst, index_mask);
}
/**
* Relocates an instance of this type from src to dst. src will point to uninitialized memory
* afterwards.
*
* C++ equivalent:
* dst = std::move(src);
* src->~T();
*/
void relocate_to_initialized(void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_initialized(src, dst);
}
void relocate_to_initialized_n(void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_initialized_n(src, dst, n);
}
void relocate_to_initialized_indices(void *src, void *dst, IndexMask index_mask) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_initialized_indices(src, dst, index_mask);
}
/**
* Relocates an instance of this type from src to dst. src will point to uninitialized memory
* afterwards.
*
* C++ equivalent:
* new (dst) T(std::move(src))
* src->~T();
*/
void relocate_to_uninitialized(void *src, void *dst) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_uninitialized(src, dst);
}
void relocate_to_uninitialized_n(void *src, void *dst, uint n) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_uninitialized_n(src, dst, n);
}
void relocate_to_uninitialized_indices(void *src, void *dst, IndexMask index_mask) const
{
BLI_assert(src != dst);
BLI_assert(this->pointer_can_point_to_instance(src));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_relocate_to_uninitialized_indices(src, dst, index_mask);
}
/**
* Copy the given value to the first n elements in an array starting at dst.
*
* Other instances of the same type should live in the array before this method is called.
*/
void fill_initialized(const void *value, void *dst, uint n) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_fill_initialized(value, dst, n);
}
void fill_initialized_indices(const void *value, void *dst, IndexMask index_mask) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_fill_initialized_indices(value, dst, index_mask);
}
/**
* Copy the given value to the first n elements in an array starting at dst.
*
* The array should be uninitialized before this method is called.
*/
void fill_uninitialized(const void *value, void *dst, uint n) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_fill_uninitialized(value, dst, n);
}
void fill_uninitialized_indices(const void *value, void *dst, IndexMask index_mask) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
BLI_assert(this->pointer_can_point_to_instance(dst));
m_fill_uninitialized_indices(value, dst, index_mask);
}
/**
* Get a pointer to a constant value of this type. The specific value depends on the type.
* It is usually a zero-initialized or default constructed value.
*/
const void *default_value() const
{
return m_default_value;
}
/**
* Two types only compare equal when their pointer is equal. No two instances of CPPType for the
* same C++ type should be created.
*/
friend bool operator==(const CPPType &a, const CPPType &b)
{
return &a == &b;
}
friend bool operator!=(const CPPType &a, const CPPType &b)
{
return !(&a == &b);
}
template<typename T> static const CPPType &get();
private:
uint m_size;
uint m_alignment;
uintptr_t m_alignment_mask;
bool m_is_trivially_destructible;
ConstructDefaultF m_construct_default;
ConstructDefaultNF m_construct_default_n;
ConstructDefaultIndicesF m_construct_default_indices;
DestructF m_destruct;
DestructNF m_destruct_n;
DestructIndicesF m_destruct_indices;
CopyToInitializedF m_copy_to_initialized;
CopyToInitializedNF m_copy_to_initialized_n;
CopyToInitializedIndicesF m_copy_to_initialized_indices;
CopyToUninitializedF m_copy_to_uninitialized;
CopyToUninitializedNF m_copy_to_uninitialized_n;
CopyToUninitializedIndicesF m_copy_to_uninitialized_indices;
RelocateToInitializedF m_relocate_to_initialized;
RelocateToInitializedNF m_relocate_to_initialized_n;
RelocateToInitializedIndicesF m_relocate_to_initialized_indices;
RelocateToUninitializedF m_relocate_to_uninitialized;
RelocateToUninitializedNF m_relocate_to_uninitialized_n;
RelocateToUninitializedIndicesF m_relocate_to_uninitialized_indices;
FillInitializedF m_fill_initialized;
FillInitializedIndicesF m_fill_initialized_indices;
FillUninitializedF m_fill_uninitialized;
FillUninitializedIndicesF m_fill_uninitialized_indices;
const void *m_default_value;
std::string m_name;
};
/* --------------------------------------------------------------------
* Utility for creating CPPType instances for C++ types.
*/
namespace CPPTypeUtil {
template<typename T> void construct_default_cb(void *ptr)
{
BLI::construct_default((T *)ptr);
}
template<typename T> void construct_default_n_cb(void *ptr, uint n)
{
for (uint i = 0; i < n; i++) {
BLI::construct_default((T *)ptr + i);
}
}
template<typename T> void construct_default_indices_cb(void *ptr, IndexMask index_mask)
{
index_mask.foreach_index([&](uint i) { BLI::construct_default((T *)ptr + i); });
}
template<typename T> void destruct_cb(void *ptr)
{
BLI::destruct((T *)ptr);
}
template<typename T> void destruct_n_cb(void *ptr, uint n)
{
BLI::destruct_n((T *)ptr, n);
}
template<typename T> void destruct_indices_cb(void *ptr, IndexMask index_mask)
{
index_mask.foreach_index([&](uint i) { BLI::destruct((T *)ptr + i); });
}
template<typename T> void copy_to_initialized_cb(const void *src, void *dst)
{
*(T *)dst = *(T *)src;
}
template<typename T> void copy_to_initialized_n_cb(const void *src, void *dst, uint n)
{
const T *src_ = (const T *)src;
T *dst_ = (T *)dst;
for (uint i = 0; i < n; i++) {
dst_[i] = src_[i];
}
}
template<typename T>
void copy_to_initialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
{
const T *src_ = (const T *)src;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) { dst_[i] = src_[i]; });
}
template<typename T> void copy_to_uninitialized_cb(const void *src, void *dst)
{
BLI::uninitialized_copy_n((T *)src, 1, (T *)dst);
}
template<typename T> void copy_to_uninitialized_n_cb(const void *src, void *dst, uint n)
{
BLI::uninitialized_copy_n((T *)src, n, (T *)dst);
}
template<typename T>
void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask index_mask)
{
const T *src_ = (const T *)src;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) { new (dst_ + i) T(src_[i]); });
}
template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
{
BLI::relocate((T *)src, (T *)dst);
}
template<typename T> void relocate_to_initialized_n_cb(void *src, void *dst, uint n)
{
BLI::relocate_n((T *)src, n, (T *)dst);
}
template<typename T>
void relocate_to_initialized_indices_cb(void *src, void *dst, IndexMask index_mask)
{
T *src_ = (T *)src;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) {
dst_[i] = std::move(src_[i]);
src_[i].~T();
});
}
template<typename T> void relocate_to_uninitialized_cb(void *src, void *dst)
{
BLI::uninitialized_relocate((T *)src, (T *)dst);
}
template<typename T> void relocate_to_uninitialized_n_cb(void *src, void *dst, uint n)
{
BLI::uninitialized_relocate_n((T *)src, n, (T *)dst);
}
template<typename T>
void relocate_to_uninitialized_indices_cb(void *src, void *dst, IndexMask index_mask)
{
T *src_ = (T *)src;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) {
new (dst_ + i) T(std::move(src_[i]));
src_[i].~T();
});
}
template<typename T> void fill_initialized_cb(const void *value, void *dst, uint n)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
for (uint i = 0; i < n; i++) {
dst_[i] = value_;
}
}
template<typename T>
void fill_initialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) { dst_[i] = value_; });
}
template<typename T> void fill_uninitialized_cb(const void *value, void *dst, uint n)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
for (uint i = 0; i < n; i++) {
new (dst_ + i) T(value_);
}
}
template<typename T>
void fill_uninitialized_indices_cb(const void *value, void *dst, IndexMask index_mask)
{
const T &value_ = *(const T *)value;
T *dst_ = (T *)dst;
index_mask.foreach_index([&](uint i) { new (dst_ + i) T(value_); });
}
} // namespace CPPTypeUtil
template<typename T>
static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &default_value)
{
using namespace CPPTypeUtil;
const CPPType *type = new CPPType(name,
sizeof(T),
alignof(T),
std::is_trivially_destructible<T>::value,
construct_default_cb<T>,
construct_default_n_cb<T>,
construct_default_indices_cb<T>,
destruct_cb<T>,
destruct_n_cb<T>,
destruct_indices_cb<T>,
copy_to_initialized_cb<T>,
copy_to_initialized_n_cb<T>,
copy_to_initialized_indices_cb<T>,
copy_to_uninitialized_cb<T>,
copy_to_uninitialized_n_cb<T>,
copy_to_uninitialized_indices_cb<T>,
relocate_to_initialized_cb<T>,
relocate_to_initialized_n_cb<T>,
relocate_to_initialized_indices_cb<T>,
relocate_to_uninitialized_cb<T>,
relocate_to_uninitialized_n_cb<T>,
relocate_to_uninitialized_indices_cb<T>,
fill_initialized_cb<T>,
fill_initialized_indices_cb<T>,
fill_uninitialized_cb<T>,
fill_uninitialized_indices_cb<T>,
(const void *)&default_value);
return std::unique_ptr<const CPPType>(type);
}
} // namespace FN
#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \
static TYPE_NAME default_value_##IDENTIFIER; \
static std::unique_ptr<const FN::CPPType> CPPTYPE_##IDENTIFIER##_owner = \
FN::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \
const FN::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \
template<> const FN::CPPType &FN::CPPType::get<TYPE_NAME>() \
{ \
return CPPType_##IDENTIFIER; \
}
#endif /* __FN_CPP_TYPE_HH__ */

View File

@ -0,0 +1,48 @@
/*
* 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_CPP_TYPES_HH__
#define __FN_CPP_TYPES_HH__
/** \file
* \ingroup functions
*
* This header provides convenient access to CPPType instances for some core types like integer
* types.
*/
#include "FN_cpp_type.hh"
namespace FN {
extern const CPPType &CPPType_bool;
extern const CPPType &CPPType_float;
extern const CPPType &CPPType_float3;
extern const CPPType &CPPType_float4x4;
extern const CPPType &CPPType_int32;
extern const CPPType &CPPType_uint32;
extern const CPPType &CPPType_uint8;
extern const CPPType &CPPType_Color4f;
extern const CPPType &CPPType_Color4b;
extern const CPPType &CPPType_string;
} // namespace FN
#endif /* __FN_CPP_TYPES_HH__ */

View File

@ -0,0 +1,41 @@
/*
* 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.
*/
#include "FN_cpp_types.hh"
#include "BLI_color.hh"
#include "BLI_float2.hh"
#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
namespace FN {
MAKE_CPP_TYPE(bool, bool)
MAKE_CPP_TYPE(float, float)
MAKE_CPP_TYPE(float3, BLI::float3)
MAKE_CPP_TYPE(float4x4, BLI::float4x4)
MAKE_CPP_TYPE(int32, int32_t)
MAKE_CPP_TYPE(uint32, uint32_t)
MAKE_CPP_TYPE(uint8, uint8_t)
MAKE_CPP_TYPE(Color4f, BLI::Color4f)
MAKE_CPP_TYPE(Color4b, BLI::Color4b)
MAKE_CPP_TYPE(string, std::string)
} // namespace FN

View File

@ -17,6 +17,7 @@ if(WITH_GTESTS)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
add_subdirectory(functions)
if(WITH_CODEC_FFMPEG)
add_subdirectory(ffmpeg)
endif()

View File

@ -0,0 +1,39 @@
#include "BLI_index_mask.hh"
#include "testing/testing.h"
using namespace BLI;
TEST(index_mask, DefaultConstructor)
{
IndexMask mask;
EXPECT_EQ(mask.min_array_size(), 0);
EXPECT_EQ(mask.size(), 0);
}
TEST(index_mask, ArrayConstructor)
{
[](IndexMask mask) {
EXPECT_EQ(mask.size(), 4);
EXPECT_EQ(mask.min_array_size(), 8);
EXPECT_FALSE(mask.is_range());
EXPECT_EQ(mask[0], 3);
EXPECT_EQ(mask[1], 5);
EXPECT_EQ(mask[2], 6);
EXPECT_EQ(mask[3], 7);
}({3, 5, 6, 7});
}
TEST(index_mask, RangeConstructor)
{
IndexMask mask = IndexRange(3, 5);
EXPECT_EQ(mask.size(), 5);
EXPECT_EQ(mask.min_array_size(), 8);
EXPECT_EQ(mask.last(), 7);
EXPECT_TRUE(mask.is_range());
EXPECT_EQ(mask.as_range().first(), 3);
EXPECT_EQ(mask.as_range().last(), 7);
ArrayRef<uint> indices = mask.indices();
EXPECT_EQ(indices[0], 3);
EXPECT_EQ(indices[1], 4);
EXPECT_EQ(indices[2], 5);
}

View File

@ -50,6 +50,7 @@ BLENDER_TEST(BLI_ghash "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_heap "bf_blenlib")
BLENDER_TEST(BLI_heap_simple "bf_blenlib")
BLENDER_TEST(BLI_index_mask "bf_blenlib")
BLENDER_TEST(BLI_index_range "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_linear_allocator "bf_blenlib")

View File

@ -0,0 +1,39 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../source/blender/blenlib
../../../source/blender/functions
../../../source/blender/makesdna
../../../intern/guardedalloc
)
setup_libdirs()
include_directories(${INC})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
if(WITH_BUILDINFO)
set(BUILDINFO buildinfoobj)
endif()
BLENDER_TEST(FN_cpp_type "bf_blenlib;bf_functions;${BUILDINFO}")

View File

@ -0,0 +1,299 @@
/*
* 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.
*
*/
#include "testing/testing.h"
#include "FN_cpp_type.hh"
static const int default_constructed_value = 1;
static const int copy_constructed_value = 2;
static const int move_constructed_value = 3;
static const int copy_constructed_from_value = 4;
static const int move_constructed_from_value = 5;
static const int copy_assigned_value = 6;
static const int copy_assigned_from_value = 7;
static const int move_assigned_value = 8;
static const int move_assigned_from_value = 9;
static const int destructed_value = 10;
struct TestType {
mutable volatile int value;
TestType()
{
value = default_constructed_value;
}
~TestType()
{
value = destructed_value;
}
TestType(const TestType &other)
{
value = copy_constructed_value;
other.value = copy_constructed_from_value;
}
TestType(TestType &&other)
{
value = move_constructed_value;
other.value = move_constructed_from_value;
}
TestType &operator=(const TestType &other)
{
value = copy_assigned_value;
other.value = copy_assigned_from_value;
return *this;
}
TestType &operator=(TestType &&other)
{
value = move_assigned_value;
other.value = move_assigned_from_value;
return *this;
}
};
MAKE_CPP_TYPE(TestType, TestType)
TEST(cpp_type, Size)
{
EXPECT_EQ(CPPType_TestType.size(), sizeof(TestType));
}
TEST(cpp_type, Alignment)
{
EXPECT_EQ(CPPType_TestType.alignment(), alignof(TestType));
}
TEST(cpp_type, DefaultConstruction)
{
int buffer[10] = {0};
CPPType_TestType.construct_default((void *)buffer);
EXPECT_EQ(buffer[0], default_constructed_value);
EXPECT_EQ(buffer[1], 0);
CPPType_TestType.construct_default_n((void *)buffer, 3);
EXPECT_EQ(buffer[0], default_constructed_value);
EXPECT_EQ(buffer[1], default_constructed_value);
EXPECT_EQ(buffer[2], default_constructed_value);
EXPECT_EQ(buffer[3], 0);
CPPType_TestType.construct_default_indices((void *)buffer, {2, 5, 7});
EXPECT_EQ(buffer[2], default_constructed_value);
EXPECT_EQ(buffer[4], 0);
EXPECT_EQ(buffer[5], default_constructed_value);
EXPECT_EQ(buffer[6], 0);
EXPECT_EQ(buffer[7], default_constructed_value);
EXPECT_EQ(buffer[8], 0);
}
TEST(cpp_type, Destruct)
{
int buffer[10] = {0};
CPPType_TestType.destruct((void *)buffer);
EXPECT_EQ(buffer[0], destructed_value);
EXPECT_EQ(buffer[1], 0);
CPPType_TestType.destruct_n((void *)buffer, 3);
EXPECT_EQ(buffer[0], destructed_value);
EXPECT_EQ(buffer[1], destructed_value);
EXPECT_EQ(buffer[2], destructed_value);
EXPECT_EQ(buffer[3], 0);
CPPType_TestType.destruct_indices((void *)buffer, {2, 5, 7});
EXPECT_EQ(buffer[2], destructed_value);
EXPECT_EQ(buffer[4], 0);
EXPECT_EQ(buffer[5], destructed_value);
EXPECT_EQ(buffer[6], 0);
EXPECT_EQ(buffer[7], destructed_value);
EXPECT_EQ(buffer[8], 0);
}
TEST(cpp_type, CopyToUninitialized)
{
int buffer1[10] = {0};
int buffer2[10] = {0};
CPPType_TestType.copy_to_uninitialized((void *)buffer1, (void *)buffer2);
EXPECT_EQ(buffer1[0], copy_constructed_from_value);
EXPECT_EQ(buffer2[0], copy_constructed_value);
CPPType_TestType.copy_to_uninitialized_n((void *)buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1[0], copy_constructed_from_value);
EXPECT_EQ(buffer2[0], copy_constructed_value);
EXPECT_EQ(buffer1[1], copy_constructed_from_value);
EXPECT_EQ(buffer2[1], copy_constructed_value);
EXPECT_EQ(buffer1[2], copy_constructed_from_value);
EXPECT_EQ(buffer2[2], copy_constructed_value);
EXPECT_EQ(buffer1[3], 0);
EXPECT_EQ(buffer2[3], 0);
CPPType_TestType.copy_to_uninitialized_indices((void *)buffer1, (void *)buffer2, {2, 5, 7});
EXPECT_EQ(buffer1[2], copy_constructed_from_value);
EXPECT_EQ(buffer2[2], copy_constructed_value);
EXPECT_EQ(buffer1[4], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer1[5], copy_constructed_from_value);
EXPECT_EQ(buffer2[5], copy_constructed_value);
EXPECT_EQ(buffer1[6], 0);
EXPECT_EQ(buffer2[6], 0);
EXPECT_EQ(buffer1[7], copy_constructed_from_value);
EXPECT_EQ(buffer2[7], copy_constructed_value);
EXPECT_EQ(buffer1[8], 0);
EXPECT_EQ(buffer2[8], 0);
}
TEST(cpp_type, CopyToInitialized)
{
int buffer1[10] = {0};
int buffer2[10] = {0};
CPPType_TestType.copy_to_initialized((void *)buffer1, (void *)buffer2);
EXPECT_EQ(buffer1[0], copy_assigned_from_value);
EXPECT_EQ(buffer2[0], copy_assigned_value);
CPPType_TestType.copy_to_initialized_n((void *)buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1[0], copy_assigned_from_value);
EXPECT_EQ(buffer2[0], copy_assigned_value);
EXPECT_EQ(buffer1[1], copy_assigned_from_value);
EXPECT_EQ(buffer2[1], copy_assigned_value);
EXPECT_EQ(buffer1[2], copy_assigned_from_value);
EXPECT_EQ(buffer2[2], copy_assigned_value);
EXPECT_EQ(buffer1[3], 0);
EXPECT_EQ(buffer2[3], 0);
CPPType_TestType.copy_to_initialized_indices((void *)buffer1, (void *)buffer2, {2, 5, 7});
EXPECT_EQ(buffer1[2], copy_assigned_from_value);
EXPECT_EQ(buffer2[2], copy_assigned_value);
EXPECT_EQ(buffer1[4], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer1[5], copy_assigned_from_value);
EXPECT_EQ(buffer2[5], copy_assigned_value);
EXPECT_EQ(buffer1[6], 0);
EXPECT_EQ(buffer2[6], 0);
EXPECT_EQ(buffer1[7], copy_assigned_from_value);
EXPECT_EQ(buffer2[7], copy_assigned_value);
EXPECT_EQ(buffer1[8], 0);
EXPECT_EQ(buffer2[8], 0);
}
TEST(cpp_type, RelocateToUninitialized)
{
int buffer1[10] = {0};
int buffer2[10] = {0};
CPPType_TestType.relocate_to_uninitialized((void *)buffer1, (void *)buffer2);
EXPECT_EQ(buffer1[0], destructed_value);
EXPECT_EQ(buffer2[0], move_constructed_value);
CPPType_TestType.relocate_to_uninitialized_n((void *)buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1[0], destructed_value);
EXPECT_EQ(buffer2[0], move_constructed_value);
EXPECT_EQ(buffer1[1], destructed_value);
EXPECT_EQ(buffer2[1], move_constructed_value);
EXPECT_EQ(buffer1[2], destructed_value);
EXPECT_EQ(buffer2[2], move_constructed_value);
EXPECT_EQ(buffer1[3], 0);
EXPECT_EQ(buffer2[3], 0);
CPPType_TestType.relocate_to_uninitialized_indices((void *)buffer1, (void *)buffer2, {2, 5, 7});
EXPECT_EQ(buffer1[2], destructed_value);
EXPECT_EQ(buffer2[2], move_constructed_value);
EXPECT_EQ(buffer1[4], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer1[5], destructed_value);
EXPECT_EQ(buffer2[5], move_constructed_value);
EXPECT_EQ(buffer1[6], 0);
EXPECT_EQ(buffer2[6], 0);
EXPECT_EQ(buffer1[7], destructed_value);
EXPECT_EQ(buffer2[7], move_constructed_value);
EXPECT_EQ(buffer1[8], 0);
EXPECT_EQ(buffer2[8], 0);
}
TEST(cpp_type, RelocateToInitialized)
{
int buffer1[10] = {0};
int buffer2[10] = {0};
CPPType_TestType.relocate_to_initialized((void *)buffer1, (void *)buffer2);
EXPECT_EQ(buffer1[0], destructed_value);
EXPECT_EQ(buffer2[0], move_assigned_value);
CPPType_TestType.relocate_to_initialized_n((void *)buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1[0], destructed_value);
EXPECT_EQ(buffer2[0], move_assigned_value);
EXPECT_EQ(buffer1[1], destructed_value);
EXPECT_EQ(buffer2[1], move_assigned_value);
EXPECT_EQ(buffer1[2], destructed_value);
EXPECT_EQ(buffer2[2], move_assigned_value);
EXPECT_EQ(buffer1[3], 0);
EXPECT_EQ(buffer2[3], 0);
CPPType_TestType.relocate_to_initialized_indices((void *)buffer1, (void *)buffer2, {2, 5, 7});
EXPECT_EQ(buffer1[2], destructed_value);
EXPECT_EQ(buffer2[2], move_assigned_value);
EXPECT_EQ(buffer1[4], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer1[5], destructed_value);
EXPECT_EQ(buffer2[5], move_assigned_value);
EXPECT_EQ(buffer1[6], 0);
EXPECT_EQ(buffer2[6], 0);
EXPECT_EQ(buffer1[7], destructed_value);
EXPECT_EQ(buffer2[7], move_assigned_value);
EXPECT_EQ(buffer1[8], 0);
EXPECT_EQ(buffer2[8], 0);
}
TEST(cpp_type, FillInitialized)
{
int buffer1 = 0;
int buffer2[10] = {0};
CPPType_TestType.fill_initialized((void *)&buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1, copy_assigned_from_value);
EXPECT_EQ(buffer2[0], copy_assigned_value);
EXPECT_EQ(buffer2[1], copy_assigned_value);
EXPECT_EQ(buffer2[2], copy_assigned_value);
EXPECT_EQ(buffer2[3], 0);
buffer1 = 0;
CPPType_TestType.fill_initialized_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8});
EXPECT_EQ(buffer1, copy_assigned_from_value);
EXPECT_EQ(buffer2[0], copy_assigned_value);
EXPECT_EQ(buffer2[1], copy_assigned_value);
EXPECT_EQ(buffer2[2], copy_assigned_value);
EXPECT_EQ(buffer2[3], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer2[5], 0);
EXPECT_EQ(buffer2[6], copy_assigned_value);
EXPECT_EQ(buffer2[7], 0);
EXPECT_EQ(buffer2[8], copy_assigned_value);
EXPECT_EQ(buffer2[9], 0);
}
TEST(cpp_type, FillUninitialized)
{
int buffer1 = 0;
int buffer2[10] = {0};
CPPType_TestType.fill_uninitialized((void *)&buffer1, (void *)buffer2, 3);
EXPECT_EQ(buffer1, copy_constructed_from_value);
EXPECT_EQ(buffer2[0], copy_constructed_value);
EXPECT_EQ(buffer2[1], copy_constructed_value);
EXPECT_EQ(buffer2[2], copy_constructed_value);
EXPECT_EQ(buffer2[3], 0);
buffer1 = 0;
CPPType_TestType.fill_uninitialized_indices((void *)&buffer1, (void *)buffer2, {1, 6, 8});
EXPECT_EQ(buffer1, copy_constructed_from_value);
EXPECT_EQ(buffer2[0], copy_constructed_value);
EXPECT_EQ(buffer2[1], copy_constructed_value);
EXPECT_EQ(buffer2[2], copy_constructed_value);
EXPECT_EQ(buffer2[3], 0);
EXPECT_EQ(buffer2[4], 0);
EXPECT_EQ(buffer2[5], 0);
EXPECT_EQ(buffer2[6], copy_constructed_value);
EXPECT_EQ(buffer2[7], 0);
EXPECT_EQ(buffer2[8], copy_constructed_value);
EXPECT_EQ(buffer2[9], 0);
}