//////////////////////////////////////////////////////////////////////////////// /// @brief vector implementation /// /// @file /// /// DISCLAIMER /// /// Copyright 2014 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 /// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany /// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "vector.h" #include "Basics/tri-strings.h" // ----------------------------------------------------------------------------- // --SECTION-- private constants // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief grow rate //////////////////////////////////////////////////////////////////////////////// #define GROW_FACTOR (1.2) // ----------------------------------------------------------------------------- // --SECTION-- POD VECTORS // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a vector //////////////////////////////////////////////////////////////////////////////// void TRI_InitVector (TRI_vector_t* vector, TRI_memory_zone_t* zone, size_t elementSize) { vector->_buffer = nullptr; vector->_memoryZoneX = TRI_MemoryZoneId(zone); 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, TRI_memory_zone_t* zone, size_t elementSize, size_t initialCapacity) { // init vector as usual TRI_InitVector(vector, zone, elementSize); if (initialCapacity != 0) { vector->_buffer = static_cast(TRI_Allocate(TRI_MemoryZone(vector->_memoryZoneX), (initialCapacity * static_cast(vector->_elementSizeX)), false)); 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(TRI_MemoryZone(vector->_memoryZoneX), vector->_buffer); } } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector and frees the pointer //////////////////////////////////////////////////////////////////////////////// void TRI_FreeVector (TRI_memory_zone_t* zone, TRI_vector_t* vector) { TRI_DestroyVector(vector); TRI_Free(zone, vector); } // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @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(TRI_MemoryZone(vector->_memoryZoneX), 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 clears the vector //////////////////////////////////////////////////////////////////////////////// void TRI_ClearVector (TRI_vector_t* vector) { vector->_lengthX = 0; } //////////////////////////////////////////////////////////////////////////////// /// @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(TRI_MemoryZone(vector->_memoryZoneX), 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(TRI_MemoryZone(vector->_memoryZoneX), 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(TRI_MemoryZone(vector->_memoryZoneX), newSize * elementSize, false)); 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(TRI_MemoryZone(vector->_memoryZoneX), 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; } // ----------------------------------------------------------------------------- // --SECTION-- POINTER VECTORS // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a vector //////////////////////////////////////////////////////////////////////////////// void TRI_InitVectorPointer (TRI_vector_pointer_t* vector, TRI_memory_zone_t* zone) { vector->_memoryZone = zone; vector->_buffer = nullptr; vector->_length = 0; vector->_capacity = 0; } //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a vector, with user-definable settings //////////////////////////////////////////////////////////////////////////////// int TRI_InitVectorPointer (TRI_vector_pointer_t* vector, TRI_memory_zone_t* zone, size_t initialCapacity) { TRI_InitVectorPointer(vector, zone); if (initialCapacity != 0) { vector->_buffer = static_cast(TRI_Allocate(vector->_memoryZone, (initialCapacity * sizeof(void*)), true)); if (vector->_buffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } } vector->_capacity = initialCapacity; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector, but does not free the pointer //////////////////////////////////////////////////////////////////////////////// void TRI_DestroyVectorPointer (TRI_vector_pointer_t* vector) { if (vector->_buffer != nullptr) { TRI_Free(vector->_memoryZone, vector->_buffer); } } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector and frees the pointer //////////////////////////////////////////////////////////////////////////////// void TRI_FreeVectorPointer (TRI_memory_zone_t* zone, TRI_vector_pointer_t* vector) { TRI_DestroyVectorPointer(vector); TRI_Free(zone, vector); } // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief ensures a vector has space for extraCapacity more items //////////////////////////////////////////////////////////////////////////////// int TRI_ReserveVectorPointer (TRI_vector_pointer_t* vector, size_t extraCapacity) { size_t oldLength = vector->_length; size_t minLength = oldLength + extraCapacity; size_t newSize; void* newBuffer; if (vector->_capacity >= minLength) { return TRI_ERROR_NO_ERROR; } newSize = vector->_capacity; while (newSize < minLength) { newSize = (size_t) (1 + GROW_FACTOR * newSize); } newBuffer = TRI_Reallocate(vector->_memoryZone, vector->_buffer, newSize * sizeof(void*)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_buffer = static_cast(newBuffer); vector->_capacity = newSize; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief copies a vector //////////////////////////////////////////////////////////////////////////////// TRI_vector_pointer_t* TRI_CopyVectorPointer (TRI_memory_zone_t* zone, TRI_vector_pointer_t const* vector) { TRI_vector_pointer_t* copy = static_cast(TRI_Allocate(zone, sizeof(TRI_vector_pointer_t), false)); if (copy == nullptr) { return nullptr; } copy->_memoryZone = zone; if (vector->_capacity == 0) { copy->_buffer = nullptr; copy->_length = 0; copy->_capacity = 0; } else { copy->_buffer = static_cast(TRI_Allocate(zone, vector->_length * sizeof(void*), false)); if (copy->_buffer == nullptr) { TRI_Free(zone, copy); return nullptr; } copy->_length = vector->_length; copy->_capacity = vector->_length; memcpy(copy->_buffer, vector->_buffer, vector->_length * sizeof(void*)); } return copy; } //////////////////////////////////////////////////////////////////////////////// /// @brief adds an element at the end //////////////////////////////////////////////////////////////////////////////// int TRI_PushBackVectorPointer (TRI_vector_pointer_t* vector, void* element) { if (vector->_length == vector->_capacity) { void* newBuffer; size_t newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); newBuffer = TRI_Reallocate(vector->_memoryZone, vector->_buffer, newSize * sizeof(void*)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_buffer = static_cast(newBuffer); // prefill the new vector elements with 0's memset(&vector->_buffer[vector->_capacity], 0, (newSize - vector->_capacity) * sizeof(void*)); vector->_capacity = newSize; } vector->_buffer[vector->_length++] = element; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief inserts an element at position n, shifting the following elements //////////////////////////////////////////////////////////////////////////////// int TRI_InsertVectorPointer (TRI_vector_pointer_t* vector, void* element, size_t n) { // ........................................................................... // Check and see if we need to extend the vector // ........................................................................... if (vector->_length >= vector->_capacity || n >= vector->_capacity) { void* newBuffer; size_t newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); if (n >= newSize) { newSize = n + 1; } TRI_ASSERT(newSize > n); newBuffer = TRI_Reallocate(vector->_memoryZone, vector->_buffer, newSize * sizeof(void*)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_buffer = static_cast(newBuffer); // prefill the new vector elements with 0's memset(&vector->_buffer[vector->_capacity], 0, (newSize - vector->_capacity) * sizeof(void*)); vector->_capacity = newSize; } if (n < vector->_length) { memmove(vector->_buffer + n + 1, vector->_buffer + n, sizeof(void*) * (vector->_length - n)); } TRI_ASSERT(vector->_capacity >= vector->_length); vector->_buffer[n] = element; if (n > vector->_length) { vector->_length = n + 1; } else { ++vector->_length; } return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief removes an element, returns this element //////////////////////////////////////////////////////////////////////////////// void* TRI_RemoveVectorPointer (TRI_vector_pointer_t* vector, size_t n) { void* old; old = 0; if (n < vector->_length) { old = vector->_buffer[n]; if (n + 1 < vector->_length) { memmove(vector->_buffer + n, vector->_buffer + (n + 1), (vector->_length - n - 1) * sizeof(void*)); } --vector->_length; } return old; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the element at a given position //////////////////////////////////////////////////////////////////////////////// void* TRI_AtVectorPointer (TRI_vector_pointer_t const* vector, size_t pos) { if (vector->_buffer == nullptr || pos >= vector->_length) { return nullptr; } return vector->_buffer[pos]; } // ----------------------------------------------------------------------------- // --SECTION-- STRING VECTORS // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a string vector //////////////////////////////////////////////////////////////////////////////// void TRI_InitVectorString (TRI_vector_string_t* vector, TRI_memory_zone_t* zone) { vector->_memoryZone = zone; vector->_buffer = nullptr; vector->_length = 0; vector->_capacity = 0; } //////////////////////////////////////////////////////////////////////////////// /// @brief initializes a string vector, with user-definable settings //////////////////////////////////////////////////////////////////////////////// int TRI_InitVectorString2 (TRI_vector_string_t* vector, TRI_memory_zone_t* zone, size_t initialCapacity) { TRI_InitVectorString(vector, zone); if (initialCapacity != 0) { vector->_buffer = (char**) TRI_Allocate(vector->_memoryZone, initialCapacity * sizeof(char*), false); if (vector->_buffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } } vector->_capacity = initialCapacity; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector and all strings, but does not free the pointer //////////////////////////////////////////////////////////////////////////////// void TRI_DestroyVectorString (TRI_vector_string_t* vector) { if (vector->_buffer != nullptr) { for (size_t i = 0; i < vector->_length; ++i) { if (vector->_buffer[i] != nullptr) { TRI_Free(vector->_memoryZone, vector->_buffer[i]); } } TRI_Free(vector->_memoryZone, vector->_buffer); } } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys a vector and frees the string //////////////////////////////////////////////////////////////////////////////// void TRI_FreeVectorString (TRI_memory_zone_t* zone, TRI_vector_string_t* vector) { TRI_DestroyVectorString(vector); TRI_Free(zone, vector); } // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief adds an element at the end //////////////////////////////////////////////////////////////////////////////// int TRI_PushBackVectorString (TRI_vector_string_t* vector, char* element) { if (vector->_length == vector->_capacity) { char** newBuffer; size_t newSize = (size_t) (1 + GROW_FACTOR * vector->_capacity); newBuffer = (char**) TRI_Reallocate(vector->_memoryZone, vector->_buffer, newSize * sizeof(char*)); if (newBuffer == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } vector->_capacity = newSize; vector->_buffer = newBuffer; } vector->_buffer[vector->_length++] = element; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief removes an element, returns this element //////////////////////////////////////////////////////////////////////////////// void TRI_RemoveVectorString (TRI_vector_string_t* vector, size_t n) { if (n < vector->_length) { if (vector->_buffer[n] != nullptr) { TRI_Free(vector->_memoryZone, vector->_buffer[n]); } if (n + 1 < vector->_length) { memmove(vector->_buffer + n, vector->_buffer + (n + 1), (vector->_length - n - 1) * sizeof(void*)); } --vector->_length; } } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the element at a given position //////////////////////////////////////////////////////////////////////////////// char* TRI_AtVectorString (TRI_vector_string_t const* vector, size_t pos) { if (vector->_buffer == nullptr || pos >= vector->_length) { return nullptr; } return (char*) vector->_buffer[pos]; } // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- // Local Variables: // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" // End: