77 #ifndef NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
78 #define NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
86 #include <unordered_set>
91 #define checkPtr(ptr, msg) \
93 ptrAssert((ptr), (msg), __FILE__, __LINE__); \
98 template<
typename BufferT>
117 std::shared_ptr<Pool> mPool;
121 #if defined(DEBUG) || defined(_DEBUG)
122 static inline void ptrAssert(
void*
ptr,
const char* msg,
const char* file,
int line,
bool abort =
true)
124 if (ptr ==
nullptr) {
125 fprintf(stderr,
"NULL pointer error: %s %s %d\n", msg, file, line);
130 fprintf(stderr,
"Alignment pointer error: %s %s %d\n", msg, file, line);
136 static inline void ptrAssert(
void*,
const char*,
const char*,
int,
bool =
true)
191 const uint8_t*
data()
const {
return mData; }
192 uint8_t*
data() {
return mData; }
210 bool isEmpty()
const {
return !mPool || mSize == 0 || mData ==
nullptr; }
274 mData =
static_cast<uint8_t*
>(Pool::alloc(
mSize));
275 if (
mData ==
nullptr) {
276 throw std::runtime_error(
"Pool::Pool malloc failed");
281 throw std::runtime_error(
"Pool::Pool: external memory buffer is not aligned to " +
283 " bytes.\nHint: use nanovdb::alignPtr or std::aligned_alloc (C++17 only)");
315 auto* alignedFree =
mFree + alignmentPadding(
mFree);
318 std::stringstream ss;
319 ss <<
"HostBuffer::Pool: insufficient memory\n"
321 <<
"-bytes alignment from a pool with "
323 <<
" bytes are used by " <<
mRegister.size() <<
" other buffer(s). "
324 <<
"Pool is " << (
mManaged ?
"internally" :
"externally") <<
" managed.\n";
326 throw std::runtime_error(ss.str());
328 buffer->mSize =
size;
329 const std::lock_guard<std::mutex> lock(
mMutex);
331 buffer->mData = alignedFree;
338 const std::lock_guard<std::mutex> lock(
mMutex);
345 const std::lock_guard<std::mutex> lock(
mMutex);
366 const uint64_t memUsage = this->
usage();
368 const bool managed = (
data ==
nullptr);
370 if (!managed && alignmentPadding(
data) != 0) {
371 throw std::runtime_error(
"Pool::resize: external memory buffer is not aligned to " +
375 if (memUsage > size) {
376 throw std::runtime_error(
"Pool::resize: insufficient memory");
379 uint64_t padding = 0;
382 data = Pool::realloc(
mData, memUsage, size, padding);
384 data = Pool::alloc(size);
385 padding = alignmentPadding(
data);
388 if (
data ==
nullptr) {
389 throw std::runtime_error(
"Pool::resize: allocation failed");
391 auto* paddedData =
static_cast<uint8_t*
>(
data) + padding;
400 mFree = paddedData + memUsage;
420 static void* alloc(uint64_t
size)
430 static void* realloc(
void*
const origData,
432 uint64_t desiredSize,
438 if (data !=
nullptr && data != origData) {
439 uint64_t newPadding = alignmentPadding(data);
441 if (newPadding != padding) {
443 std::memmove(static_cast<uint8_t*>(data) + newPadding,
444 static_cast<uint8_t*>(data) + padding,
445 Min(origSize, desiredSize));
446 padding = newPadding;
460 mPool = std::make_shared<Pool>(
size);
461 mData = mPool->mFree;
462 mPool->mRegister.insert(
this);
463 mPool->mFree +=
size;
469 if (mPool && mSize != 0) {
470 mPool->replace(&other,
this);
474 other.mData =
nullptr;
479 if (bufferSize == 0) {
480 throw std::runtime_error(
"HostBuffer: invalid buffer size");
485 if (!mPool || mPool->mSize != bufferSize) {
488 mPool->add(
this, bufferSize);
499 if (mPool && mSize != 0) {
500 mPool->replace(&other,
this);
504 other.mData =
nullptr;
510 return mPool ? mPool->mSize : 0u;
515 return mPool ? mPool->usage(): 0u;
520 return mPool ? mPool->mManaged :
false;
525 return mPool ? mPool->isFull() :
false;
531 throw std::runtime_error(
"HostBuffer: invalid pool size");
537 buffer.mData =
nullptr;
543 if (bufferSize == 0) {
544 throw std::runtime_error(
"HostBuffer: invalid buffer size");
548 buffer.mPool->add(&buffer, bufferSize);
555 if (pool ==
nullptr || !pool->mPool) {
556 buffer.mPool = std::make_shared<Pool>(
bufferSize);
558 buffer.mPool = pool->mPool;
560 buffer.mPool->add(&buffer, bufferSize);
576 if (this->
size()>0) {
577 throw std::runtime_error(
"HostBuffer: only empty buffers can call reset");
580 throw std::runtime_error(
"HostBuffer: this buffer contains no pool to reset");
588 throw std::runtime_error(
"HostBuffer: this buffer contains no pool to resize");
590 mPool->resize(size, data);
595 #endif // end of NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED
~HostBuffer()
Custom descructor.
void init(uint64_t bufferSize, void *data=nullptr)
Initialize as a full buffer with the specified size. If data is NULL the memory is internally allocat...
bool isEmpty() const
Returns true if this buffer has no memory associated with it.
static HostBuffer createPool(uint64_t poolSize, void *data=nullptr)
Return a pool buffer which satisfies: buffer.size == 0, buffer.poolSize() == poolSize, and buffer.data() == nullptr. If data==nullptr, memory for the pool will be allocated.
HostBuffer(uint64_t bufferSize=0)
Return a full buffer or an empty buffer.
Pool & operator=(const Pool &)=delete
Disallow copy assignment operation.
HostBuffer & operator=(HostBuffer &&other)
Move copy assignment operation.
static HostBuffer createFull(uint64_t bufferSize, void *data=nullptr)
Return a full buffer which satisfies: buffer.size == bufferSize, buffer.poolSize() == bufferSize...
void replace(HostBuffer *buffer1, HostBuffer *buffer2)
Replaces buffer1 with buffer2 in the register.
void clear()
Clear this buffer so it is empty.
bool empty() const
Returns true if this buffer has no memory associated with it.
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
void add(HostBuffer *buffer, uint64_t size)
Allocate a buffer of the specified size and add it to the register.
bool isPool() const
Return true if this is a pool, i.e. an empty buffer with a nonempty internal pool, i.e. this->size() == 0 and this->poolSize() != 0.
bool isFull() const
Return true if the pool exists, is nonempty but has no more available memory.
#define NANOVDB_DATA_ALIGNMENT
void resize(uint64_t size, void *data=nullptr)
Resize this Pool and update registered buffers as needed. If data is no NULL it is used as externally...
uint64_t bufferSize() const
Returns the size in bytes associated with this buffer.
uint64_t usage() const
Return the total number of bytes used from this Pool by buffers.
__hostdev__ Type Min(Type a, Type b)
uint8_t * data()
Retuns a pointer to the raw memory buffer managed by this allocator.
Implements a light-weight self-contained VDB data-structure in a single file! In other words...
static constexpr bool hasDeviceDual
const uint8_t * data() const
Retuns a pointer to the raw memory buffer managed by this allocator.
auto fprintf(std::FILE *f, const S &fmt, const T &...args) -> int
uint64_t poolUsage() const
Total number of bytes from the pool currently in use by buffers.
~Pool()
Custom destructor.
bool isManaged() const
Return true if memory is managed (using std::malloc and std:free) by the shared pool in this buffer...
Pool(uint64_t size=0, void *data=nullptr)
External memory ctor.
void reset()
Reset the register and all its buffers.
bool isFull() const
Return true is all the memory in this pool is in use.
void resizePool(uint64_t poolSize, void *data=nullptr)
resize the pool size. It will attempt to resize the existing memory block, but if that fails a deep c...
uint64_t size() const
Returns the size in bytes associated with this buffer.
void reset()
Clears all existing buffers that are registered against the memory pool and resets the pool so it can...
uint64_t poolSize() const
Returns the size in bytes of the memory pool shared with this instance.
**Note that the tasks the is the thread number *for the pool
static HostBuffer create(uint64_t bufferSize, const HostBuffer *pool=nullptr)
Return a buffer with bufferSize bytes managed by the specified memory pool. If none is provided...
std::unordered_set< HostBuffer * > HashTableT