omni/extras/ScratchBuffer.h
File members: omni/extras/ScratchBuffer.h
// Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "../../carb/Defines.h"
#include <algorithm>
#include <iterator>
namespace omni
{
namespace extras
{
#ifdef DOXYGEN_BUILD // Sphinx does not like the computation and reports errors, so special case for documentation.
template <typename T, size_t BaseSize_ = 16, size_t ShrinkThreshold_ = 100>
#else
template <typename T, size_t BaseSize_ = CARB_MAX(512ull / sizeof(T), 16ull), size_t ShrinkThreshold_ = 100>
#endif
class ScratchBuffer
{
public:
using DataType = T;
static constexpr size_t BaseSize = BaseSize_;
ScratchBuffer()
{
m_dynamicArray = m_localArray;
m_size = BaseSize;
m_capacity = BaseSize;
}
ScratchBuffer(const ScratchBuffer& right) : ScratchBuffer()
{
*this = right;
}
ScratchBuffer(ScratchBuffer&& right) : ScratchBuffer()
{
*this = std::move(right);
}
~ScratchBuffer()
{
if (m_dynamicArray != nullptr && m_dynamicArray != m_localArray)
delete[] m_dynamicArray;
}
ScratchBuffer& operator=(const ScratchBuffer& right)
{
if (&right == this)
return *this;
if (!resize(right.m_size))
return *this;
std::copy_n(right.m_dynamicArray, m_size, m_dynamicArray);
return *this;
}
ScratchBuffer& operator=(ScratchBuffer&& right)
{
if (&right == this)
return *this;
if (!resize(right.m_size))
return *this;
std::copy_n(std::make_move_iterator(right.m_dynamicArray), m_size, m_dynamicArray);
return *this;
}
T& operator[](size_t index)
{
return m_dynamicArray[index];
}
T* data()
{
return m_dynamicArray;
}
const T* data() const
{
return m_dynamicArray;
}
size_t size() const
{
return m_size;
}
bool resize(size_t count)
{
T* tmp = m_localArray;
size_t copyCount;
if (count == 0)
return true;
// the buffer is already the requested size -> nothing to do => succeed.
if (count == m_size)
return true;
// the buffer is already large enough => don't resize unless the change is drastic.
if (count <= m_capacity)
{
if ((count * 100) >= ShrinkThreshold_ * m_size)
{
m_size = count;
return true;
}
}
if (count > BaseSize)
{
tmp = new (std::nothrow) T[count];
if (tmp == nullptr)
return false;
}
// the buffer didn't change -> nothing to copy => update parameters and succeed.
if (tmp == m_dynamicArray)
{
m_size = count;
m_capacity = BaseSize;
return true;
}
copyCount = m_size;
if (m_size > count)
copyCount = count;
std::copy_n(std::make_move_iterator(m_dynamicArray), copyCount, tmp);
if (m_dynamicArray != nullptr && m_dynamicArray != m_localArray)
delete[] m_dynamicArray;
m_dynamicArray = tmp;
m_size = count;
m_capacity = count;
return true;
}
private:
T m_localArray[BaseSize];
T* m_dynamicArray;
size_t m_size = BaseSize;
size_t m_capacity = BaseSize;
};
} // namespace extras
} // namespace omni