228 lines
6.1 KiB
C++
228 lines
6.1 KiB
C++
|
#ifndef _DEARRAYBUFFER_HPP
|
||
|
#define _DEARRAYBUFFER_HPP
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* drawElements C++ Base Library
|
||
|
* -----------------------------
|
||
|
*
|
||
|
* Copyright 2014 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*//*!
|
||
|
* \file
|
||
|
* \brief Array buffer
|
||
|
*//*--------------------------------------------------------------------*/
|
||
|
|
||
|
#include "deDefs.hpp"
|
||
|
#include "deMemory.h"
|
||
|
|
||
|
#include <new>
|
||
|
|
||
|
namespace de
|
||
|
{
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
void* ArrayBuffer_AlignedMalloc (size_t numBytes, size_t alignment);
|
||
|
void ArrayBuffer_AlignedFree (void*);
|
||
|
|
||
|
} // detail
|
||
|
|
||
|
//! Array buffer self-test.
|
||
|
void ArrayBuffer_selfTest (void);
|
||
|
|
||
|
/*--------------------------------------------------------------------*//*!
|
||
|
* \brief Contiguous array that does not initialize its elements.
|
||
|
*//*--------------------------------------------------------------------*/
|
||
|
template <typename T, size_t Alignment = (sizeof(T) > 4 ? 4 : sizeof(T)), size_t Stride = sizeof(T)>
|
||
|
class ArrayBuffer
|
||
|
{
|
||
|
public:
|
||
|
DE_STATIC_ASSERT(Stride >= sizeof(T));
|
||
|
|
||
|
ArrayBuffer (void) throw();
|
||
|
ArrayBuffer (size_t numElements);
|
||
|
ArrayBuffer (const T* ptr, size_t numElements);
|
||
|
ArrayBuffer (const ArrayBuffer& other);
|
||
|
~ArrayBuffer (void) throw();
|
||
|
ArrayBuffer& operator= (const ArrayBuffer& other);
|
||
|
|
||
|
void clear (void) throw();
|
||
|
void setStorage (size_t numElements); // !< \note after a succesful call buffer contents are undefined
|
||
|
void swap (ArrayBuffer& other) throw();
|
||
|
size_t size (void) const throw();
|
||
|
bool empty (void) const throw();
|
||
|
|
||
|
T* getElementPtr (size_t elementNdx) throw();
|
||
|
const T* getElementPtr (size_t elementNdx) const throw();
|
||
|
void* getPtr (void) throw();
|
||
|
const void* getPtr (void) const throw();
|
||
|
|
||
|
private:
|
||
|
void* m_ptr;
|
||
|
size_t m_cap;
|
||
|
} DE_WARN_UNUSED_TYPE;
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (void) throw()
|
||
|
: m_ptr (DE_NULL)
|
||
|
, m_cap (0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (size_t numElements)
|
||
|
: m_ptr (DE_NULL)
|
||
|
, m_cap (0)
|
||
|
{
|
||
|
if (numElements)
|
||
|
{
|
||
|
// \note no need to allocate stride for the last element, sizeof(T) is enough. Also handles cases where sizeof(T) > Stride
|
||
|
const size_t storageSize = (numElements - 1) * Stride + sizeof(T);
|
||
|
void* const ptr = detail::ArrayBuffer_AlignedMalloc(storageSize, Alignment);
|
||
|
|
||
|
if (!ptr)
|
||
|
throw std::bad_alloc();
|
||
|
|
||
|
m_ptr = ptr;
|
||
|
m_cap = numElements;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const T* ptr, size_t numElements)
|
||
|
: m_ptr (DE_NULL)
|
||
|
, m_cap (0)
|
||
|
{
|
||
|
if (numElements)
|
||
|
{
|
||
|
// create new buffer of wanted size, copy to it, and swap to it
|
||
|
ArrayBuffer<T,Alignment,Stride> tmp(numElements);
|
||
|
|
||
|
if (Stride == sizeof(T))
|
||
|
{
|
||
|
// tightly packed
|
||
|
const size_t storageSize = sizeof(T) * numElements;
|
||
|
deMemcpy(tmp.m_ptr, ptr, (int)storageSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// sparsely packed
|
||
|
for (size_t ndx = 0; ndx < numElements; ++ndx)
|
||
|
*tmp.getElementPtr(ndx) = ptr[ndx];
|
||
|
}
|
||
|
|
||
|
swap(tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const ArrayBuffer<T,Alignment,Stride>& other)
|
||
|
: m_ptr (DE_NULL)
|
||
|
, m_cap (0)
|
||
|
{
|
||
|
if (other.m_cap)
|
||
|
{
|
||
|
// copy to temporary and swap to it
|
||
|
|
||
|
const size_t storageSize = (other.m_cap - 1) * Stride + sizeof(T);
|
||
|
ArrayBuffer tmp (other.m_cap);
|
||
|
|
||
|
deMemcpy(tmp.m_ptr, other.m_ptr, (int)storageSize);
|
||
|
swap(tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>::~ArrayBuffer (void) throw()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
ArrayBuffer<T,Alignment,Stride>& ArrayBuffer<T,Alignment,Stride>::operator= (const ArrayBuffer& other)
|
||
|
{
|
||
|
ArrayBuffer copied(other);
|
||
|
swap(copied);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
void ArrayBuffer<T,Alignment,Stride>::clear (void) throw()
|
||
|
{
|
||
|
detail::ArrayBuffer_AlignedFree(m_ptr);
|
||
|
|
||
|
m_ptr = DE_NULL;
|
||
|
m_cap = 0;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
void ArrayBuffer<T,Alignment,Stride>::setStorage (size_t numElements)
|
||
|
{
|
||
|
// create new buffer of the wanted size, swap to it
|
||
|
ArrayBuffer<T,Alignment,Stride> newBuffer(numElements);
|
||
|
swap(newBuffer);
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
void ArrayBuffer<T,Alignment,Stride>::swap (ArrayBuffer& other) throw()
|
||
|
{
|
||
|
void* const otherPtr = other.m_ptr;
|
||
|
const size_t otherCap = other.m_cap;
|
||
|
|
||
|
other.m_ptr = m_ptr;
|
||
|
other.m_cap = m_cap;
|
||
|
m_ptr = otherPtr;
|
||
|
m_cap = otherCap;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
size_t ArrayBuffer<T,Alignment,Stride>::size (void) const throw()
|
||
|
{
|
||
|
return m_cap;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
bool ArrayBuffer<T,Alignment,Stride>::empty (void) const throw()
|
||
|
{
|
||
|
return size() == 0;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) throw()
|
||
|
{
|
||
|
return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
const T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) const throw()
|
||
|
{
|
||
|
return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) throw()
|
||
|
{
|
||
|
return m_ptr;
|
||
|
}
|
||
|
|
||
|
template <typename T, size_t Alignment, size_t Stride>
|
||
|
const void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) const throw()
|
||
|
{
|
||
|
return m_ptr;
|
||
|
}
|
||
|
|
||
|
} // de
|
||
|
|
||
|
#endif // _DEARRAYBUFFER_HPP
|