/** ******************************************************************************* * @file EdnEdnVectorBin.h * @brief Editeur De N'ours : Basic EdnVectorBin for direct data insertion (template) * @author Edouard DUPIN * @date 07/04/2011 * @par Project * Edn * * @par Copyright * Copyright 2010 Edouard DUPIN, all right reserved * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY. * * Licence summary : * You can modify and redistribute the sources code and binaries. * You can send me the bug-fix * You can not earn money with this Software (if the source extract from Edn * represent less than 50% of original Sources) * Term of the licence in in the file licence.txt. * ******************************************************************************* */ #ifndef __EDN_VECTOR_BIN_H__ #define __EDN_VECTOR_BIN_H__ #include "toolsMemory.h" #undef __class__ #define __class__ "EdnEdnVectorBin" /** * @brief EdnVectorBin classes ... * * @tparam[in] SIZE Size of the current element. * * @todo : Need to add : popBack / Assign / Insert / Erase / Swap / Clear * * m_data * <------------ m_dataSize ------------> * ---------------------------------------- * | 0 | * |--------------------------------------| * | 1 | * |--------------------------------------| * | 2 | * |--------------------------------------| * m_size | 3 | * |--------------------------------------| * | x | * |--------------------------------------| * | x | * |--------------------------------------| * | x | * |--------------------------------------| * | x | * |--------------------------------------| * | x | * |--------------------------------------| * | x | * |--------------------------------------| * m_allocated | x | * ---------------------------------------- * */ template class EdnVectorBin { public: class Iterator { // Private data : private: int32_t m_current; // curent Id on the vector EdnVectorBin * m_EdnVectorBin; // Pointer on the curent element of the vectorBin public: /** * @brief Basic itarator constructor with no link with an EdnVector */ Iterator(): m_current(-1), m_EdnVectorBin(NULL) { // nothing to do ... } /** * @brief Recopy constructor on a specific EdnVector. * @param[in] otherIterator The Iterator that might be copy */ Iterator(const Iterator & otherIterator): m_current(otherIterator.m_current), m_EdnVectorBin(otherIterator.m_EdnVectorBin) { // nothing to do ... } /** * @brief Asignation operator. * @param[in] otherIterator The Iterator that might be copy * @return reference on the curent Iterator */ Iterator& operator=(const Iterator & otherIterator) { m_current = otherIterator.m_current; m_EdnVectorBin = otherIterator.m_EdnVectorBin; return *this; } /** * @brief Basic destructor */ ~Iterator() { m_current = -1; m_EdnVectorBin = NULL; } /** * @brief basic boolean cast * @return true if the element is present in the EdnVector size */ operator bool () { if( 0 <= m_current && m_current < m_EdnVectorBin->Size() ) { return true; } else { return false; } } /** * @brief Incremental operator * @return Reference on the current iterator incremented */ Iterator& operator++ () { if( NULL != m_EdnVectorBin && m_current < m_EdnVectorBin->Size() ) { m_current++; } return *this; } /** * @brief Decremental operator * @return Reference on the current iterator decremented */ Iterator& operator-- () { if (m_current >= 0) { m_current--; } return *this; } /** * @brief Incremental operator * @return Reference on a new iterator and increment the other one */ Iterator operator++ (int32_t) { Iterator it(*this); ++(*this); return it; } /** * @brief Decremental operator * @return Reference on a new iterator and decrement the other one */ Iterator operator-- (int32_t) { Iterator it(*this); --(*this); return it; } /** * @brief Get reference on the current Element * @return the reference on the current Element */ MY_TYPE & operator-> () const { EDN_CHECK_INOUT(m_current >= 0 && m_current < m_EdnVectorBin->Size()); return &m_EdnVectorBin->Get(m_current); } /** * @brief Get reference on the current Element * @return the reference on the current Element */ MY_TYPE & operator* () const { EDN_CHECK_INOUT(m_current >= 0 && m_current < m_EdnVectorBin->Size()); return m_EdnVectorBin->Get(m_current); } private: /** * @brief * * @param[in,out] --- * * @return --- * */ Iterator(EdnVectorBin * Evb, int32_t pos): m_current(pos), m_EdnVectorBin(Evb) { // nothing to do ... } friend class EdnVectorBin; }; private: MY_TYPE * m_data; //!< pointer on the curetn table of Data int32_t m_size; //!< nb Element in the buffer int32_t m_allocated; //!< Current allocated size int32_t m_increment; //!< methode of increment public: /** * @brief Create an empty vector * @param[in] count Minimum request size of the Buffer */ EdnVectorBin(int32_t count = 0): m_data(NULL), m_size(0), m_allocated(0), m_increment(1) { ChangeAllocation(count); } /** * @brief Re-copy constructor (copy all needed data) * @param[in] Evb Vector that might be copy */ EdnVectorBin(const EdnVectorBin & Evb) { m_allocated = Evb.m_allocated; m_size = Evb.m_size; m_increment = Evb.m_increment; m_data = NULL; //EDN_DEBUG("USE Specific vector allocator ... Evb.m_size=" << Evb.m_size << " Evb.m_increment=" << Evb.m_increment); // allocate all same data EDN_MALLOC(m_data, m_allocated, MY_TYPE); EDN_ASSERT(NULL!=m_data, "Error in data allocation"); // Copy all data ... memcpy(m_data, Evb.m_data, m_allocated * sizeof(MY_TYPE) ); } /** * @brief Destructor of the current Class */ ~EdnVectorBin() { if (NULL!=m_data) { EDN_FREE(m_data); m_data = NULL; m_allocated = 0; m_size = 0; m_increment = 0; } } /** * @brief Re-copy operator * @param[in] Evb Vector that might be copy * @return reference on the curent re-copy vector */ EdnVectorBin& operator=(const EdnVectorBin & Evb) { //EDN_DEBUG("USE RECOPY vector ... Evb.m_size=" << Evb.m_size << " Evb.m_increment=" << Evb.m_increment); if( this != &Evb ) // avoid copy to itself { if (NULL!=m_data) { EDN_FREE(m_data); m_data = NULL; } // Set the new value m_allocated = Evb.m_allocated; m_size = Evb.m_size; m_increment = Evb.m_increment; // allocate all same data EDN_MALLOC(m_data, m_allocated, MY_TYPE); EDN_ASSERT(NULL!=m_data, "Error in data allocation"); // Copy all data ... memcpy(m_data, Evb.m_data, m_allocated * sizeof(MY_TYPE) ); } // Return the curent pointer return *this; } /** * @brief Add at the Last position of the Vector * @param[in] item Element to add at the end of vector */ EdnVectorBin& operator+= (const EdnVectorBin & Evb) // += operator { int32_t nbElememt = Evb.Size(); int32_t idx = m_size; Resize(m_size+nbElememt); memcpy(&m_data[idx], &Evb.m_data[0], nbElememt*sizeof(MY_TYPE) ); // Return the curent pointer return *this; } /** * @brief Set increment mode of this vector (default it match corectly with the number of element inside) * @param[in] newIncrementNumber methode requested */ void SetIncrement(int32_t newIncrementNumber) { m_increment = newIncrementNumber; } /** * @brief Get the number of element in the vector * @return The number requested */ int32_t Size() const { return m_size; } /** * @brief Get the Allocated size in the vector * @return The size of allocation */ int32_t AllocatedSize() const { return m_allocated; } /** * @brief Get a current element in the vector * @param[in] pos Desired position read * @return Reference on the Element */ MY_TYPE& Get(int32_t pos) { return m_data[pos]; } /** * @brief Get an copy Element an a special position * @param[in] pos Position in the vector that might be get [0..Size()] * @return An reference on the copy of selected element */ MY_TYPE& operator[] (int32_t pos) { return Get(pos); } /** * @brief Get an Element an a special position * @param[in] pos Position in the vector that might be get [0..Size()] * @return An reference on the selected element */ const MY_TYPE& operator[] (int32_t pos) const { return m_data[pos]; } /** * @brief Add at the Last position of the Vector * @param[in] item Element to add at the end of vector */ void PushBack(const MY_TYPE& item) { int32_t idx = m_size; Resize(m_size+1); m_data[idx] = item; } /** * @brief Add at the Last position of the Vector * @param[in] item Element to add at the end of vector */ void PushBack(const MY_TYPE * item, int32_t nbElement) { if (NULL == item) { return; } int32_t idx = m_size; Resize(m_size+nbElement); memcpy(&m_data[idx], item, nbElement*sizeof(MY_TYPE) ); } /** * @brief Remove the last element of the vector */ void PopBack(void) { if(m_size>0) { Resize(m_size-1); } } /** * @brief Remove all alement in the current vector */ void Clear(void) { if(m_size>0) { Resize(0); } } /** * @brief * * @param[in,out] --- * * @return --- * */ void Insert(int32_t pos, const MY_TYPE& item) { if (pos>m_size) { EDN_ERROR(" can not insert Element at this position : " << pos << " > " << m_size<< " add it at the end ... "); PushBack(item); return; } int32_t tmpSize = m_size; // Request resize of the current buffer Resize(m_size+1); // move curent data memmove((m_data + pos + 1), (m_data + pos), (tmpSize - pos)*sizeof(MY_TYPE) ); // affectation of the current element m_data[pos] = item; } /** * @brief * * @param[in,out] --- * * @return --- * */ void Insert(int32_t pos, const MY_TYPE * item, int32_t nbElement) { if (pos>m_size) { EDN_WARNING(" can not insert Element at this position : " << pos << " > " << m_size << " add it at the end ... "); PushBack(item, nbElement); return; } int32_t tmpSize = m_size; // Request resize of the current buffer Resize(m_size+nbElement); // move curent data (after the position) memmove((m_data + pos + nbElement), (m_data + pos), (tmpSize - pos)*sizeof(MY_TYPE) ); // affectation of all input element memcpy(&m_data[pos], item, nbElement*sizeof(MY_TYPE) ); } /** * @brief Remove one element * * @param[in] pos Position to remove the data * * @return --- * */ void Erase(int32_t pos) { if (pos>m_size) { EDN_ERROR(" can not Erase Element at this position : " << pos << " > " << m_size); return; } int32_t tmpSize = m_size; // move curent data memmove((m_data + pos), (m_data + pos + 1), (tmpSize - (pos+1))*sizeof(MY_TYPE) ); // Request resize of the current buffer Resize(m_size-1); } /** * @brief Remove one element * * @param[in] pos Position to remove the data * @param[in] nbElement number of element to remove * * @return --- * */ void Erase(int32_t pos, int32_t nbElement) { if (pos>m_size) { EDN_ERROR(" can not Erase Element at this position : " << pos << " > " << m_size); return; } if (pos+nbElement>m_size) { nbElement = m_size - pos; } int32_t tmpSize = m_size; // move curent data memmove((m_data + pos), (m_data + pos + nbElement), (tmpSize - (pos+nbElement))*sizeof(MY_TYPE) ); // Request resize of the current buffer Resize(m_size-nbElement); } /** * @brief extract data between two point : * @param[in] posStart start position to extract data * @param[in] posEnd End position to extract data * @return the extracted vector */ EdnVectorBin Extract(int32_t posStart = 0, int32_t posEnd=0x7FFFFFFF) { EdnVectorBin out; if (posStart < 0) { posStart = 0; } else if (posStart >= Size() ) { return out; } if (posEnd < 0) { return out; } else if (posEnd >= Size() ) { posEnd = Size(); } out.PushBack(&m_data[posStart], posEnd-posStart); return out; } /** * @brief Set the minimum allocation in memory for the curent vector ==> reallocate the * buffer to fit exactly the mumber of element needed */ void Fit(void) { if (m_size > m_allocated) { // Reallocate the curent data to the correct size ... EDN_REALLOC(m_data, m_size, MY_TYPE); } // Check result with assert : EDN_ASSERT(NULL!=m_data, "Error in data Fitting"); m_allocated = m_size; } /** * @brief Get an iterator an an specific position * @param[in] pos Requested position of the iterator in the vector * @return The Iterator */ Iterator Position(int32_t pos) { return Iterator(this, pos); } /** * @brief Get an Iterator on the start position of the Vector * @return The Iterator */ Iterator Begin(void) { return Position(0); } /** * @brief Get an Iterator on the end position of the Vector * @return The Iterator */ Iterator End(void) { return Position( Size()-1 ); } private: /** * @brief Change the current size of the vector * @param[in] newSize New requested size of element in the vector */ void Resize(int32_t newSize) { // Reallocate memory if (newSize > m_allocated) { ChangeAllocation(newSize); } m_size = newSize; } /** * @brief Change the current allocation to the corect one (depend on the current size) * @param[in] newSize Minimum number of element needed */ void ChangeAllocation(int32_t newSize) { // set the minimal size to 1 if(newSize <= 0) { newSize = 1; } int32_t requestSize = m_allocated; // set the size with the corect chose type : if (newSize == m_allocated) { return; } else if (newSize < requestSize) { // down the size of the vector: if (0==m_increment) { // never down size... } else { int32_t devide = m_increment; if (devide == 0) { devide = 1; } int32_t numberOfStep = m_allocated / devide; if (newSize< ((numberOfStep-2)*devide + devide/2) ) { //Allow Reallocation of a new size shoerter requestSize = ((newSize / devide)+1) * devide; } } } else { while(newSize > requestSize) { if (0 == requestSize) { requestSize = 1; } else if (0==m_increment) { requestSize = requestSize * 2; } else { requestSize = (requestSize + m_increment); } } } // No reallocation needed : if (requestSize == m_allocated) { return; } // check if something is allocated : if (NULL == m_data) { // no data allocated ==> request an allocation (might be the first) EDN_MALLOC(m_data, requestSize, MY_TYPE); } else { // move datas EDN_REALLOC(m_data, requestSize, MY_TYPE); } // Check result with assert : EDN_ASSERT(NULL!=m_data, "Error in data allocation"); // set the new allocation size m_allocated = requestSize; } }; #undef __class__ #define __class__ NULL #endif