1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_ALIGNED_ALLOCATOR_HH
#define DUNE_ALIGNED_ALLOCATOR_HH
#include "mallocallocator.hh"
#include <cstdlib>
#include <type_traits>
namespace Dune
{
/**
@ingroup Allocators
@brief Allocators which guarantee alignment of the memory
@tparam T type of the object one wants to allocate
@tparam Alignment explicitly specify the alignment, by default it is std::alignment_of<T>::value
*/
template<class T, int Alignment = -1>
class AlignedAllocator : public MallocAllocator<T> {
#if __APPLE__
/*
* macOS has pretty draconian restrictions on the
* alignments that you may ask for: It has to be
*
* 1) a power of 2
* 2) at least as large as sizeof(void*)
*
* So here is a little constexpr function that calculates just that
* (together with the correct starting value for align fed in further down).
*/
static constexpr int fixAlignment(int align)
{
return ((Alignment==-1) ? std::alignment_of<T>::value : Alignment) > align
? fixAlignment(align << 1) : align;
}
#else
/*
* Non-Apple platforms we just have to check whether an explicit alignment was
* restricted or fall back to the default alignment of T.
*/
static constexpr int fixAlignment(int align)
{
return (Alignment==-1) ? std::alignment_of<T>::value : Alignment;
}
#endif
public:
using pointer = typename MallocAllocator<T>::pointer;
using size_type = typename MallocAllocator<T>::size_type;
template <class U> struct rebind {
typedef AlignedAllocator<U,Alignment> other;
};
static constexpr int alignment = fixAlignment(sizeof(void*));
//! allocate n objects of type T
pointer allocate(size_type n, [[maybe_unused]] const void* hint = 0)
{
if (n > this->max_size())
throw std::bad_alloc();
#if __APPLE__
// Apple is also restrictive regarding the allocation size.
// size must be at least the alignment size.
size_type size = n * sizeof(T) >= alignment ? n * sizeof(T) : alignment;
#else
size_type size = n * sizeof(T);
#endif
/*
* Everybody else gets the standard treatment.
*/
pointer ret = static_cast<pointer>(std::aligned_alloc(alignment, size));
if (!ret)
throw std::bad_alloc();
return ret;
}
};
}
#endif // DUNE_ALIGNED_ALLOCATOR_HH
|