1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 14 янв. 2019 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <dsp/bits.h> 23 #include <core/3d/Allocator3D.h> 24 #include <core/sugar.h> 25 #include <core/status.h> 26 27 namespace lsp 28 { BasicAllocator3D(size_t sz_of,size_t c_size)29 BasicAllocator3D::BasicAllocator3D(size_t sz_of, size_t c_size) 30 { 31 nChunks = 0; 32 nShift = int_log2(c_size); 33 nMask = (1 << nShift) - 1; 34 35 nSizeOf = sz_of; 36 nAllocated = 0; 37 vChunks = NULL; 38 pCurr = NULL; 39 nLeft = 0; 40 } 41 ~BasicAllocator3D()42 BasicAllocator3D::~BasicAllocator3D() 43 { 44 do_destroy(); 45 } 46 get_chunk(size_t id)47 uint8_t *BasicAllocator3D::get_chunk(size_t id) 48 { 49 // Reallocate chunk index if too small 50 if (id >= nChunks) 51 { 52 size_t cap = (id + 0x10) & (~0x0f); 53 uint8_t **nc = reinterpret_cast<uint8_t **>(::realloc(vChunks, sizeof(uint8_t *) * cap)); 54 if (nc == NULL) 55 return NULL; 56 // Initialize pointers 57 for (size_t i=nChunks; i<cap; ++i) 58 nc[nChunks++] = NULL; 59 vChunks = nc; 60 } 61 62 // Fetch chunks 63 uint8_t *chunk = vChunks[id]; 64 if (chunk != NULL) 65 return chunk; 66 67 // Try to allocate 68 chunk = reinterpret_cast<uint8_t *>(::malloc(nSizeOf << nShift)); 69 if (chunk == NULL) 70 return NULL; 71 72 vChunks[id] = chunk; 73 return chunk; 74 } 75 do_get(size_t idx)76 void *BasicAllocator3D::do_get(size_t idx) 77 { 78 if (idx >= nAllocated) 79 return NULL; 80 uint8_t *chunk = vChunks[idx >> nShift]; 81 return &chunk[nSizeOf * (idx & nMask)]; 82 } 83 do_alloc()84 void *BasicAllocator3D::do_alloc() 85 { 86 // Try to allocate from current chunk 87 if (nLeft <= 0) 88 { 89 pCurr = get_chunk(nAllocated >> nShift); 90 if (pCurr == NULL) 91 return NULL; 92 nLeft = nMask; // (1 << nShift) - 1 93 } 94 else 95 --nLeft; 96 97 uint8_t *p = pCurr; 98 pCurr += nSizeOf; 99 ++nAllocated; 100 return p; 101 } 102 do_alloc_n(void ** ptr,size_t n)103 size_t BasicAllocator3D::do_alloc_n(void **ptr, size_t n) 104 { 105 size_t left = n; 106 107 while (left > 0) 108 { 109 // Try to allocate from current chunk 110 if (nLeft <= 0) 111 { 112 pCurr = get_chunk(nAllocated >> nShift); 113 if (pCurr == NULL) 114 break; 115 nLeft = (1 << nShift); 116 } 117 118 // Allocate N items 119 size_t to_alloc = (nLeft > n) ? n : nLeft; 120 nLeft -= to_alloc; 121 nAllocated += to_alloc; 122 123 uint8_t *p = pCurr; 124 while (to_alloc--) 125 { 126 *(ptr++) = p; 127 p += nSizeOf; 128 } 129 130 pCurr = p; 131 } 132 133 return n - left; 134 } 135 do_ialloc(void ** p)136 ssize_t BasicAllocator3D::do_ialloc(void **p) 137 { 138 // Try to allocate from current chunk 139 if (nLeft <= 0) 140 { 141 pCurr = get_chunk(nAllocated >> nShift); 142 if (pCurr == NULL) 143 return -STATUS_NO_MEM; 144 nLeft = nMask; // (1 << nShift) - 1 145 } 146 else 147 --nLeft; 148 149 *p = pCurr; 150 pCurr += nSizeOf; 151 return nAllocated++; 152 } 153 do_destroy()154 void BasicAllocator3D::do_destroy() 155 { 156 if (vChunks != NULL) 157 { 158 for (size_t i=0; i<nChunks; ++i) 159 { 160 uint8_t *c = vChunks[i]; 161 if (c != NULL) 162 { 163 ::free(c); 164 vChunks[i] = NULL; 165 } 166 } 167 168 ::free(vChunks); 169 vChunks = NULL; 170 } 171 172 nAllocated = 0; 173 nChunks = 0; 174 pCurr = NULL; 175 nLeft = 0; 176 } 177 do_clear()178 void BasicAllocator3D::do_clear() 179 { 180 nAllocated = 0; 181 pCurr = NULL; 182 nLeft = 0; 183 } 184 do_swap(BasicAllocator3D * src)185 void BasicAllocator3D::do_swap(BasicAllocator3D *src) 186 { 187 swap(nChunks, src->nChunks); 188 swap(nShift, src->nShift); 189 swap(nMask, src->nMask); 190 swap(nSizeOf, src->nSizeOf); 191 swap(nAllocated, src->nAllocated); 192 swap(vChunks, src->vChunks); 193 swap(pCurr, src->pCurr); 194 swap(nLeft, src->nLeft); 195 } 196 do_validate(const void * ptr) const197 bool BasicAllocator3D::do_validate(const void *ptr) const 198 { 199 if (ptr == NULL) 200 return true; 201 202 const uint8_t *uptr = reinterpret_cast<const uint8_t *>(ptr); 203 ssize_t csize = nSizeOf << nShift; 204 205 for (size_t i=0; i<nChunks; ++i) 206 { 207 if (vChunks[i] == NULL) 208 continue; 209 ssize_t delta = uptr - vChunks[i]; 210 if ((delta < 0) || (delta >= csize)) 211 continue; 212 if ((delta % nSizeOf) != 0) 213 return false; 214 delta /= nSizeOf; 215 216 return ((i << nShift) + delta) < nAllocated; 217 } 218 219 return false; 220 } 221 calc_index_of(const void * ptr) const222 ssize_t BasicAllocator3D::calc_index_of(const void *ptr) const 223 { 224 if (ptr == NULL) 225 return -1; 226 227 const uint8_t *uptr = reinterpret_cast<const uint8_t *>(ptr); 228 ssize_t csize = nSizeOf << nShift; 229 ssize_t offset = 0; 230 ssize_t chunk_cap = 1 << nShift; 231 232 for (size_t i=0; i<nChunks; ++i, offset += chunk_cap) 233 { 234 if (vChunks[i] == NULL) 235 continue; 236 ssize_t delta = uptr - vChunks[i]; 237 if ((delta < 0) || (delta >= csize)) 238 continue; 239 if ((delta % nSizeOf) != 0) 240 return -1; 241 return offset + delta / nSizeOf; 242 } 243 244 return -1; 245 } 246 } 247 248