274 lines
8.7 KiB
C++
274 lines
8.7 KiB
C++
/**************************************************************************************/
|
|
/* */
|
|
/* Visualization Library */
|
|
/* http://visualizationlibrary.org */
|
|
/* */
|
|
/* Copyright (c) 2005-2020, Michele Bosi */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or without modification, */
|
|
/* are permitted provided that the following conditions are met: */
|
|
/* */
|
|
/* - Redistributions of source code must retain the above copyright notice, this */
|
|
/* list of conditions and the following disclaimer. */
|
|
/* */
|
|
/* - Redistributions in binary form must reproduce the above copyright notice, this */
|
|
/* list of conditions and the following disclaimer in the documentation and/or */
|
|
/* other materials provided with the distribution. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
|
|
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
|
|
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
|
|
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
|
|
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
|
|
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
|
|
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
|
|
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
|
|
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
|
|
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
|
/* */
|
|
/**************************************************************************************/
|
|
|
|
#ifndef Buffer_INCLUDE_ONCE
|
|
#define Buffer_INCLUDE_ONCE
|
|
|
|
#include <vlCore/Object.hpp>
|
|
#include <string.h>
|
|
|
|
namespace vl
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
// Buffer
|
|
//-----------------------------------------------------------------------------
|
|
/**
|
|
* Implements a buffer whose storage is in local memory.
|
|
*/
|
|
class Buffer: public Object
|
|
{
|
|
VL_INSTRUMENT_CLASS(vl::Buffer, Object)
|
|
|
|
public:
|
|
typedef enum
|
|
{
|
|
UserAllocatedBuffer,
|
|
AutoAllocatedBuffer
|
|
} EAllocationMode;
|
|
|
|
public:
|
|
Buffer()
|
|
{
|
|
VL_DEBUG_SET_OBJECT_NAME()
|
|
mPtr = NULL;
|
|
mByteCount = 0;
|
|
mAlignment = VL_DEFAULT_BUFFER_BYTE_ALIGNMENT;
|
|
mAllocationMode = AutoAllocatedBuffer;
|
|
}
|
|
Buffer(const Buffer& other): Object(other)
|
|
{
|
|
VL_DEBUG_SET_OBJECT_NAME()
|
|
mPtr = NULL;
|
|
mByteCount = 0;
|
|
mAlignment = VL_DEFAULT_BUFFER_BYTE_ALIGNMENT;
|
|
mAllocationMode = AutoAllocatedBuffer;
|
|
// copy local data
|
|
*this = other;
|
|
}
|
|
Buffer& operator=(const Buffer& other)
|
|
{
|
|
if ( mAllocationMode == AutoAllocatedBuffer)
|
|
{
|
|
// same alignment
|
|
mAlignment = other.mAlignment;
|
|
// make space for new data
|
|
resize(other.bytesUsed());
|
|
// copy new data
|
|
memcpy(mPtr, other.ptr(), bytesUsed());
|
|
}
|
|
else
|
|
{
|
|
VL_CHECK(mPtr);
|
|
VL_CHECK(other.mPtr);
|
|
VL_CHECK(mByteCount == other.mByteCount);
|
|
memcpy(mPtr, other.ptr(), bytesUsed());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// swaps the data
|
|
void swap(Buffer& other)
|
|
{
|
|
// temp
|
|
unsigned char* tmp_ptr = mPtr;
|
|
size_t tmp_byte_count = mByteCount;
|
|
size_t tmp_alignment = mAlignment;
|
|
// this <- other
|
|
mPtr = other.mPtr;
|
|
mByteCount = other.mByteCount;
|
|
mAlignment = other.mAlignment;
|
|
// this -> other
|
|
other.mPtr = tmp_ptr;
|
|
other.mByteCount = tmp_byte_count;
|
|
other.mAlignment = tmp_alignment;
|
|
}
|
|
|
|
~Buffer()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
if ( mAllocationMode == AutoAllocatedBuffer ) {
|
|
alignedFree(mPtr);
|
|
}
|
|
mPtr = NULL;
|
|
mByteCount = 0;
|
|
mAllocationMode = AutoAllocatedBuffer;
|
|
}
|
|
|
|
// if alignment < 1 uses the last specified alignment or the default one
|
|
void resize(size_t byte_count, size_t alignment = 0)
|
|
{
|
|
VL_CHECK( mAllocationMode == AutoAllocatedBuffer );
|
|
|
|
if (byte_count == 0)
|
|
{
|
|
clear();
|
|
return;
|
|
}
|
|
|
|
alignment = alignment >= 1 ? alignment : mAlignment;
|
|
if ( byte_count != mByteCount || alignment != mAlignment)
|
|
{
|
|
mAlignment = alignment;
|
|
// allocate the new chunk
|
|
unsigned char* ptr = NULL;
|
|
if (byte_count)
|
|
ptr = (unsigned char*)alignedMalloc(byte_count, mAlignment);
|
|
if (mPtr)
|
|
{
|
|
if (byte_count)
|
|
{
|
|
size_t min = mByteCount < byte_count ? mByteCount : byte_count;
|
|
// copy the old content brutally
|
|
memcpy(ptr, mPtr, min);
|
|
}
|
|
// free the old pointer
|
|
alignedFree(mPtr);
|
|
}
|
|
// set the new pointer
|
|
mPtr = ptr;
|
|
// set the new reserved bytes
|
|
mByteCount = byte_count;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Uses a user-allocated buffer as storage.
|
|
* After calling this function any call to resize() is illegal.
|
|
* Calling this function enables the UserAllocatedBuffer mode. Call
|
|
* setAllocationMode( AutoAllocatedBuffer ) to revert to the default
|
|
* behaviour.
|
|
*/
|
|
void setUserAllocatedBuffer(void* ptr, size_t bytes)
|
|
{
|
|
clear();
|
|
mPtr = (unsigned char*)ptr;
|
|
mByteCount = bytes;
|
|
mAlignment = 0;
|
|
mAllocationMode = UserAllocatedBuffer;
|
|
}
|
|
|
|
void setAllocationMode( EAllocationMode mode )
|
|
{
|
|
if ( mAllocationMode != mode )
|
|
{
|
|
clear();
|
|
mAllocationMode = mode;
|
|
// reset buffer data
|
|
mPtr = 0;
|
|
mByteCount = 0;
|
|
mAlignment = 0;
|
|
}
|
|
}
|
|
|
|
EAllocationMode allocationMode() const { return mAllocationMode; }
|
|
|
|
size_t bytesUsed() const { return mByteCount; }
|
|
|
|
bool empty() const { return mByteCount == 0; }
|
|
|
|
unsigned char* ptr() { return mPtr; }
|
|
|
|
const unsigned char* ptr() const { return mPtr; }
|
|
|
|
size_t alignment() const { return mAlignment; }
|
|
|
|
// returns a chunck of memory aligned to the specified amount
|
|
// alignment must be a power of two
|
|
static void *alignedMalloc(size_t bytes, size_t alignment)
|
|
{
|
|
// alignment must be a power of two
|
|
if ( alignment & (alignment-1))
|
|
return NULL;
|
|
|
|
size_t actual_byte_count = bytes + alignment - 1;
|
|
|
|
// reserve space to store the delta
|
|
actual_byte_count += sizeof(int);
|
|
|
|
// allocation
|
|
char *original_ptr = new char[actual_byte_count];
|
|
|
|
if (original_ptr == NULL)
|
|
return NULL;
|
|
|
|
// move base pointer by the space required for our delta
|
|
char *base_ptr = (char *)original_ptr + sizeof(int);
|
|
|
|
// align the pointer
|
|
#if 1
|
|
// warning-free workaround
|
|
unsigned long long long_long_ptr = base_ptr - (char*)0;
|
|
while( long_long_ptr % alignment ) ++long_long_ptr;
|
|
void *aligned_ptr = (char*)0 + long_long_ptr;
|
|
#else
|
|
// this generates too many warnings
|
|
void *aligned_ptr = (void *) (((unsigned long long)base_ptr + alignment - 1) & ~((unsigned long long)alignment - 1));
|
|
#endif
|
|
|
|
// compute the delta
|
|
int delta = (int)((char*)aligned_ptr - (char*)original_ptr);
|
|
|
|
// store the delta just sizeof(int) bytes before the aligned pointer
|
|
*((int *)aligned_ptr - 1) = delta;
|
|
|
|
return aligned_ptr;
|
|
}
|
|
|
|
static void alignedFree(void *ptr)
|
|
{
|
|
if (ptr == NULL)
|
|
return;
|
|
|
|
// gets the previously stored delta
|
|
int delta = *( (int *)ptr - 1);
|
|
|
|
// calculate the pointer returned by malloc()
|
|
char *original_ptr = (char*)ptr - delta;
|
|
|
|
// finally free the original pointer
|
|
delete [] original_ptr;
|
|
}
|
|
|
|
protected:
|
|
unsigned char* mPtr;
|
|
size_t mByteCount;
|
|
size_t mAlignment;
|
|
EAllocationMode mAllocationMode;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|