/*
* Copyright (C) 2020 Linux Studio Plugins Project
* (C) 2020 Vladimir Sadovnikov
*
* This file is part of lsp-plugins
* Created on: 14 янв. 2019 г.
*
* lsp-plugins is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* lsp-plugins is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with lsp-plugins. If not, see .
*/
#include
#include
#include
#include
namespace lsp
{
BasicAllocator3D::BasicAllocator3D(size_t sz_of, size_t c_size)
{
nChunks = 0;
nShift = int_log2(c_size);
nMask = (1 << nShift) - 1;
nSizeOf = sz_of;
nAllocated = 0;
vChunks = NULL;
pCurr = NULL;
nLeft = 0;
}
BasicAllocator3D::~BasicAllocator3D()
{
do_destroy();
}
uint8_t *BasicAllocator3D::get_chunk(size_t id)
{
// Reallocate chunk index if too small
if (id >= nChunks)
{
size_t cap = (id + 0x10) & (~0x0f);
uint8_t **nc = reinterpret_cast(::realloc(vChunks, sizeof(uint8_t *) * cap));
if (nc == NULL)
return NULL;
// Initialize pointers
for (size_t i=nChunks; i(::malloc(nSizeOf << nShift));
if (chunk == NULL)
return NULL;
vChunks[id] = chunk;
return chunk;
}
void *BasicAllocator3D::do_get(size_t idx)
{
if (idx >= nAllocated)
return NULL;
uint8_t *chunk = vChunks[idx >> nShift];
return &chunk[nSizeOf * (idx & nMask)];
}
void *BasicAllocator3D::do_alloc()
{
// Try to allocate from current chunk
if (nLeft <= 0)
{
pCurr = get_chunk(nAllocated >> nShift);
if (pCurr == NULL)
return NULL;
nLeft = nMask; // (1 << nShift) - 1
}
else
--nLeft;
uint8_t *p = pCurr;
pCurr += nSizeOf;
++nAllocated;
return p;
}
size_t BasicAllocator3D::do_alloc_n(void **ptr, size_t n)
{
size_t left = n;
while (left > 0)
{
// Try to allocate from current chunk
if (nLeft <= 0)
{
pCurr = get_chunk(nAllocated >> nShift);
if (pCurr == NULL)
break;
nLeft = (1 << nShift);
}
// Allocate N items
size_t to_alloc = (nLeft > n) ? n : nLeft;
nLeft -= to_alloc;
nAllocated += to_alloc;
uint8_t *p = pCurr;
while (to_alloc--)
{
*(ptr++) = p;
p += nSizeOf;
}
pCurr = p;
}
return n - left;
}
ssize_t BasicAllocator3D::do_ialloc(void **p)
{
// Try to allocate from current chunk
if (nLeft <= 0)
{
pCurr = get_chunk(nAllocated >> nShift);
if (pCurr == NULL)
return -STATUS_NO_MEM;
nLeft = nMask; // (1 << nShift) - 1
}
else
--nLeft;
*p = pCurr;
pCurr += nSizeOf;
return nAllocated++;
}
void BasicAllocator3D::do_destroy()
{
if (vChunks != NULL)
{
for (size_t i=0; inChunks);
swap(nShift, src->nShift);
swap(nMask, src->nMask);
swap(nSizeOf, src->nSizeOf);
swap(nAllocated, src->nAllocated);
swap(vChunks, src->vChunks);
swap(pCurr, src->pCurr);
swap(nLeft, src->nLeft);
}
bool BasicAllocator3D::do_validate(const void *ptr) const
{
if (ptr == NULL)
return true;
const uint8_t *uptr = reinterpret_cast(ptr);
ssize_t csize = nSizeOf << nShift;
for (size_t i=0; i= csize))
continue;
if ((delta % nSizeOf) != 0)
return false;
delta /= nSizeOf;
return ((i << nShift) + delta) < nAllocated;
}
return false;
}
ssize_t BasicAllocator3D::calc_index_of(const void *ptr) const
{
if (ptr == NULL)
return -1;
const uint8_t *uptr = reinterpret_cast(ptr);
ssize_t csize = nSizeOf << nShift;
ssize_t offset = 0;
ssize_t chunk_cap = 1 << nShift;
for (size_t i=0; i= csize))
continue;
if ((delta % nSizeOf) != 0)
return -1;
return offset + delta / nSizeOf;
}
return -1;
}
}