Program Listing for File alloc.hpp
↰ Return to documentation for file (include/proxsuite/linalg/veg/memory/alloc.hpp
)
#ifndef VEG_ALLOC_HPP_TAWYRUICS
#define VEG_ALLOC_HPP_TAWYRUICS
#include "proxsuite/fwd.hpp"
#include "proxsuite/linalg/veg/ref.hpp"
#include "proxsuite/linalg/veg/type_traits/constructible.hpp"
#include "proxsuite/linalg/veg/type_traits/assignable.hpp"
#include "proxsuite/linalg/veg/internal/typedefs.hpp"
#include "proxsuite/linalg/veg/internal/macros.hpp"
#include "proxsuite/linalg/veg/memory/placement.hpp"
#include "proxsuite/linalg/veg/type_traits/alloc.hpp"
#include <cstddef> // std::max_align_t
#include <cstdlib> // std::{malloc, free, realloc}, ::{aligned_alloc, free}
#ifndef __APPLE__
#include <malloc.h> // ::malloc_usable_size
#else
#include <AvailabilityMacros.h>
#include <malloc/malloc.h>
#define malloc_usable_size malloc_size
#endif
#include "proxsuite/linalg/veg/internal/prologue.hpp"
namespace proxsuite {
namespace linalg {
namespace veg {
#ifdef __APPLE__
namespace alignment {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 && \
(defined(_LIBCPP_HAS_ALIGNED_ALLOC) || defined(_LIBCPP_HAS_C11_FEATURES)) && \
defined(PROXSUITE_WITH_CPP_17)
VEG_INLINE void*
aligned_alloc(std::size_t alignment, std::size_t size)
{
return std::aligned_alloc(alignment, size);
}
#elif MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
VEG_INLINE void*
aligned_alloc(std::size_t alignment, std::size_t size)
{
if (alignment < sizeof(void*)) {
alignment = sizeof(void*);
}
void* p;
if (::posix_memalign(&p, alignment, size) != 0) {
p = 0;
}
return p;
}
#endif
} // namespace alignment
#endif
// Support aligned_alloc for c++14, code from boost/align.
namespace alignment {
namespace detail {
// Source: https://www.boost.org/doc/libs/1_65_0/boost/align/detail/min_size.hpp
template<std::size_t A, std::size_t B>
struct min_size : std::integral_constant<std::size_t, (A < B) ? A : B>
{};
template<class T>
struct offset_value
{
char value;
T object;
};
// Source:
// https://www.boost.org/doc/libs/1_65_0/boost/align/detail/alignment_of.hpp
template<class T>
struct alignment_of : min_size<sizeof(T), sizeof(offset_value<T>) - sizeof(T)>
{};
// Source:
// https://www.boost.org/doc/libs/1_65_0/boost/align/detail/is_alignment.hpp
constexpr inline bool
is_alignment(std::size_t value)
{
return (value > 0) && ((value & (value - 1)) == 0);
}
// Source: https://www.boost.org/doc/libs/1_74_0/boost/align/detail/align.hpp
inline void*
align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space)
{
assert(is_alignment(alignment));
char* p = reinterpret_cast<char*>(
~(alignment - 1) & (reinterpret_cast<std::size_t>(ptr) + alignment - 1));
assert((p - static_cast<char*>(ptr)) >= 0);
std::size_t n = std::size_t(p - static_cast<char*>(ptr));
if (size + n <= space) {
ptr = p;
space -= n;
return p;
}
return 0;
}
// Source:
// https://www.boost.org/doc/libs/1_65_0/boost/align/detail/aligned_alloc.hpp
inline void*
aligned_alloc(std::size_t alignment, std::size_t size)
{
assert(is_alignment(alignment));
enum
{
N = alignment_of<void*>::value
};
if (alignment < N) {
alignment = N;
}
std::size_t n = size + alignment - N;
void* p = std::malloc(sizeof(void*) + n);
if (p) {
void* r = static_cast<char*>(p) + sizeof(void*);
(void)align(alignment, size, r, n);
*(static_cast<void**>(r) - 1) = p;
p = r;
}
return p;
}
} // namespace detail
} // namespace alignment
namespace mem {
enum struct CopyAvailable
{
no,
yes_maythrow,
yes_nothrow,
};
enum struct DtorAvailable
{
no,
yes_maythrow,
yes_nothrow,
};
template<typename T>
struct CopyAvailableFor
: meta::constant<mem::CopyAvailable,
(VEG_CONCEPT(nothrow_copyable<T>) &&
VEG_CONCEPT(nothrow_copy_assignable<T>))
? CopyAvailable::yes_nothrow
: (VEG_CONCEPT(copyable<T>) &&
VEG_CONCEPT(copy_assignable<T>))
? CopyAvailable::yes_maythrow
: CopyAvailable::no>
{};
template<typename T>
struct DtorAvailableFor
: meta::constant<mem::DtorAvailable,
VEG_CONCEPT(nothrow_destructible<T>)
? DtorAvailable::yes_nothrow
: DtorAvailable::yes_maythrow>
{};
VEG_INLINE auto
aligned_alloc(usize align, usize size) noexcept -> void*
{
usize const mask = align - 1;
#if defined(_WIN32)
return _aligned_malloc((size + mask) & ~mask, align);
#elif defined(__APPLE__)
#if defined(PROXSUITE_WITH_CPP_17) && defined(_LIBCPP_HAS_ALIGNED_ALLOC)
return alignment::aligned_alloc(align, (size + mask) & ~mask);
#else
return alignment::detail::aligned_alloc(align, (size + mask) & ~mask);
#endif
#else
#if defined(PROXSUITE_WITH_CPP_17) && defined(_LIBCPP_HAS_ALIGNED_ALLOC)
return std::aligned_alloc(align, (size + mask) & ~mask);
#else
return alignment::detail::aligned_alloc(align, (size + mask) & ~mask);
#endif
#endif
}
VEG_INLINE void
aligned_free(usize /*align*/, void* ptr) noexcept
{
#ifndef _WIN32
std::free(ptr);
#else
_aligned_free(ptr);
#endif
}
struct SystemAlloc
{
constexpr friend auto operator==(SystemAlloc /*unused*/,
SystemAlloc /*unused*/) noexcept -> bool
{
return true;
}
};
template<>
struct Alloc<SystemAlloc>
{
static constexpr usize max_base_align = alignof(std::max_align_t);
VEG_INLINE static void dealloc(RefMut<SystemAlloc> /*alloc*/,
void* ptr,
Layout layout) noexcept
{
(layout.align <= max_base_align) ? std::free(ptr)
: mem::aligned_free(layout.align, ptr);
}
VEG_NODISCARD VEG_INLINE static auto alloc(RefMut<SystemAlloc> /*alloc*/,
Layout layout) noexcept
-> mem::AllocBlock
{
void* ptr = (layout.align <= max_base_align)
? std::malloc(layout.byte_size)
: mem::aligned_alloc(layout.align, layout.byte_size);
if (HEDLEY_UNLIKELY(ptr == nullptr)) {
_detail::terminate();
}
#ifndef _WIN32
return { ptr, ::malloc_usable_size(ptr) };
#else
return { ptr, _msize(ptr) };
#endif
}
VEG_NODISCARD VEG_NO_INLINE static auto realloc(RefMut<SystemAlloc> /*alloc*/,
void* ptr,
Layout layout,
usize new_size,
usize copy_size,
RelocFn reloc) noexcept
-> mem::AllocBlock
{
void* new_ptr; // NOLINT
bool typical_align = layout.align <= max_base_align;
bool trivial_reloc = reloc.is_trivial();
bool use_realloc = typical_align && trivial_reloc;
if (use_realloc) {
new_ptr = std::realloc(ptr, new_size);
} else {
new_ptr = mem::aligned_alloc(layout.align, new_size);
}
if (HEDLEY_UNLIKELY(new_ptr == nullptr)) {
_detail::terminate();
}
if (!use_realloc) {
reloc(new_ptr, ptr, copy_size);
mem::aligned_free(layout.align, ptr);
}
#ifndef _WIN32
return { new_ptr, ::malloc_usable_size(new_ptr) };
#else
return { new_ptr, _msize(new_ptr) };
#endif
}
VEG_NODISCARD VEG_INLINE auto try_grow_in_place(
void* /*ptr*/,
Layout /*layout*/,
usize /*new_size*/) const noexcept -> bool
{
return false;
}
VEG_NODISCARD VEG_INLINE static auto grow(RefMut<SystemAlloc> alloc,
void* ptr,
Layout layout,
usize new_size,
RelocFn reloc) noexcept
-> mem::AllocBlock
{
return realloc(
VEG_FWD(alloc), ptr, layout, new_size, layout.byte_size, reloc);
}
VEG_NODISCARD VEG_INLINE static auto shrink(RefMut<SystemAlloc> alloc,
void* ptr,
Layout layout,
usize new_size,
RelocFn reloc) noexcept
-> mem::AllocBlock
{
return realloc(VEG_FWD(alloc), ptr, layout, new_size, new_size, reloc);
}
};
struct DefaultCloner
{};
template<>
struct Cloner<DefaultCloner>
{
template<typename T>
using trivial_clone = meta::bool_constant<VEG_CONCEPT(trivially_copyable<T>)>;
template<typename T, typename Alloc>
VEG_INLINE static void destroy(RefMut<DefaultCloner> /*cloner*/,
T* ptr,
RefMut<Alloc> /*alloc*/)
VEG_NOEXCEPT_IF(VEG_CONCEPT(nothrow_destructible<T>))
{
mem::destroy_at(ptr);
}
VEG_TEMPLATE((typename T, typename Alloc),
requires(VEG_CONCEPT(copyable<T>)),
VEG_NODISCARD VEG_INLINE static auto clone,
(/*cloner*/, RefMut<DefaultCloner>),
(rhs, Ref<T>),
(/*alloc*/, RefMut<Alloc>))
VEG_NOEXCEPT_IF(VEG_CONCEPT(nothrow_copyable<T>))->T { return T(rhs.get()); }
VEG_TEMPLATE((typename T, typename Alloc),
requires(VEG_CONCEPT(copyable<T>)),
VEG_INLINE static void clone_from,
(/*cloner*/, RefMut<DefaultCloner>),
(lhs, RefMut<T>),
(rhs, Ref<T>),
(/*alloc*/, RefMut<Alloc>))
VEG_NOEXCEPT_IF(VEG_CONCEPT(nothrow_copy_assignable<T>))
{
lhs.get() = rhs.get();
}
};
VEG_INLINE_VAR(system_alloc, SystemAlloc);
VEG_INLINE_VAR(default_cloner, DefaultCloner);
} // namespace mem
namespace _detail {
namespace _mem {
template<typename A>
struct ManagedAlloc /* NOLINT */
{
void* data;
mem::Layout layout;
RefMut<A> alloc;
VEG_INLINE ~ManagedAlloc()
{
if (data != nullptr) {
mem::Alloc<A>::dealloc(VEG_FWD(alloc), VEG_FWD(data), VEG_FWD(layout));
}
}
};
} // namespace _mem
} // namespace _detail
} // namespace veg
} // namespace linalg
} // namespace proxsuite
#include "proxsuite/linalg/veg/internal/epilogue.hpp"
#endif /* end of include guard VEG_ALLOC_HPP_TAWYRUICS */