Files
test/source/blender/blenlib/intern/implicit_sharing.cc
2025-03-29 15:18:50 +11:00

113 lines
2.9 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bli
*/
#include <algorithm>
#include <cstring>
#include "MEM_guardedalloc.h"
#include "BLI_implicit_sharing.hh"
namespace blender::implicit_sharing {
class MEMFreeImplicitSharing : public ImplicitSharingInfo {
public:
void *data;
MEMFreeImplicitSharing(void *data) : data(data)
{
BLI_assert(data != nullptr);
}
private:
void delete_self_with_data() override
{
MEM_freeN(data);
MEM_delete(this);
}
};
const ImplicitSharingInfo *info_for_mem_free(void *data)
{
return MEM_new<MEMFreeImplicitSharing>(__func__, data);
}
namespace detail {
void *make_trivial_data_mutable_impl(void *old_data,
const int64_t size,
const int64_t alignment,
const ImplicitSharingInfo **sharing_info)
{
if (!old_data) {
BLI_assert(size == 0);
return nullptr;
}
BLI_assert(*sharing_info != nullptr);
if ((*sharing_info)->is_mutable()) {
(*sharing_info)->tag_ensured_mutable();
}
else {
void *new_data = MEM_mallocN_aligned(size, alignment, __func__);
memcpy(new_data, old_data, size);
(*sharing_info)->remove_user_and_delete_if_last();
*sharing_info = info_for_mem_free(new_data);
return new_data;
}
return old_data;
}
void *resize_trivial_array_impl(void *old_data,
const int64_t old_size,
const int64_t new_size,
const int64_t alignment,
const ImplicitSharingInfo **sharing_info)
{
if (new_size == 0) {
if (*sharing_info) {
(*sharing_info)->remove_user_and_delete_if_last();
*sharing_info = nullptr;
}
return nullptr;
}
if (!old_data) {
BLI_assert(old_size == 0);
BLI_assert(*sharing_info == nullptr);
void *new_data = MEM_mallocN_aligned(new_size, alignment, __func__);
*sharing_info = info_for_mem_free(new_data);
return new_data;
}
BLI_assert(old_size != 0);
if ((*sharing_info)->is_mutable()) {
if (auto *info = const_cast<MEMFreeImplicitSharing *>(
dynamic_cast<const MEMFreeImplicitSharing *>(*sharing_info)))
{
/* If the array was allocated with the MEM allocator, we can use realloc directly, which
* could theoretically give better performance if the data can be reused in place. */
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));
info->data = new_data;
(*sharing_info)->tag_ensured_mutable();
return new_data;
}
}
void *new_data = MEM_mallocN_aligned(new_size, alignment, __func__);
memcpy(new_data, old_data, std::min(old_size, new_size));
(*sharing_info)->remove_user_and_delete_if_last();
*sharing_info = info_for_mem_free(new_data);
return new_data;
}
} // namespace detail
} // namespace blender::implicit_sharing