blob: 5a98898f3e5fbc154240cb920322b50e33abc4f3 [file] [log] [blame]
#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