BLI: add scoped-defer utility to add RAII-like behavior to C types
This utility is useful when using C types that own some resource in a C++ file. It mainly helps in functions that have multiple return statements, but also simplifies code by moving construction and destruction closer together. Differential Revision: https://developer.blender.org/D14215
This commit is contained in:
parent
721335553c
commit
c23ec04b4e
Notes:
blender-bot
2023-02-14 10:37:50 +01:00
Referenced by issue #96123, Crash when click-dragging across the visibility icons
|
@ -544,3 +544,31 @@ Container &move_assign_container(Container &dst, Container &&src) noexcept(
|
|||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
namespace blender::detail {
|
||||
|
||||
template<typename Func> struct ScopedDeferHelper {
|
||||
Func func;
|
||||
|
||||
~ScopedDeferHelper()
|
||||
{
|
||||
func();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::detail
|
||||
|
||||
#define BLI_SCOPED_DEFER_NAME1(a, b) a##b
|
||||
#define BLI_SCOPED_DEFER_NAME2(a, b) BLI_SCOPED_DEFER_NAME1(a, b)
|
||||
#define BLI_SCOPED_DEFER_NAME(a) BLI_SCOPED_DEFER_NAME2(_scoped_defer_##a##_, __LINE__)
|
||||
|
||||
/**
|
||||
* Execute the given function when the current scope ends. This can be used to cheaply implement
|
||||
* some RAII-like behavior for C types that don't support it. Long term, the types we want to use
|
||||
* this with should either be converted to C++ or get a proper C++ API. Until then, this function
|
||||
* can help avoid common resource leakages.
|
||||
*/
|
||||
#define BLI_SCOPED_DEFER(function_to_defer) \
|
||||
auto BLI_SCOPED_DEFER_NAME(func) = (function_to_defer); \
|
||||
blender::detail::ScopedDeferHelper<decltype(BLI_SCOPED_DEFER_NAME(func))> \
|
||||
BLI_SCOPED_DEFER_NAME(helper){std::move(BLI_SCOPED_DEFER_NAME(func))};
|
||||
|
|
|
@ -176,4 +176,29 @@ static_assert(!is_same_any_v<int, float, bool>);
|
|||
static_assert(!is_same_any_v<int, float>);
|
||||
static_assert(!is_same_any_v<int>);
|
||||
|
||||
TEST(memory_utils, ScopedDefer1)
|
||||
{
|
||||
int a = 0;
|
||||
{
|
||||
BLI_SCOPED_DEFER([&]() { a -= 5; });
|
||||
{
|
||||
BLI_SCOPED_DEFER([&]() { a *= 10; });
|
||||
a = 5;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(a, 45);
|
||||
}
|
||||
|
||||
TEST(memory_utils, ScopedDefer2)
|
||||
{
|
||||
std::string s;
|
||||
{
|
||||
BLI_SCOPED_DEFER([&]() { s += "A"; });
|
||||
BLI_SCOPED_DEFER([&]() { s += "B"; });
|
||||
BLI_SCOPED_DEFER([&]() { s += "C"; });
|
||||
BLI_SCOPED_DEFER([&]() { s += "D"; });
|
||||
}
|
||||
EXPECT_EQ(s, "DCBA");
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -152,6 +152,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
|
|||
}
|
||||
|
||||
KDTree_3d *kdtree = build_kdtree(positions);
|
||||
BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
|
||||
|
||||
for (const int i : positions.index_range()) {
|
||||
if (elimination_mask[i]) {
|
||||
|
@ -176,8 +177,6 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
|
|||
},
|
||||
&callback_data);
|
||||
}
|
||||
|
||||
BLI_kdtree_3d_free(kdtree);
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
|
||||
|
|
|
@ -141,10 +141,13 @@ static void raycast_to_mesh(IndexMask mask,
|
|||
{
|
||||
BVHTreeFromMesh tree_data;
|
||||
BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4);
|
||||
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&tree_data); });
|
||||
|
||||
if (tree_data.tree == nullptr) {
|
||||
free_bvhtree_from_mesh(&tree_data);
|
||||
return;
|
||||
}
|
||||
/* We shouldn't be rebuilding the BVH tree when calling this function in parallel. */
|
||||
BLI_assert(tree_data.cached);
|
||||
|
||||
for (const int i : mask) {
|
||||
const float ray_length = ray_lengths[i];
|
||||
|
@ -197,10 +200,6 @@ static void raycast_to_mesh(IndexMask mask,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We shouldn't be rebuilding the BVH tree when calling this function in parallel. */
|
||||
BLI_assert(tree_data.cached);
|
||||
free_bvhtree_from_mesh(&tree_data);
|
||||
}
|
||||
|
||||
class RaycastFunction : public fn::MultiFunction {
|
||||
|
|
Loading…
Reference in New Issue