1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkAbstractArray.h"
// Helpers:
#include "vtkAOSDataArrayTemplate.h"
#include "vtkBitArray.h"
#include "vtkFloatArray.h"
#include "vtkNew.h"
#include "vtkSOADataArrayTemplate.h"
#ifdef VTK_USE_SCALED_SOA_ARRAYS
#include "vtkScaledSOADataArrayTemplate.h"
#endif
#include "vtkStringArray.h"
#include <cstdint>
#include <cstdio>
// Forward declare the test function:
namespace
{
//------------------------------------------------------------------------------
struct UseFree
{
static const int value = vtkAbstractArray::VTK_DATA_ARRAY_FREE;
};
struct UseDelete
{
static const int value = vtkAbstractArray::VTK_DATA_ARRAY_DELETE;
};
struct UseAlignedFree
{
static const int value = vtkAbstractArray::VTK_DATA_ARRAY_ALIGNED_FREE;
};
struct UseLambda
{
static const int value = vtkAbstractArray::VTK_DATA_ARRAY_USER_DEFINED;
};
int timesLambdaFreeCalled = 0;
//------------------------------------------------------------------------------
#define testAssert(expr, errorMessage) \
do \
{ \
if (!(expr)) \
{ \
++errors; \
vtkGenericWarningMacro(<< "Assertion failed: " #expr << "\n" << errorMessage); \
} \
} while (false)
//------------------------------------------------------------------------------
void* make_allocation(UseFree, std::size_t size, int)
{
return malloc(size);
}
void* make_allocation(UseDelete, std::size_t size, int type)
{
// Std::string is weird. When UseDelete is passed it binds to a custom
// free function that casts the memory to std::string*. So to not violate
// this behavior we need to allocate as a string
if (type == VTK_STRING)
{
return new std::string[size];
}
else
{
return new uint8_t[size];
}
}
void* make_allocation(UseAlignedFree, std::size_t size, int)
{
#if defined(_WIN32)
return _aligned_malloc(size, 16);
#else
return malloc(size);
#endif
}
void* make_allocation(UseLambda, std::size_t size, int)
{
return new uint8_t[size];
}
//------------------------------------------------------------------------------
template <typename FreeType>
void assign_user_free(FreeType, vtkAbstractArray*)
{
}
void assign_user_free(UseLambda, vtkAbstractArray* array)
{
array->SetArrayFreeFunction(
[](void* ptr)
{
delete[] reinterpret_cast<uint8_t*>(ptr);
timesLambdaFreeCalled++;
});
}
//------------------------------------------------------------------------------
template <typename FreeType>
int assign_void_array(
FreeType, vtkAbstractArray* array, void* ptr, std::size_t size, bool vtkShouldFree)
{
int errors = 0;
if (vtkSOADataArrayTemplate<double>* is_soa =
vtkArrayDownCast<vtkSOADataArrayTemplate<double>>(array))
{
is_soa->SetNumberOfComponents(1);
is_soa->SetArray(0, reinterpret_cast<double*>(ptr), static_cast<vtkIdType>(size), false,
!vtkShouldFree, FreeType::value);
}
#ifdef VTK_USE_SCALED_SOA_ARRAYS
else if (vtkScaledSOADataArrayTemplate<double>* is_scale_soa =
vtkArrayDownCast<vtkScaledSOADataArrayTemplate<double>>(array))
{
is_scale_soa->SetNumberOfComponents(1);
is_scale_soa->SetArray(0, reinterpret_cast<double*>(ptr), static_cast<vtkIdType>(size), false,
!vtkShouldFree, FreeType::value);
}
#endif
else
{
const int save = vtkShouldFree ? 0 : 1;
array->SetVoidArray(ptr, static_cast<vtkIdType>(size), save, FreeType::value);
testAssert(array->GetVoidPointer(0) == ptr, "assignment failed");
}
return errors;
}
//------------------------------------------------------------------------------
template <typename FreeType>
int ExerciseDelete(FreeType f)
{
int errors = 0;
std::cout << "Starting tests for free type: " << f.value << std::endl;
std::vector<vtkAbstractArray*> arrays;
arrays.push_back(vtkStringArray::New());
arrays.push_back(vtkBitArray::New());
arrays.push_back(vtkFloatArray::New());
arrays.push_back(vtkAOSDataArrayTemplate<double>::New());
arrays.push_back(vtkSOADataArrayTemplate<double>::New());
#ifdef VTK_USE_SCALED_SOA_ARRAYS
arrays.push_back(vtkScaledSOADataArrayTemplate<double>::New());
#endif
const std::size_t size = 5000;
for (auto it = arrays.begin(); it != arrays.end(); ++it)
{
vtkAbstractArray* array = *it;
// test setting the array's memory and having it not free the memory
void* ptr = make_allocation(f, size, array->GetDataType());
errors += assign_void_array(f, array, ptr, size, false);
// ask array to free memory, ptr should still be valid
array->Initialize();
// This time ask the array to free the memory
errors += assign_void_array(f, array, ptr, size, true);
// if we are a lambda we need to set the real free function
assign_user_free(f, array);
// free the memory for real this time
array->Initialize();
}
for (auto it = arrays.begin(); it != arrays.end(); ++it)
{
vtkAbstractArray* array = *it;
array->Delete();
}
return errors;
}
} // end anon namespace
//-------------Test Entry Point-------------------------------------------------
int TestArrayFreeFunctions(int, char*[])
{
int errors = 0;
errors += ExerciseDelete(UseFree{});
errors += ExerciseDelete(UseDelete{});
errors += ExerciseDelete(UseAlignedFree{});
errors += ExerciseDelete(UseLambda{});
if (timesLambdaFreeCalled != 5)
{
std::cerr << "Test failed! Lambda free not called " << std::endl;
}
if (errors > 0)
{
std::cerr << "Test failed! Error count: " << errors << std::endl;
}
return errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
|