//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// 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. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Dr. Frank Celler //////////////////////////////////////////////////////////////////////////////// #include "vector.h" #include //////////////////////////////////////////////////////////////////////////////// /// @brief grow rate //////////////////////////////////////////////////////////////////////////////// #define GROW_FACTOR (1.2) //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a vector //////////////////////////////////////////////////////////////////////////////// void TRI_InitVector(TRI_vector_t* vector, size_t elementSize) { vector->_buffer = nullptr; vector->_lengthX = 0; vector->_capacityX = 0; vector->_elementSizeX = static_cast(elementSize); } //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a vector, with user-definable settings //////////////////////////////////////////////////////////////////////////////// int TRI_InitVector2(TRI_vector_t* vector, size_t elementSize, size_t initialCapacity) { // init vector as usual TRI_InitVector(vector, elementSize); if (initialCapacity != 0) { vector->_buffer = static_cast(TRI_Allocate( (initialCapacity * static_cast(vector->_elementSizeX)))); if (vector->_buffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } } vector->_capacityX = static_cast(initialCapacity); return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector, but does not free the pointer //////////////////////////////////////////////////////////////////////////////// void TRI_DestroyVector(TRI_vector_t* vector) { if (vector->_buffer != nullptr) { TRI_Free(vector->_buffer); } } //////////////////////////////////////////////////////////////////////////////// /// @brief ensures a vector has space for extraCapacity more items //////////////////////////////////////////////////////////////////////////////// int TRI_ReserveVector(TRI_vector_t* vector, size_t extraCapacity) { size_t oldLength = static_cast(vector->_lengthX); size_t minLength = oldLength + extraCapacity; if (static_cast(vector->_capacityX) >= minLength) { return TRI_ERROR_NO_ERROR; } size_t newSize = static_cast(vector->_capacityX); while (newSize < minLength) { newSize = (size_t)(1 + GROW_FACTOR * newSize); } auto newBuffer = static_cast( TRI_Reallocate(vector->_buffer, newSize * static_cast(vector->_elementSizeX))); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_buffer = newBuffer; vector->_capacityX = static_cast(newSize); return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief adjusts the length of the vector //////////////////////////////////////////////////////////////////////////////// void TRI_SetLengthVector(TRI_vector_t* vector, size_t n) { vector->_lengthX = static_cast(n); } //////////////////////////////////////////////////////////////////////////////// /// @brief resizes the vector //////////////////////////////////////////////////////////////////////////////// int TRI_ResizeVector(TRI_vector_t* vector, size_t n) { if (static_cast(vector->_lengthX) == n) { return TRI_ERROR_NO_ERROR; } if (static_cast(vector->_capacityX) < n) { size_t newSize = n; auto newBuffer = static_cast( TRI_Reallocate(vector->_buffer, newSize * static_cast(vector->_elementSizeX))); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_capacityX = static_cast(n); vector->_buffer = newBuffer; } vector->_lengthX = static_cast(n); return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an element at the end //////////////////////////////////////////////////////////////////////////////// int TRI_PushBackVector(TRI_vector_t* vector, void const* element) { size_t const elementSize = static_cast(vector->_elementSizeX); if (vector->_lengthX == vector->_capacityX) { size_t newSize = (size_t)(1 + (GROW_FACTOR * static_cast(vector->_capacityX))); auto newBuffer = static_cast(TRI_Reallocate(vector->_buffer, newSize * elementSize)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_capacityX = static_cast(newSize); vector->_buffer = newBuffer; } memcpy(vector->_buffer + static_cast(vector->_lengthX) * elementSize, element, elementSize); vector->_lengthX++; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief removes an element //////////////////////////////////////////////////////////////////////////////// void TRI_RemoveVector(TRI_vector_t* vector, size_t n) { if (n < static_cast(vector->_lengthX)) { if (n + 1 < static_cast(vector->_lengthX)) { size_t const elementSize = static_cast(vector->_elementSizeX); memmove(vector->_buffer + n * elementSize, vector->_buffer + (n + 1) * elementSize, (static_cast(vector->_lengthX) - n - 1) * elementSize); } --vector->_lengthX; } } //////////////////////////////////////////////////////////////////////////////// /// @brief returns an element to the vector after borrowing it via /// TRI_NextVector. This will also decrease the vector length by one. /// The caller must ensure that the element has been fetched from the vector /// before. //////////////////////////////////////////////////////////////////////////////// void TRI_ReturnVector(TRI_vector_t* vector) { TRI_ASSERT(vector->_lengthX > 0); vector->_lengthX--; } //////////////////////////////////////////////////////////////////////////////// /// @brief increases vector length by one and returns the address of the /// uninitialized element at the new position //////////////////////////////////////////////////////////////////////////////// void* TRI_NextVector(TRI_vector_t* vector) { // ensure the vector has enough capacity for another element int res = TRI_ReserveVector(vector, 1); if (res != TRI_ERROR_NO_ERROR) { // out of memory return nullptr; } ++vector->_lengthX; TRI_ASSERT(vector->_lengthX <= vector->_capacityX); TRI_ASSERT(vector->_buffer != nullptr); return TRI_AtVector(vector, static_cast(vector->_lengthX - 1)); } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the element at a given position //////////////////////////////////////////////////////////////////////////////// void* TRI_AtVector(TRI_vector_t const* vector, size_t pos) { if (vector->_buffer == nullptr || pos >= static_cast(vector->_lengthX)) { return nullptr; } return static_cast(vector->_buffer + pos * static_cast(vector->_elementSizeX)); } //////////////////////////////////////////////////////////////////////////////// /// @brief inserts an element at a given position //////////////////////////////////////////////////////////////////////////////// int TRI_InsertVector(TRI_vector_t* vector, void const* element, size_t n) { size_t const elementSize = static_cast(vector->_elementSizeX); // ........................................................................... // Check and see if we need to extend the vector // ........................................................................... if (vector->_lengthX >= vector->_capacityX || n >= static_cast(vector->_capacityX)) { size_t newSize = (size_t)(1 + (GROW_FACTOR * static_cast(vector->_capacityX))); if (n >= newSize) { newSize = n + 1; } TRI_ASSERT(newSize > n); auto newBuffer = static_cast(TRI_Allocate(newSize * elementSize)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_capacityX = static_cast(newSize); if (vector->_buffer != nullptr) { memcpy(newBuffer, vector->_buffer, static_cast(vector->_lengthX) * elementSize); TRI_Free(vector->_buffer); } vector->_buffer = newBuffer; } if (n < static_cast(vector->_lengthX)) { memmove(vector->_buffer + (elementSize * (n + 1)), vector->_buffer + (elementSize * n), elementSize * (static_cast(vector->_lengthX) - n)); ++vector->_lengthX; } else { vector->_lengthX = static_cast(n + 1); } memcpy(vector->_buffer + (elementSize * n), element, elementSize); return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief sets an element at a given position //////////////////////////////////////////////////////////////////////////////// void TRI_SetVector(TRI_vector_t* vector, size_t pos, void const* element) { if (pos < static_cast(vector->_lengthX)) { size_t const elementSize = static_cast(vector->_elementSizeX); memcpy((void*)(vector->_buffer + pos * elementSize), element, elementSize); } } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the beginning //////////////////////////////////////////////////////////////////////////////// void* TRI_BeginVector(TRI_vector_t const* vector) { return vector->_buffer; }