1 /* 2 * This file is part of the MR utility library. 3 * 4 * This code is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This code is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this code; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 /** \file ducc0/infra/aligned_array.h 20 * 21 * \copyright Copyright (C) 2019-2021 Max-Planck-Society 22 * \author Martin Reinecke 23 */ 24 25 #ifndef DUCC0_ALIGNED_ARRAY_H 26 #define DUCC0_ALIGNED_ARRAY_H 27 28 #include <cstdlib> 29 #include <new> 30 31 namespace ducc0 { 32 33 namespace detail_aligned_array { 34 35 using namespace std; 36 37 /// Bare bones array class. 38 /** Mostly useful for uninitialized temporary buffers. 39 * \note Since this class operates on raw memory, it should only be used with 40 * POD types, and even then only with caution! */ 41 template<typename T, size_t alignment=alignof(T)> class array_base 42 { 43 private: 44 T *p; 45 size_t sz; 46 ralloc(size_t num)47 static T *ralloc(size_t num) 48 { 49 if constexpr(alignment<=alignof(max_align_t)) 50 { 51 void *res = malloc(num*sizeof(T)); 52 if (!res) throw bad_alloc(); 53 return reinterpret_cast<T *>(res); 54 } 55 else 56 { 57 if (num==0) return nullptr; 58 // FIXME: let's not use aligned_alloc on Apple for the moment, 59 // it's only supported from 10.15 on... 60 #if ((__cplusplus >= 201703L) && (!defined(__APPLE__))) 61 // aligned_alloc requires the allocated size to be a multiple of the 62 // requested alignment, so increase size if necessary 63 void *res = aligned_alloc(alignment,((num*sizeof(T)+alignment-1)/alignment)*alignment); 64 if (!res) throw bad_alloc(); 65 #else // portable emulation 66 void *ptr = malloc(num*sizeof(T)+alignment); 67 if (!ptr) throw bad_alloc(); 68 void *res = reinterpret_cast<void *>((reinterpret_cast<size_t>(ptr) & ~(size_t(alignment-1))) + alignment); 69 (reinterpret_cast<void**>(res))[-1] = ptr; 70 #endif 71 return reinterpret_cast<T *>(res); 72 } 73 } dealloc(T * ptr)74 static void dealloc(T *ptr) 75 { 76 if constexpr(alignment<=alignof(max_align_t)) 77 free(ptr); 78 else 79 #if ((__cplusplus >= 201703L) && (!defined(__APPLE__))) 80 free(ptr); 81 #else 82 if (ptr) free((reinterpret_cast<void**>(ptr))[-1]); 83 #endif 84 } 85 86 public: 87 /// Creates a zero-sized array with no associated memory. array_base()88 array_base() : p(nullptr), sz(0) {} 89 /// Creates an array with \a n entries. 90 /** \note Memory is not initialized! */ array_base(size_t n)91 array_base(size_t n) : p(ralloc(n)), sz(n) {} array_base(array_base && other)92 array_base(array_base &&other) 93 : p(other.p), sz(other.sz) 94 { other.p=nullptr; other.sz=0; } ~array_base()95 ~array_base() { dealloc(p); } 96 97 /// If \a n is different from the currnt size, resizes the array to hold 98 /// \a n elements. 99 /** \note No data content is copied, the new array is uninitialized! */ resize(size_t n)100 void resize(size_t n) 101 { 102 if (n==sz) return; 103 dealloc(p); 104 p = ralloc(n); 105 sz = n; 106 } 107 108 /// Returns a writeable reference to the element at index \a idx. 109 T &operator[](size_t idx) { return p[idx]; } 110 /// Returns a read-only reference to the element at index \a idx. 111 const T &operator[](size_t idx) const { return p[idx]; } 112 113 /// Returns a writeable pointer to the array data. data()114 T *data() { return p; } 115 /// Returns a read-only pointer to the array data. data()116 const T *data() const { return p; } 117 118 /// Returns the size of the array. size()119 size_t size() const { return sz; } 120 }; 121 122 template<typename T> using quick_array = array_base<T>; 123 template<typename T> using aligned_array = array_base<T,64>; 124 125 } 126 127 using detail_aligned_array::aligned_array; 128 using detail_aligned_array::quick_array; 129 130 } 131 132 #endif 133 134