diff --git a/etk/Map.hpp b/etk/Map.hpp index ac7185c..0554d8c 100644 --- a/etk/Map.hpp +++ b/etk/Map.hpp @@ -246,9 +246,10 @@ namespace etk { * @param[in] _count Number of basic element in the table. * @param[in] _ordered select an ordered map or an onordered map. */ - Map(int32_t _count = 0, bool _ordered=true) : - m_data(_count), + Map(size_t _count = 0, bool _ordered=true) : + m_data(), m_ordered(_ordered) { + m_data.reserve(_count); // nothing to do } /** @@ -256,7 +257,7 @@ namespace etk { * @param[in] _obj Other Map to move */ Map(Map&& _obj): - m_data(0), + m_data(), m_ordered(true) { _obj.swap(*this); } diff --git a/etk/Set.hpp b/etk/Set.hpp index 19298c1..7cf570b 100644 --- a/etk/Set.hpp +++ b/etk/Set.hpp @@ -242,8 +242,9 @@ namespace etk { * @param[in] _count Number of basic element (pre-allocated) in the table. */ Set(int32_t _count = 0) : - m_data(_count), + m_data(), m_comparator([](const ETK_SET_TYPE& _key1, const ETK_SET_TYPE& _key2) { return _key1 < _key2; }) { + m_data.reserve(_count); // nothing to do } @@ -253,7 +254,7 @@ namespace etk { */ template Set(const ETK_SET_TYPE_2& ... _args): - m_data(0), + m_data(), m_comparator([](const ETK_SET_TYPE& _key1, const ETK_SET_TYPE& _key2) { return _key1 < _key2; }) { add(_args...); } diff --git a/etk/Vector.hpp b/etk/Vector.hpp index 63b1174..363bbdd 100644 --- a/etk/Vector.hpp +++ b/etk/Vector.hpp @@ -8,6 +8,23 @@ #include //#include #include +// better mode of vector ==> increate the code complexity +#define ETK_ENABLE_PLACEMENT_NEW 1 + +//#define ETK_VECTOR_DEBUG(...) printf(__VA_ARGS__) +#define ETK_VECTOR_DEBUG(...) do {} while (false) + +// it is define bu generic "include " ==> no double define of placement new +#ifndef _NEW + // Default placement versions of operator new. + inline void* operator new(size_t, char* _p) throw() { + ETK_VECTOR_DEBUG("plop\n"); + return _p; + } + inline void operator delete (void*, char*) throw() { + + } +#endif namespace etk { class Stream; @@ -216,17 +233,32 @@ namespace etk { size_t m_size; //!< Number of element in the buffer size_t m_allocated; //!< Current allocated size public: + /** + * @brief Create an empty vector + */ + Vector(): + m_data(nullptr), + m_size(0), + m_allocated(0) { + + } + #if 0 /** * @brief Create an empty vector * @param[in] _count Minimum request size of the Buffer */ - Vector(int32_t _count = 0): + Vector(size_t _count): m_data(nullptr), m_size(0), m_allocated(0) { changeAllocation(_count); + // instanciate all objects + for (size_t iii=0; iii<_count; ++iii) { + new ((char*)&m_data[iii]) ETK_VECTOR_TYPE(); + } m_size = _count; } + #endif /** * @brief List initializer (ex: etk::Vector plop = {"hello", world"} * @param[in] _element element to add in the vector @@ -243,21 +275,42 @@ namespace etk { * @brief Re-copy constructor (copy all needed data) * @param[in] _obj Vector that might be copy */ - Vector(const etk::Vector& _obj): - m_data(nullptr), - m_size(_obj.m_size), - m_allocated(_obj.m_allocated) { - // allocate all same data - m_data = new ETK_VECTOR_TYPE[m_allocated]; - if (m_data == nullptr) { - return; + #ifndef ETK_ENABLE_PLACEMENT_NEW + Vector(const etk::Vector& _obj): + m_data(nullptr), + m_size(_obj.m_size), + m_allocated(_obj.m_allocated) { + // allocate all same data + m_data = new ETK_VECTOR_TYPE[m_allocated]; + if (m_data == nullptr) { + return; + } + // Copy all data ... + for(size_t iii=0; iii& _obj): + m_data(nullptr), + m_size(0), + m_allocated(0) { + reserve(_obj.m_size); + for(size_t iii=0; iii<_obj.m_size; iii++) { + #if 0 + pushBack(_obj.m_data[iii]); + #else + new ((char*)&m_data[iii]) ETK_VECTOR_TYPE(etk::move(_obj.m_data[iii])); + #endif + } + m_size = _obj.m_size; } - } + #endif + /** + * @brief Move operator of elements + * @param[in] _obj Object to move + */ Vector(etk::Vector&& _obj): m_data(_obj.m_data), m_size(_obj.m_size), @@ -267,11 +320,25 @@ namespace etk { _obj.m_allocated = 0; } /** - * @brief Destructor of the current Class + * @brief Destructor of the current class */ ~Vector() { if (m_data != nullptr) { - delete[] m_data; + #ifndef ETK_ENABLE_PLACEMENT_NEW + delete[] m_data; + #else + for(size_t iii=0; iii & _obj) { - if (this != &_obj) { - if (m_data != nullptr) { - delete[] m_data; - m_data = nullptr; - } - // Set the new value - m_allocated = _obj.m_allocated; - m_size = _obj.m_size; - // allocate all same data - m_data = new ETK_VECTOR_TYPE[m_allocated]; - if (m_data == nullptr) { - return *this; - } - for(size_t iii=0; iii&& _obj) { + if(this != &_obj) { + etk::swap(m_data, _obj.m_data); + etk::swap(m_allocated, _obj.m_allocated); + etk::swap(m_size, _obj.m_size); } // Return the current pointer return *this; } + /** + * @brief Re-copy operator + * @param[in] _obj Vector that might be copy + * @return reference on the current re-copy vector + */ + #ifndef ETK_ENABLE_PLACEMENT_NEW + Vector& operator=(const etk::Vector& _obj) { + if (this != &_obj) { + if (m_data != nullptr) { + delete[] m_data; + m_data = nullptr; + } + // Set the new value + m_allocated = _obj.m_allocated; + m_size = _obj.m_size; + // allocate all same data + m_data = new ETK_VECTOR_TYPE[m_allocated]; + if (m_data == nullptr) { + return *this; + } + for(size_t iii=0; iii& _obj) { + // remove all previous elements + clear(); + // Force a specicfic size + reserve(_obj.m_size); + for(size_t iii=0; iii<_obj.m_size; iii++) { + #if 0 + pushBack(_obj.m_data[iii]); + #else + new ((char*)&m_data[iii]) ETK_VECTOR_TYPE(etk::move(_obj.m_data[iii])); + #endif + } + m_size = _obj.m_size; + // Return the current pointer + return *this; + } + #endif /** * @brief Add at the Last position of the Vector * @param[in] _obj Element to add at the end of vector */ Vector& operator+= (const etk::Vector& _obj) { - size_t numberElement = _obj.size(); - size_t idElement = m_size; - resize(m_size+numberElement); - if (m_size<=idElement) { - //TK_CRITICAL("allocation error"); - return *this; - } - for(size_t iii=0; iii idElement) { - // initialize data ... - for(size_t iii=idElement; iii<_newSize; iii++) { - m_data[iii] = _basicElement; - } - } - } /** * @brief Get the Allocated size in the vector * @return The size of allocation @@ -440,26 +531,38 @@ namespace etk { * @param[in] _item Element to add at the end of vector */ void pushBack(ETK_VECTOR_TYPE&& _item) { - size_t idElement = m_size; - resize(m_size+1); - if (idElement < m_size) { - m_data[idElement] = etk::move(_item); - } else { - //TK_ERROR("Resize does not work correctly ... not added item"); - } + #ifndef ETK_ENABLE_PLACEMENT_NEW + size_t idElement = m_size; + resize(m_size+1); + if (idElement < m_size) { + m_data[idElement] = etk::move(_item); + } else { + //TK_ERROR("Resize does not work correctly ... not added item"); + } + #else + reserve(m_size+1); + new ((char*)&m_data[m_size]) ETK_VECTOR_TYPE(etk::move(_item)); + m_size += 1; + #endif } /** * @brief Add at the Last position of the Vector * @param[in] _item Element to add at the end of vector */ void pushBack(const ETK_VECTOR_TYPE& _item) { - size_t idElement = m_size; - resize(m_size+1); - if (idElement < m_size) { - m_data[idElement] = etk::move(_item); - } else { - //TK_ERROR("Resize does not work correctly ... not added item"); - } + #ifndef ETK_ENABLE_PLACEMENT_NEW + size_t idElement = m_size; + resize(m_size+1); + if (idElement < m_size) { + m_data[idElement] = etk::move(_item); + } else { + //TK_ERROR("Resize does not work correctly ... not added item"); + } + #else + reserve(m_size+1); + new ((char*)&m_data[m_size]) ETK_VECTOR_TYPE(etk::move(_item)); + m_size += 1; + #endif } /** * @brief Add at the Last position of the Vector @@ -470,15 +573,27 @@ namespace etk { if (_item == nullptr) { return; } - size_t idElement = m_size; - resize(m_size+_nbElement); - if (idElement > m_size) { - //TK_ERROR("Resize does not work correctly ... not added item"); - return; - } - for (size_t iii=0; iii<_nbElement; iii++) { - m_data[idElement+iii] = _item[iii]; - } + #ifndef ETK_ENABLE_PLACEMENT_NEW + size_t idElement = m_size; + resize(m_size+_nbElement); + if (idElement > m_size) { + //TK_ERROR("Resize does not work correctly ... not added item"); + return; + } + for (size_t iii=0; iii<_nbElement; iii++) { + m_data[idElement+iii] = _item[iii]; + } + #else + reserve(m_size+_nbElement); + if (m_size > m_allocated) { + //TK_ERROR("Resize does not work correctly ... not added item"); + return; + } + for (size_t iii=0; iii<_nbElement; iii++) { + new ((char*)&m_data[m_size+iii]) ETK_VECTOR_TYPE(_item[iii]); + m_size += 1; + } + #endif } private: void pushBackN(const ETK_VECTOR_TYPE& _value) { @@ -503,7 +618,7 @@ namespace etk { */ void popBack() { if(m_size>0) { - resize(m_size-1); + resizeDown(m_size-1); } } /** @@ -511,7 +626,7 @@ namespace etk { */ void clear() { if(m_size>0) { - resize(0); + resizeDown(0); } } /** @@ -526,25 +641,57 @@ namespace etk { pushBack(_item, _nbElement); return; } - size_t idElement = m_size; - // Request resize of the current buffer - resize(m_size+_nbElement); - if (idElement >= m_size) { - //TK_ERROR("Resize does not work correctly ... not added item"); - return; - } - // move current data (after the position) - size_t sizeToMove = (idElement - _pos); - if (sizeToMove > 0) { - for (size_t iii=1; iii<=sizeToMove; iii++) { - // tODO: better explicite the swap... - m_data[m_size-iii] = etk::move(m_data[idElement-iii]); + #ifndef ETK_ENABLE_PLACEMENT_NEW + size_t idElement = m_size; + // Request resize of the current buffer + resize(m_size+_nbElement); + if (idElement >= m_size) { + //TK_ERROR("Resize does not work correctly ... not added item"); + return; } - } - // affectation of all input element - for (size_t iii=0; iii<_nbElement; iii++) { - m_data[_pos+iii] = etk::move(_item[iii]); - } + // move current data (after the position) + size_t sizeToMove = (idElement - _pos); + if (sizeToMove > 0) { + for (size_t iii=1; iii<=sizeToMove; iii++) { + // tODO: better explicite the swap... + #ifndef ETK_ENABLE_PLACEMENT_NEW + m_data[m_size-iii] = etk::move(m_data[idElement-iii]); + #else + etk::swap(m_data[m_size-iii], m_data[idElement-iii]); + #endif + } + } + // affectation of all input element + for (size_t iii=0; iii<_nbElement; iii++) { + m_data[_pos+iii] = etk::move(_item[iii]); + } + #else + // move current data (after the position) + size_t sizeToMove = (m_size - _pos); + // Request resize of the current buffer + reserve(m_size+_nbElement); + if (sizeToMove > 0) { + for (size_t iii=1; iii<=sizeToMove; iii++) { + // placement allocate of the element + new ((char*)&m_data[m_size+_nbElement-iii]) ETK_VECTOR_TYPE(etk::move(m_data[m_size-iii])); + // Remove previous element ==> simplify code. + m_data[m_size-iii].~ETK_VECTOR_TYPE(); + #ifdef DEBUG + // we place bad data to permit to detect stipid thing that is done in C++ code when developement is in progress. + // Only in debug this is really slow ... and for the real allocation of memory + for (size_t kkk=(m_size-iii)*sizeof(ETK_VECTOR_TYPE); kkkm_size) { + ETK_VECTOR_DEBUG("Erase len %zu %zu\n", _pos, _nbElement); + if (_pos > m_size) { //TK_ERROR(" can not Erase Len Element at this position : " << _pos << " > " << m_size); return; } - if (_pos+_nbElement>m_size) { + if (_pos + _nbElement > m_size) { _nbElement = m_size - _pos; } + ETK_VECTOR_DEBUG("Erase len %zu %zu\n", _pos, _nbElement); size_t idElement = m_size; // move current data size_t sizeToMove = (idElement - (_pos+_nbElement)); if ( 0 < sizeToMove) { for (size_t iii=0; iiim_size) { + if (_pos > m_size) { //TK_ERROR(" can not Erase Element at this position : " << _pos << " > " << m_size); return; } - if (_posEnd>m_size) { + if (_posEnd > m_size) { _posEnd = m_size; } size_t nbElement = m_size - _pos; size_t tmpSize = m_size; - // move current data + // move current data (to the end) ==> auto removed by the resize() size_t sizeToMove = (tmpSize - (_pos+nbElement)); if ( 0 < sizeToMove) { for (size_t iii=0; iii idElement) { + // initialize data ... + for(size_t iii=idElement; iii<_newSize; iii++) { + m_data[iii] = _basicElement; + } + } + #else + // Reallocate memory + if (_newSize > m_size) { + if (_newSize > m_allocated) { + changeAllocation(_newSize); + } + for (size_t iii=m_size; iii<_newSize; ++iii) { + new ((char*)&m_data[iii]) ETK_VECTOR_TYPE(_basicElement); + } + m_size = _newSize; + return; + } else if (_newSize == m_size) { + return; + } + for (size_t iii=m_size; iii<_newSize; ++iii) { + m_data[iii].~ETK_VECTOR_TYPE(); + #ifdef DEBUG + // we place bad data to permit to detect stipid thing that is done in C++ code when developement is in progress. + // Only in debug this is really slow ... and for the real allocation of memory + for (size_t kkk=iii*sizeof(ETK_VECTOR_TYPE); kkk %zu\n", m_size, _newSize); + #ifndef ETK_ENABLE_PLACEMENT_NEW + // Reallocate memory + if (_newSize > m_allocated) { + changeAllocation(_newSize); + } else if (_newSize == m_allocated) { + return; + } + for + m_size = _newSize; + #else + // Reallocate memory + if (_newSize > m_size) { + if (_newSize > m_allocated) { + changeAllocation(_newSize); + } + for (size_t iii=m_size; iii<_newSize; ++iii) { + new ((char*)&m_data[iii]) ETK_VECTOR_TYPE(); + } + } else if (_newSize == m_size) { + return; + } + ETK_VECTOR_DEBUG("Reduce %zu => %zu\n", m_size, _newSize); + for (size_t iii=_newSize; iii %zu\n", m_size, _newSize); // Reallocate memory if (_newSize > m_allocated) { - changeAllocation(_newSize); + ETK_VECTOR_DEBUG("Resize Down %zu => %zu\n", m_size, _newSize); + return; + } else if (_newSize == m_allocated) { + return; + } + ETK_VECTOR_DEBUG("Reduce %zu => %zu\n", m_size, _newSize); + for (size_t iii=_newSize; iii request an allocation (might be the first) - m_data = new ETK_VECTOR_TYPE[requestSize]; + #ifndef ETK_ENABLE_PLACEMENT_NEW + m_data = new ETK_VECTOR_TYPE[requestSize]; + #else + m_data = (ETK_VECTOR_TYPE*)(new char[sizeof(ETK_VECTOR_TYPE)*requestSize]); + #endif if (m_data == nullptr) { //TK_CRITICAL("Vector : Error in data allocation request allocation:" << requestSize << "*" << (int32_t)(sizeof(ETK_VECTOR_TYPE)) << "bytes" ); m_allocated = 0; return; } + #ifdef DEBUG + // we place bad data to permit to detect stipid thing that is done in C++ code when developement is in progress. + // Only in debug this is really slow ... and for the real allocation of memory + for (size_t kkk=0; kkk test(3); + etk::Vector test(3.9f, 33.0f,55.8f); + EXPECT_EQ(test.size(), 3); + EXPECT_EQ(test[0], 3.9f); + EXPECT_EQ(test[1], 33.0f); + EXPECT_EQ(test[2], 55.8f); +} + +TEST(TestVector, resize) { + // Test contructor value + etk::Vector test; + test.resize(3); EXPECT_EQ(test.size(), 3); } TEST(TestVector, empty) { @@ -182,3 +192,83 @@ TEST(TestVector, initializationList_2) { EXPECT_EQ(test[3], 8); } + + +static uint32_t isDestroy = 0; + +class testContructDestruct { + private: + uint32_t m_addValue; + public: + testContructDestruct(uint32_t _addValue): + m_addValue(_addValue) { + isDestroy += m_addValue; + TEST_DEBUG("Create class " << m_addValue); + } + testContructDestruct(testContructDestruct&& _obj): + m_addValue(_obj.m_addValue) { + _obj.m_addValue = 0; + TEST_DEBUG("move contruction " << m_addValue); + } + virtual ~testContructDestruct() { + if (m_addValue == 0) { + TEST_DEBUG("Remove class (after move)"); + return; + } + TEST_DEBUG("Remove Class " << m_addValue); + isDestroy -= m_addValue; + } + testContructDestruct& operator= (testContructDestruct&& _obj) { + TEST_DEBUG("move operator " << m_addValue); + if (this != &_obj) { + etk::swap(m_addValue, _obj.m_addValue); + } + return *this; + } +}; + +TEST(TestVector, destroyElementAtTheCorectMoment) { + isDestroy = 0; + { + etk::Vector list; + list.pushBack(testContructDestruct(55)); + EXPECT_EQ(list.size(), 1); + EXPECT_EQ(isDestroy, 55); + auto it = list.erase(list.begin()); + EXPECT_EQ(isDestroy, 0); + EXPECT_EQ(list.size(), 0); + EXPECT_EQ(it, list.end()); + } + EXPECT_EQ(isDestroy, 0); +} + +TEST(TestVector, destroyElementAtTheCorectMoment_2) { + isDestroy = 0; + { + etk::Vector list; + list.pushBack(testContructDestruct(4)); + list.pushBack(testContructDestruct(30)); + list.pushBack(testContructDestruct(1000)); + list.pushBack(testContructDestruct(200)); + EXPECT_EQ(list.size(), 4); + EXPECT_EQ(isDestroy, 1234); + auto it = list.erase(list.begin()); + EXPECT_EQ(list.size(), 3); + EXPECT_EQ(isDestroy, 1230); + it = list.erase(list.begin()+1); + EXPECT_EQ(isDestroy, 230); + EXPECT_EQ(list.size(), 2); + } + EXPECT_EQ(isDestroy, 0); +} + +TEST(TestVector, allocateElementAtTheCorectMoment) { + isDestroy = 0; + { + etk::Vector list; + list.reserve(10); + EXPECT_EQ(list.size(), 0); + EXPECT_EQ(isDestroy, 0); + } + EXPECT_EQ(isDestroy, 0); +}