1 /* 2 * This file is part of RawTherapee. 3 * 4 * Copyright (c) 2004-2012 Gabor Horvath <hgabor@rawtherapee.com>, Oliver Duis <oduis@oliverduis.de> 5 * 6 * RawTherapee is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * RawTherapee is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 #ifndef _ALIGNEDBUFFER_ 20 #define _ALIGNEDBUFFER_ 21 22 #include <cstdint> 23 #include <cstdlib> 24 #include <utility> 25 26 inline size_t padToAlignment(size_t size, size_t align = 16) { 27 return align * ((size + align - 1) / align); 28 } 29 30 // Aligned buffer that should be faster 31 template <class T> class AlignedBuffer 32 { 33 34 private: 35 void* real ; 36 char alignment; 37 size_t allocatedSize; 38 int unitSize; 39 40 public: 41 T* data ; 42 bool inUse; 43 44 /** @brief Allocate aligned memory 45 * @param size Number of elements of size T to allocate, i.e. allocated size will be sizeof(T)*size ; set it to 0 if you want to defer the allocation 46 * @param align Expressed in bytes; SSE instructions need 128 bits alignment, which mean 16 bytes, which is the default value 47 */ real(nullptr)48 AlignedBuffer (size_t size = 0, size_t align = 16) : real(nullptr), alignment(align), allocatedSize(0), unitSize(0), data(nullptr), inUse(false) 49 { 50 if (size) { 51 resize(size); 52 } 53 } 54 ~AlignedBuffer()55 ~AlignedBuffer () 56 { 57 if (real) { 58 free(real); 59 } 60 } 61 62 /** @brief Return true if there's no memory allocated 63 */ isEmpty()64 bool isEmpty() const 65 { 66 return allocatedSize == 0; 67 } 68 69 /** @brief Allocate the "size" amount of elements of "structSize" length each 70 * @param size number of elements to allocate 71 * @param structSize if non null, will let you override the default struct's size (unit: byte) 72 * @return True is everything went fine, including freeing memory when size==0, false if the allocation failed 73 */ 74 bool resize(size_t size, int structSize = 0) 75 { 76 if (allocatedSize != size) { 77 if (!size) { 78 // The user want to free the memory 79 if (real) { 80 free(real); 81 } 82 83 real = nullptr; 84 data = nullptr; 85 inUse = false; 86 allocatedSize = 0; 87 unitSize = 0; 88 } else { 89 unitSize = structSize ? structSize : sizeof(T); 90 size_t oldAllocatedSize = allocatedSize; 91 allocatedSize = size * unitSize; 92 93 // realloc were used here to limit memory fragmentation, specially when the size was smaller than the previous one. 94 // But realloc copies the content to the eventually new location, which is unnecessary. To avoid this performance penalty, 95 // we're freeing the memory and allocate it again if the new size is bigger. 96 97 if (allocatedSize < oldAllocatedSize) { 98 void *temp = realloc(real, allocatedSize + alignment); 99 if (temp) { // realloc succeeded 100 real = temp; 101 } else { // realloc failed => free old buffer and allocate new one 102 if (real) { 103 free (real); 104 } 105 real = malloc(allocatedSize + alignment); 106 } 107 } else { 108 if (real) { 109 free (real); 110 } 111 112 real = malloc(allocatedSize + alignment); 113 } 114 115 if (real) { 116 data = (T*)( ( uintptr_t(real) + uintptr_t(alignment - 1)) / alignment * alignment); 117 inUse = true; 118 } else { 119 allocatedSize = 0; 120 unitSize = 0; 121 data = nullptr; 122 inUse = false; 123 return false; 124 } 125 } 126 } 127 128 return true; 129 } 130 swap(AlignedBuffer<T> & other)131 void swap(AlignedBuffer<T> &other) 132 { 133 std::swap(real, other.real); 134 std::swap(alignment, other.alignment); 135 std::swap(allocatedSize, other.allocatedSize); 136 std::swap(data, other.data); 137 std::swap(inUse, other.inUse); 138 } 139 getSize()140 unsigned int getSize() const 141 { 142 return unitSize ? allocatedSize / unitSize : 0; 143 } 144 }; 145 146 #endif 147