29 #ifndef PIRANHA_MEMORY_HPP 30 #define PIRANHA_MEMORY_HPP 41 #include <type_traits> 45 #include <piranha/config.hpp> 47 #include <piranha/thread_pool.hpp> 50 #if defined(PIRANHA_HAVE_POSIX_MEMALIGN) // POSIX memalign. 52 #define PIRANHA_HAVE_MEMORY_ALIGNMENT_PRIMITIVES 54 #elif defined(_WIN32) // Windows _aligned_malloc. 55 #define PIRANHA_HAVE_MEMORY_ALIGNMENT_PRIMITIVES 57 #else // malloc + std::align. 72 inline void *cpp_aligned_alloc(
const std::size_t &alignment,
const std::size_t &size)
74 if (unlikely(alignment == 0u || size > std::numeric_limits<std::size_t>::max() - alignment)) {
78 std::size_t a_size = size + alignment;
79 const std::size_t orig_a_size = a_size;
81 void *u_ptr = std::malloc(a_size), *orig_u_ptr = u_ptr;
82 if (unlikely(u_ptr ==
nullptr)) {
86 void *ptr = std::align(alignment,size,u_ptr,a_size);
87 if (unlikely(ptr ==
nullptr)) {
88 std::free(orig_u_ptr);
92 piranha_assert(orig_a_size >= a_size);
94 piranha_assert(orig_a_size == a_size || orig_u_ptr != ptr);
96 const std::size_t delta = (orig_a_size == a_size) ? alignment : orig_a_size - a_size;
97 piranha_assert(delta <= alignment);
98 piranha_assert(delta > 0u);
100 if (unlikely(delta > std::numeric_limits<unsigned char>::max())) {
102 std::free(orig_u_ptr);
106 if (orig_u_ptr == ptr) {
107 ptr =
static_cast<void *
>(
static_cast<unsigned char *
>(ptr) + alignment);
110 *(
static_cast<unsigned char *
>(ptr) - 1) =
static_cast<unsigned char>(delta);
134 inline void *
aligned_palloc(
const std::size_t &alignment,
const std::size_t &size)
137 if (unlikely(size == 0u)) {
140 if (alignment == 0u) {
141 void *ptr = std::malloc(size);
142 if (unlikely(ptr ==
nullptr)) {
147 #if defined(PIRANHA_HAVE_POSIX_MEMALIGN) 149 const int retval = ::posix_memalign(&ptr, alignment, size);
150 if (unlikely(retval != 0)) {
154 #elif defined(_WIN32) 155 void *ptr = ::_aligned_malloc(size, alignment);
156 if (unlikely(ptr ==
nullptr)) {
184 if (unlikely(ptr ==
nullptr)) {
187 if (alignment == 0u) {
191 #if defined(PIRANHA_HAVE_POSIX_MEMALIGN) 193 #elif defined(_WIN32) 194 ::_aligned_free(ptr);
223 template <
typename T>
227 if (alignment == 0u) {
231 if (unlikely(static_cast<bool>(alignment & (alignment - 1u)))) {
236 if (unlikely(alignment <
alignof(
typename std::decay<T>::type))) {
239 #if defined(PIRANHA_HAVE_POSIX_MEMALIGN) 241 if (unlikely(static_cast<bool>(alignment %
sizeof(
void *)))) {
270 template <typename T, typename = typename std::enable_if<is_container_element<T>::value>::type>
273 using ranges_vector = std::vector<std::pair<T *, T *>>;
274 using rv_size_type =
typename ranges_vector::size_type;
275 if (unlikely(ptr ==
nullptr)) {
276 piranha_assert(!size);
280 auto init_function = [](T *start, T *end,
const unsigned &thread_idx, ranges_vector *rv) {
281 auto orig_start = start;
283 for (; start != end; ++start) {
284 ::new (static_cast<void *>(start)) T();
288 for (; orig_start != start; ++orig_start) {
297 (*rv)[
static_cast<rv_size_type
>(thread_idx)].first = orig_start;
298 (*rv)[
static_cast<rv_size_type
>(thread_idx)].second = end;
301 if (n_threads <= 1) {
302 init_function(ptr, ptr + size, 0u,
nullptr);
305 ranges_vector inited_ranges(static_cast<rv_size_type>(n_threads), std::make_pair(ptr, ptr));
306 if (unlikely(inited_ranges.size() != n_threads)) {
310 const auto wpt =
static_cast<std::size_t
>(size / n_threads);
313 for (
auto i = 0u; i < n_threads; ++i) {
314 auto start = ptr + i * wpt, end = (i == n_threads - 1u) ? ptr + size : ptr + (i + 1u) * wpt;
322 for (
const auto &p : inited_ranges) {
323 for (
auto start = p.first; start != p.second; ++start) {
348 template <typename T, typename = typename std::enable_if<is_container_element<T>::value>::type>
351 using ranges_vector = std::vector<std::pair<T *, T *>>;
352 using rv_size_type =
typename ranges_vector::size_type;
354 if (unlikely(ptr ==
nullptr)) {
355 piranha_assert(!size);
360 if (std::is_trivially_destructible<T>::value) {
367 auto destroy_function = [](T * start, T * end) noexcept
369 for (; start != end; ++start) {
370 static_assert(noexcept(start->~T()),
"This destructor cannot throw.");
374 if (n_threads <= 1u) {
375 destroy_function(ptr, ptr + size);
379 ranges_vector d_ranges;
382 d_ranges.resize(static_cast<rv_size_type>(n_threads), std::make_pair(ptr, ptr));
383 if (unlikely(d_ranges.size() != n_threads)) {
388 destroy_function(ptr, ptr + size);
393 const auto wpt =
static_cast<std::size_t
>(size / n_threads);
395 for (
auto i = 0u; i < n_threads; ++i) {
396 auto start = ptr + i * wpt, end = (i == n_threads - 1u) ? ptr + size : ptr + (i + 1u) * wpt;
397 d_ranges[
static_cast<rv_size_type
>(i)] = std::make_pair(start, end);
400 for (
auto i = 0u; i < n_threads; ++i) {
401 auto start = d_ranges[
static_cast<rv_size_type
>(i)].first,
402 end = d_ranges[static_cast<rv_size_type>(i)].second;
406 d_ranges[
static_cast<rv_size_type
>(i)].first = ptr;
407 d_ranges[
static_cast<rv_size_type
>(i)].second = ptr;
415 for (
const auto &p : d_ranges) {
416 destroy_function(p.first, p.second);
426 template <
typename T>
427 class parallel_deleter
430 explicit parallel_deleter(
const std::size_t &size,
const unsigned &n_threads) : m_size(size), m_n_threads(n_threads)
433 void operator()(T *ptr)
const 443 unsigned m_n_threads;
474 template <typename T, typename = typename std::enable_if<is_container_element<T>::value>::type>
476 const unsigned &n_threads)
478 if (unlikely(size > std::numeric_limits<std::size_t>::max() /
sizeof(T))) {
482 auto ptr =
static_cast<T *
>(
aligned_palloc(0u, static_cast<std::size_t>(size *
sizeof(T))));
487 piranha_assert(ptr !=
nullptr);
492 return std::unique_ptr<T[], detail::parallel_deleter<T>>(ptr, detail::parallel_deleter<T>{size, n_threads});
void wait_all()
Wait on all the futures.
void * aligned_palloc(const std::size_t &alignment, const std::size_t &size)
Allocate memory aligned to a specific value.
void parallel_value_init(T *ptr, const std::size_t &size, const unsigned &n_threads)
Parallel value initialisation.
std::unique_ptr< T[], detail::parallel_deleter< T > > make_parallel_array(const std::size_t &size, const unsigned &n_threads)
Create an array in parallel.
void get_all()
Get all the futures.
static enqueue_t< F &&, Args &&... > enqueue(unsigned n, F &&f, Args &&... args)
Enqueue task.
void parallel_destroy(T *ptr, const std::size_t &size, const unsigned &n_threads)
Parallel destruction.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Class to store a list of futures.
Exception for functionality not implemented or not available on the current platform.
void aligned_pfree(const std::size_t &alignment, void *ptr)
Free memory allocated via piranha::aligned_alloc.
bool alignment_check(const std::size_t &alignment)
Alignment checks.
void push_back(std::future< T > &&f)
Move-insert a future.