cpp-ipc/src/libipc/mem/new_delete_resource.cpp

102 lines
3.2 KiB
C++

#include <cstdlib> // std::aligned_alloc
#include "libipc/imp/detect_plat.h"
#include "libipc/imp/aligned.h"
#include "libipc/imp/system.h"
#include "libipc/imp/log.h"
#include "libipc/mem/memory_resource.h"
#include "libipc/mem/verify_args.h"
namespace ipc {
namespace mem {
/**
* \brief Returns a pointer to a new_delete_resource.
*
* \return new_delete_resource*
*/
new_delete_resource *new_delete_resource::get() noexcept {
static new_delete_resource mem_res;
return &mem_res;
}
/**
* \brief Allocates storage with a size of at least bytes bytes, aligned to the specified alignment.
* Alignment shall be a power of two.
*
* \see https://en.cppreference.com/w/cpp/memory/memory_resource/do_allocate
* https://www.cppstories.com/2019/08/newnew-align/
*
* \return void * - nullptr if storage of the requested size and alignment cannot be obtained.
*/
void *new_delete_resource::allocate(std::size_t bytes, std::size_t alignment) noexcept {
LIBIPC_LOG();
if (!verify_args(bytes, alignment)) {
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
return nullptr;
}
#if defined(LIBIPC_CPP_17)
/// \see https://en.cppreference.com/w/cpp/memory/c/aligned_alloc
/// \remark The size parameter must be an integral multiple of alignment.
return std::aligned_alloc(alignment, ipc::round_up(bytes, alignment));
#else
if (alignment <= alignof(std::max_align_t)) {
/// \see https://en.cppreference.com/w/cpp/memory/c/malloc
return std::malloc(bytes);
}
#if defined(LIBIPC_OS_WIN)
/// \see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc
return ::_aligned_malloc(bytes, alignment);
#else // try posix
/// \see https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html
void *p = nullptr;
int ret = ::posix_memalign(&p, alignment, bytes);
if (ret != 0) {
log.error("failed: posix_memalign(alignment = ", alignment,
", bytes = ", bytes,
"). error = ", sys::error(ret));
return nullptr;
}
return p;
#endif
#endif // defined(LIBIPC_CPP_17)
}
/**
* \brief Deallocates the storage pointed to by p.
* The storage it points to must not yet have been deallocated, otherwise the behavior is undefined.
*
* \see https://en.cppreference.com/w/cpp/memory/memory_resource/do_deallocate
*
* \param p must have been returned by a prior call to new_delete_resource::do_allocate(bytes, alignment).
*/
void new_delete_resource::deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept {
LIBIPC_LOG();
if (p == nullptr) {
return;
}
if (!verify_args(bytes, alignment)) {
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
return;
}
#if defined(LIBIPC_CPP_17)
/// \see https://en.cppreference.com/w/cpp/memory/c/free
std::free(p);
#else
if (alignment <= alignof(std::max_align_t)) {
std::free(p);
return;
}
#if defined(LIBIPC_OS_WIN)
/// \see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-free
::_aligned_free(p);
#else // try posix
::free(p);
#endif
#endif // defined(LIBIPC_CPP_17)
}
} // namespace mem
} // namespace ipc