//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2012 Ceetron AS // // This library is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at <> // for more details. // //################################################################################################## namespace cvf { //================================================================================================== /// /// \class cvf::Array /// \ingroup Core /// /// Templated version of a simple array designed for high performance and no overhead over C arrays /// in release (non-check builds). /// /// Will only work on simple types and classes that do not rely on a constructor or /// destructor (as they are not called). /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// Create an empty array //-------------------------------------------------------------------------------------------------- template Array::Array() { ground(); } //-------------------------------------------------------------------------------------------------- /// Create an array with the given number of elements //-------------------------------------------------------------------------------------------------- template Array::Array(size_t size) { CVF_ASSERT(size > 0); ground(); resize(size); } //-------------------------------------------------------------------------------------------------- /// Create the array and assign (copy) the given data //-------------------------------------------------------------------------------------------------- template Array::Array(const T* data, size_t size) { CVF_ASSERT(data); CVF_ASSERT(size > 0); ground(); assign(data, size); } //-------------------------------------------------------------------------------------------------- /// Create the array and assign (copy) the given data //-------------------------------------------------------------------------------------------------- template Array::Array(const Array& other) : Object(), ValueArray() { ground(); if (other.size() > 0) { assign(other.m_data, other.size()); } } //-------------------------------------------------------------------------------------------------- /// Explicit constructor to create the array and assign (copy) the passed value array //-------------------------------------------------------------------------------------------------- template Array::Array(const ValueArray& other) { ground(); if (other.size() > 0) { resize(other.size()); size_t i; for (i = 0; i < other.size(); i++) { set(i, other.val(i)); } } } //-------------------------------------------------------------------------------------------------- /// Explicit constructor to create the array and assign (copy) the passed std::vector //-------------------------------------------------------------------------------------------------- template Array::Array(const std::vector& other) { ground(); if (other.size() > 0) { assign(other); } } //-------------------------------------------------------------------------------------------------- /// Init all members //-------------------------------------------------------------------------------------------------- template void Array::ground() { m_size = 0; m_data = NULL; m_capacity = 0; m_sharedData = false; } //-------------------------------------------------------------------------------------------------- /// Destructor. Deletes the data. //-------------------------------------------------------------------------------------------------- template Array::~Array() { clear(); } //-------------------------------------------------------------------------------------------------- /// Returns a const reference to the element at the given index. //-------------------------------------------------------------------------------------------------- template inline const T& Array::operator[] (size_t index) const { CVF_TIGHT_ASSERT(this && m_data); CVF_TIGHT_ASSERT(index < m_size); return m_data[index]; } //-------------------------------------------------------------------------------------------------- /// Returns a modifiable reference to the element at the given index. //-------------------------------------------------------------------------------------------------- template inline T& Array::operator[] (size_t index) { CVF_TIGHT_ASSERT(this && m_data); CVF_TIGHT_ASSERT(index < m_size); return m_data[index]; } //-------------------------------------------------------------------------------------------------- /// Assign (copy) the data in the given array //-------------------------------------------------------------------------------------------------- template Array& Array::operator=(Array rhs) { CVF_TIGHT_ASSERT(!m_sharedData); rhs.swap(*this); return *this; } //-------------------------------------------------------------------------------------------------- /// Resize the array to the given size. /// The current contents (data) will be kept (as much as possible). Any new elements will be unassigned. /// Calling resize(0) is the same as clear(). //-------------------------------------------------------------------------------------------------- template void Array::resize(size_t size) { CVF_ASSERT(!m_sharedData); if (size > 0) { if (m_data) { // Copy old data T* pTmp = m_data; m_data = new T[size]; size_t numToCopy = CVF_MIN(size, m_size); cvf::System::memcpy(m_data, size*sizeof(T), pTmp, numToCopy*sizeof(T)); delete[] pTmp; } else { m_data = new T[size]; } m_size = size; m_capacity = size; } else { clear(); } } //-------------------------------------------------------------------------------------------------- /// Clear the array, freeing all memory (if not shared) and setting capacity and size to zero. /// If the array was in shared mode, it will not be in shared mode anymore. //-------------------------------------------------------------------------------------------------- template void Array::clear() { if (!m_sharedData) { delete[] m_data; } ground(); } //-------------------------------------------------------------------------------------------------- /// Returns the number of elements in the array //-------------------------------------------------------------------------------------------------- template inline size_t Array::size() const { return m_size; } //-------------------------------------------------------------------------------------------------- /// Set the element at the given index. Index must be < size() //-------------------------------------------------------------------------------------------------- template inline void Array::set(size_t index, const T& val) { CVF_TIGHT_ASSERT(index < m_size); m_data[index] = val; } //-------------------------------------------------------------------------------------------------- /// Set all elements in the array to the given value //-------------------------------------------------------------------------------------------------- template inline void Array::setAll(const T& val) { size_t i; for (i = 0; i < m_size; i++) { set(i, val); } } //-------------------------------------------------------------------------------------------------- /// Assign consecutive values to the elements in the array /// /// Example: setConsecutive(2) on an array with size=3 gives: {2,3,4} //-------------------------------------------------------------------------------------------------- template void Array::setConsecutive(const T& startValue) { T val = startValue; size_t i; for (i = 0; i < m_size; i++) { set(i, val++); } } //-------------------------------------------------------------------------------------------------- /// Returns a const reference to the element at the given index //-------------------------------------------------------------------------------------------------- template const T& cvf::Array::get(size_t index) const { CVF_TIGHT_ASSERT(index < m_size); return m_data[index]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template T cvf::Array::val(size_t index) const { CVF_TIGHT_ASSERT(index < m_size); return m_data[index]; } //-------------------------------------------------------------------------------------------------- /// Returns a const native pointer to the array storing the data //-------------------------------------------------------------------------------------------------- template inline const T* Array::ptr() const { CVF_TIGHT_ASSERT(this); return m_data; } //-------------------------------------------------------------------------------------------------- /// Returns the native pointer to the array storing the data //-------------------------------------------------------------------------------------------------- template inline T* Array::ptr() { CVF_TIGHT_ASSERT(this); return m_data; } //-------------------------------------------------------------------------------------------------- /// Returns a const native pointer to the array storing the data //-------------------------------------------------------------------------------------------------- template inline const T* Array::ptr(size_t index) const { CVF_TIGHT_ASSERT(this); CVF_TIGHT_ASSERT(index < m_size); return &m_data[index]; } //-------------------------------------------------------------------------------------------------- /// Returns the native pointer to the array storing the data //-------------------------------------------------------------------------------------------------- template inline T* Array::ptr(size_t index) { CVF_TIGHT_ASSERT(this); CVF_TIGHT_ASSERT(index < m_size); return &m_data[index]; } //-------------------------------------------------------------------------------------------------- /// Data shared with another class. Will not delete on destruction. /// /// Any method that reallocates data (resize, assign & setPtr) is not allowed and will assert /// The only way to break the shared 'connection' is via clear() //-------------------------------------------------------------------------------------------------- template void Array::setSharedPtr(T* data, size_t size) { CVF_ASSERT((data && size > 0) || (!data && size == 0)); clear(); m_data = data; m_size = size; m_sharedData = true; } //-------------------------------------------------------------------------------------------------- /// Set the data in the array to use the passed array. /// /// This class takes ownership of the passed data. //-------------------------------------------------------------------------------------------------- template void Array::setPtr(T* data, size_t size) { CVF_ASSERT((data && size > 0) || (!data && size == 0)); // Not allowed // The only way to break the shared 'connection' is via clear() CVF_ASSERT(!m_sharedData); clear(); m_data = data; m_size = size; } //-------------------------------------------------------------------------------------------------- /// Delete any current data and set from the given data pointer //-------------------------------------------------------------------------------------------------- template void Array::assign(const T* data, size_t size) { CVF_ASSERT(data); CVF_ASSERT(size > 0); CVF_ASSERT(!m_sharedData); clear(); resize(size); // copy cvf::System::memcpy(m_data, m_size*sizeof(T), data, size*sizeof(T)); } //-------------------------------------------------------------------------------------------------- /// Delete any current data and set from the given data //-------------------------------------------------------------------------------------------------- template void Array::assign(const std::vector& data) { CVF_ASSERT(!m_sharedData); clear(); size_t newSize = data.size(); if (newSize > 0) { resize(newSize); cvf::System::memcpy(m_data, m_size*sizeof(T), &data[0], newSize*sizeof(T)); } } //-------------------------------------------------------------------------------------------------- /// Copy data into the array /// /// \warning Must have enough room for the new data, meaning the array must be resize()'ed before use //-------------------------------------------------------------------------------------------------- template void Array::copyData(const T* pSource, size_t numElementsToCopy, size_t destIndex) { CVF_ASSERT(pSource); CVF_ASSERT(numElementsToCopy > 0); CVF_ASSERT(destIndex < m_size); CVF_ASSERT(destIndex + numElementsToCopy <= m_size); cvf::System::memcpy(m_data + destIndex, (m_size - destIndex)*sizeof(T), pSource, numElementsToCopy*sizeof(T)); } //-------------------------------------------------------------------------------------------------- /// Copy data into the array /// /// \warning Must have enough room for the new data, meaning the array must be resize()'ed before use //-------------------------------------------------------------------------------------------------- template void Array::copyData(const Array& source, size_t numElementsToCopy, size_t destIndex, size_t sourceIndex) { CVF_ASSERT(numElementsToCopy > 0); CVF_ASSERT(destIndex < m_size); CVF_ASSERT(numElementsToCopy + destIndex <= m_size); cvf::System::memcpy(m_data + destIndex, (m_size - destIndex)*sizeof(T), source.ptr() + sourceIndex, numElementsToCopy*sizeof(T)); } //-------------------------------------------------------------------------------------------------- /// Copy data into this array with conversion. /// Data in source array will be converted using static_cast //-------------------------------------------------------------------------------------------------- template template void Array::copyConvertedData(const Array& source, size_t numElementsToCopy, size_t destIndex, size_t sourceIndex) { CVF_ASSERT(numElementsToCopy > 0); CVF_ASSERT(destIndex < m_size); CVF_ASSERT(numElementsToCopy + destIndex <= m_size); size_t dst = destIndex; size_t i; for (i = sourceIndex; i < sourceIndex + numElementsToCopy; i++) { m_data[dst++] = static_cast(source[i]); } } //-------------------------------------------------------------------------------------------------- /// Returns an array containing the specified elements /// /// Example: ///
///   this           = {2.0, 5.5, 100.0}
///   elementIndices = {  0,     2,   1,   0,     2}
///   -> output      = {2.0, 100.0, 5.5, 2.0, 100.0}
/// 
//-------------------------------------------------------------------------------------------------- template template ref > Array::extractElements(const Array& elementIndices) const { ref > arr = new Array; size_t numItems = elementIndices.size(); if (numItems > 0) { arr->resize(numItems); size_t i; for (i = 0; i < numItems; i++) { U idx = elementIndices[i]; arr->set(i, get(idx)); } } return arr; } //-------------------------------------------------------------------------------------------------- /// Copy the contents of the array to the given std::vector //-------------------------------------------------------------------------------------------------- template void Array::toStdVector(std::vector* vec) const { CVF_ASSERT(vec); size_t numItems = size(); vec->resize(numItems); size_t i; for (i = 0; i < numItems; i++) { (*vec)[i] = (*this)[i]; } } //-------------------------------------------------------------------------------------------------- /// Get the current capacity of the array (the size of the buffer). This will return a number >= size(), /// depending on if reserve() has been used or not. /// If capacity() > size(), then add() is allowed on the array. /// /// \sa /// - reserve() /// - add() /// - squeeze() /// - setSizeZero() //-------------------------------------------------------------------------------------------------- template size_t Array::capacity() const { return m_capacity; } //-------------------------------------------------------------------------------------------------- /// Reserve (allocate) at least the given number of items. /// If capacity is less than the current buffer, nothing is done. /// size() of the array is not changed. /// /// \sa /// - capacity() /// - add() /// - squeeze() /// - setSizeZero() //-------------------------------------------------------------------------------------------------- template void Array::reserve(size_t capacity) { CVF_ASSERT(!m_sharedData); if ((capacity <= m_size) || (capacity <= m_capacity)) { // Required capacity is less than current capacity, done! return; } CVF_ASSERT(capacity > 0); CVF_ASSERT(capacity > m_size); if (m_data) { // Copy old data T* pTmp = m_data; m_data = new T[capacity]; m_capacity = capacity; cvf::System::memcpy(m_data, capacity*sizeof(T), pTmp, m_size*sizeof(T)); delete[] pTmp; } else { // alloc m_data = new T[capacity]; m_capacity = capacity; } CVF_ASSERT(m_size <= m_capacity); } //-------------------------------------------------------------------------------------------------- /// Realloc the array to the current size(). Removing any reserved memory created by reserve(). /// /// \sa /// - reserve() /// - capacity() /// - add() /// - setSizeZero() //-------------------------------------------------------------------------------------------------- template void Array::squeeze() { CVF_ASSERT(!m_sharedData); if (m_data && (m_size < m_capacity)) { if (m_size > 0) { // Copy old data T* pTmp = m_data; m_data = new T[m_size]; cvf::System::memcpy(m_data, m_capacity*sizeof(T), pTmp, m_size*sizeof(T)); delete[] pTmp; m_capacity = m_size; } else { clear(); } } } //-------------------------------------------------------------------------------------------------- /// Set the size (number of items) in the array to zero, but keep the buffer. Items in the buffer /// are not modified. /// /// \sa /// - reserve() /// - capacity() /// - add() /// - squeeze() //-------------------------------------------------------------------------------------------------- template void Array::setSizeZero() { CVF_TIGHT_ASSERT(!m_sharedData); m_size = 0; } //-------------------------------------------------------------------------------------------------- /// Add an item to the array. /// /// Note that this will not grow the array, so the array needs to be pre-allocated with reserve() /// before calling this method. The method will assert if not enough space. /// /// \sa /// - reserve() /// - capacity() /// - squeeze() /// - setSizeZero() //-------------------------------------------------------------------------------------------------- template inline void Array::add(const T& val) { CVF_TIGHT_ASSERT(!m_sharedData); CVF_TIGHT_ASSERT(m_size < m_capacity); m_data[m_size] = val; m_size++; } //-------------------------------------------------------------------------------------------------- /// Get the min value and optionally the index of the (first) min value /// Works only on arrays with types that implement comparison operators /// Empty arrays will return std::numeric_limits::max() and not modify index //-------------------------------------------------------------------------------------------------- template T Array::min(size_t* index) const { T minVal = std::numeric_limits::max(); size_t i; for (i = 0; i < m_size; i++) { if (m_data[i] < minVal) { minVal = m_data[i]; if (index) { *index = i; } } } return minVal; } //-------------------------------------------------------------------------------------------------- /// Get the min value and optionally the index of the (first) min value /// Works only on arrays with types that implement comparison operators /// Empty arrays will return std::numeric_limits::max() and not modify index //-------------------------------------------------------------------------------------------------- template T Array::max(size_t* index) const { T maxVal = std::numeric_limits::min(); size_t i; for (i = 0; i < m_size; i++) { if (m_data[i] > maxVal) { maxVal = m_data[i]; if (index) { *index = i; } } } return maxVal; } //-------------------------------------------------------------------------------------------------- /// Exchanges the contents of the two arrays. /// /// \param other Modifiable reference to the array that should have its contents swapped. /// /// \warning Note that signature differs from normal CeeVizFramework practice. This is done to be /// consistent with the signature of std::swap() //-------------------------------------------------------------------------------------------------- template void Array::swap(Array& other) { using std::swap; swap(m_size, other.m_size); swap(m_capacity, other.m_capacity); swap(m_data, other.m_data); swap(m_sharedData, other.m_sharedData); } } // namespace cvf