From ac5e80f4802acde7c1883b75743643f7ee0d957f Mon Sep 17 00:00:00 2001 From: Paolo Fabio Zaino Date: Thu, 2 Sep 2021 21:10:05 +0100 Subject: [PATCH 1/3] Early commit of the new design for RC3, this new code design allows ZVector to be very fast also in the worst case scenario (when every single record is added from the front of a vector) --- src/zvector.c | 667 +++++++++++++++++++++++++++++---------------- tests/02ITest002.c | 3 +- tests/04PTest002.c | 4 +- 3 files changed, 429 insertions(+), 245 deletions(-) diff --git a/src/zvector.c b/src/zvector.c index 07ecb42..cb770bc 100644 --- a/src/zvector.c +++ b/src/zvector.c @@ -85,14 +85,17 @@ enum { // Define the vector data structure: struct _vector { - zvect_index prev_size; // - Used when clearing a vector. - zvect_index size; // - Current Array size. size - 1 gives - // us the pointer to the last element - // in the vector. - zvect_index fep; // - First vector's Element Pointer zvect_index init_capacity; // - Initial Capacity (this is set at // creation time). - zvect_index capacity; // - Max capacity allocated. + zvect_index cap_left; // - Max capacity allocated on the left. + zvect_index cap_right; // - Max capacity allocated on the right. + zvect_index begin; // - First vector's Element Pointer + zvect_index prev_end; // - Used when clearing a vector. + zvect_index end; // - Current Array size. size - 1 gives + // us the pointer to the last element + // in the vector. + int64_t alloc_dir; // - This variable tracks where we have allocated + // memory for this vector ( < 0 = left, 0 = no allocations yet, > 0 right) size_t data_size; // - User DataType size. uint32_t flags; // - If this flag set is used to // represent ALL Vector's properties. @@ -155,6 +158,14 @@ static inline void vect_check(vector x) { throw_error("Vector not defined!"); } +static inline zvect_index _vect_capacity(vector v) { + return v->cap_left + v->cap_right; +} + +static inline zvect_index _vect_size(vector v) { + return ( v->end - v->begin ); +} + static inline void item_safewipe(vector v, const void *item) { if (item != NULL) { if (!(v->status & ZVS_CUST_WIPE_ON)) { @@ -166,17 +177,17 @@ static inline void item_safewipe(vector v, const void *item) { } static void _free_items(vector v, zvect_index first, zvect_index offset) { - if (v->size == 0) + if (_vect_size(v) == 0) return; register zvect_index j; for (j = (first + offset); j >= first; j--) { - if (v->data[j] != NULL) { + if (v->data[v->begin + j] != NULL) { if (v->flags & ZV_SEC_WIPE) - item_safewipe(v, v->data[j]); + item_safewipe(v, v->data[v->begin + j]); if (!(v->flags & ZV_BYREF)) { - free(v->data[j]); - v->data[j] = NULL; + free(v->data[v->begin + j]); + v->data[v->begin + j] = NULL; } } if (j == first) @@ -327,51 +338,110 @@ void init_zvect(void) { } /*---------------------------------------------------------------------------*/ -// Vector Capacity management functions: +// Vector Size and Capacity management functions: // This function double the CAPACITY of a vector. -static void vect_increase_capacity(vector v) { - // Check if the vector exists: - vect_check(v); +static void _vect_increase_capacity(vector v, zvect_index direction) { + zvect_index new_capacity = 0; - // Get actual capacity and double it - if ((v->capacity == 0) || (v->capacity < v->init_capacity)) - v->capacity = v->init_capacity; + void **new_data = NULL; + zvect_index nb = 0, ne = 0; + if (!direction) + { + // Increase capacity on the left side of the vector: - zvect_index new_capacity = v->capacity * 2; - void **new_data = (void **)realloc(v->data, sizeof(void *) * new_capacity); - if (new_data == NULL) - throw_error("Not enough memory to extend the vector capacity!"); + // Get actual left capacity and double it + //if ( v->cap_left == 0 ) + // v->cap_left = v->init_capacity / 2; + + new_capacity = v->cap_left * 2; + + new_data = (void **)malloc(sizeof(void *) * (new_capacity + v->cap_right)); + if (new_data == NULL) + throw_error("Not enough memory to extend the vector capacity!"); + + nb = v->cap_left; + ne = ( nb + (v->end - v->begin) ); + vect_memcpy(new_data + nb, v->data + v->begin, sizeof(void *) * (v->end - v->begin) ); + } else { + // Increase capacity on the right side of the vector: + + // Get actual left capacity and double it + //if ( v->cap_right == 0 ) + // v->cap_right = v->init_capacity / 2; + + new_capacity = v->cap_right * 2; + + new_data = (void **)realloc(v->data, sizeof(void *) * (v->cap_left + new_capacity)); + if (new_data == NULL) + throw_error("Not enough memory to extend the vector capacity!"); + } // Apply changes and release memory + if (!direction) + free(v->data); v->data = new_data; - v->capacity = new_capacity; + if (direction == 0) + { + v->cap_left = new_capacity; + v->end = ne; + v->begin = nb; + } else { + v->cap_right = new_capacity; + } } // This function halves the CAPACITY of a vector. -static void vect_decrease_capacity(vector v) { - // Check if the vector exists: - vect_check(v); - +static void _vect_decrease_capacity(vector v, zvect_index direction) { // Check if new capacity is smaller than initial capacity - if (v->capacity <= v->init_capacity) + if ( _vect_capacity(v) <= v->init_capacity) return; - // Get actual Capacity and halve it - zvect_index new_capacity = v->capacity / 2; - if (new_capacity < v->init_capacity) - new_capacity = v->init_capacity; - new_capacity = max(v->size, new_capacity); - zvect_index new_size = min(v->size, new_capacity); + zvect_index new_capacity = 0; - void **new_data = (void **)realloc(v->data, sizeof(void *) * new_capacity); - if (new_data == NULL) - throw_error("Not enough memory to resize the vector!"); + void **new_data = NULL; + zvect_index nb = 0, ne = 0; + if (!direction) + { + // Decreasing on the left: + new_capacity = v->cap_left / 2; + if (new_capacity < ( v->init_capacity / 2 )) + new_capacity = v->init_capacity / 2; + + new_capacity = max( (_vect_size(v) / 2), new_capacity); + + new_data = (void **)malloc(sizeof(void *) * (new_capacity + v->cap_right)); + if (new_data == NULL) + throw_error("Not enough memory to resize the vector!"); + + nb = ( new_capacity / 2 ); + ne = ( nb + (v->end - v->begin) ); + vect_memcpy(new_data + nb, v->data + v->begin, sizeof(void *) * (v->end - v->begin) ); + } else { + // Decreasing on the right: + new_capacity = v->cap_right / 2; + if (new_capacity < ( v->init_capacity / 2 )) + new_capacity = v->init_capacity / 2; + + new_capacity = max( (_vect_size(v) / 2), new_capacity); + + new_data = (void **)realloc(v->data, sizeof(void *) * (v->cap_left + new_capacity)); + if (new_data == NULL) + throw_error("Not enough memory available to resize the vector!"); + } // Apply changes and release memory: + if (!direction) + free(v->data); v->data = new_data; - v->capacity = new_capacity; - v->size = new_size; + if (direction == 0) + { + v->cap_left = new_capacity; + v->end = ne; + v->begin = nb; + } else { + v->cap_right = new_capacity; + } } // Thi sfunction shrinks the CAPACITY of a vector @@ -381,24 +451,45 @@ void _vect_shrink(vector v) { // Check if the vector exists: vect_check(v); - if (v->capacity == v->init_capacity) + if (v->init_capacity < 2) + v->init_capacity = 2; + + if (_vect_capacity(v) == v->init_capacity) + return; + + if ( _vect_capacity(v) <= _vect_size(v)) return; // Determine the correct shrunk size: zvect_index new_capacity; - if (v->size < v->init_capacity) + if (_vect_size(v) < v->init_capacity) new_capacity = v->init_capacity; else - new_capacity = v->size + 1; + new_capacity = _vect_size(v) + 2; // shrink the vector: + /* void **new_data = (void **)realloc(v->data, sizeof(void *) * new_capacity); if (new_data == NULL) - throw_error("No memory available to shrink the vector!"); + throw_error("Not enough memory available to shrink the vector!"); + */ + + void **new_data = (void **)malloc(sizeof(void *) * new_capacity); + if (new_data == NULL) + throw_error("Not enough memory available to shrink the vector!"); + + zvect_index ne = 0, nb = 0; + nb = ( new_capacity / 2 ); + ne = ( nb + (v->end - v->begin) ); + vect_memcpy(new_data + nb, v->data + v->begin, sizeof(void *) * (v->end - v->begin) ); // Apply changes: + free(v->data); v->data = new_data; - v->capacity = new_capacity; + v->end = ne; + v->begin = nb; + v->cap_left = new_capacity / 2; + v->cap_right = new_capacity / 2; } void vect_shrink(vector v) { @@ -419,6 +510,26 @@ void vect_shrink(vector v) { ** ZVector API ** ***********************/ +/*---------------------------------------------------------------------------*/ +// Vector Structural Information report: + +bool vect_is_empty(vector v) { + // Check if the vector exists + vect_check(v); + + return _vect_size(v) == 0; +} + +zvect_index vect_size(vector v) { + // Check if the vector exists + vect_check(v); + + // return v->end; + return _vect_size(v); +} + +/*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ // Vector Creation and Destruction: @@ -435,21 +546,30 @@ vector vect_create(const size_t init_capacity, const size_t item_size, throw_error("Not enough memory to allocate the vector!"); // Initialize the vector: - v->prev_size = 0; - v->size = 0; + v->prev_end = 0; + v->end = 0; if (item_size == 0) v->data_size = ZVECT_DEFAULT_DATA_SIZE; else v->data_size = item_size; + zvect_index capacity = init_capacity; if (init_capacity == 0) - v->capacity = ZVECT_INITIAL_CAPACITY; - else - v->capacity = init_capacity; + { + v->cap_left = ZVECT_INITIAL_CAPACITY / 2; + v->cap_right= ZVECT_INITIAL_CAPACITY / 2; + } else { + + if (init_capacity <= 4) + capacity = 4; - v->fep = v->capacity / 2; + v->cap_left = capacity / 2; + v->cap_right= capacity / 2; + } + v->begin = 1; + v->end = 1; - v->init_capacity = v->capacity; + v->init_capacity = v->cap_left + v->cap_right; v->flags = properties; v->SfWpFunc = NULL; v->status = 0; @@ -466,7 +586,7 @@ vector vect_create(const size_t init_capacity, const size_t item_size, #endif // Allocate memory for the vector storage area - v->data = (void **)malloc(sizeof(void *) * v->capacity); + v->data = (void **)malloc(sizeof(void *) * _vect_capacity(v)); if (v->data == NULL) throw_error("Not enough memory to allocate the vector storage area!"); @@ -479,33 +599,34 @@ static void _vect_destroy(vector v, uint32_t flags) { check_mutex_lock(v, 1); #endif // Clear the vector: - if ((v->size > 0) && (flags & 1)) { + if ((_vect_size(v) > 0) && (flags & 1)) { // Secure Wipe the vector (or just free) depending on vector properties: - zvect_index i = v->size; // if v->size is 200, then the first i below will be 199 + zvect_index i = _vect_size(v); // if _vect_size(v) is 200, then the first i below will be 199 while (i--) { - if (v->data[i] != NULL) { + if (v->data[v->begin + i] != NULL) { if ((v->flags & ZV_SEC_WIPE)) - item_safewipe(v, v->data[i]); + item_safewipe(v, v->data[v->begin + i]); if (!(v->flags & ZV_BYREF)) { - free(v->data[i]); - v->data[i] = NULL; + free(v->data[v->begin + i]); + v->data[v->begin + i] = NULL; } } } } // Reset interested descriptors: - v->prev_size = v->size; - v->size = 0; + v->prev_end = _vect_size(v); + v->end = 0; // Shrink Vector's capacity: - if (v->capacity > v->init_capacity) + if (_vect_capacity(v) > v->init_capacity) _vect_shrink(v); - v->prev_size = 0; + v->prev_end = 0; v->init_capacity = 0; - v->capacity = 0; + v->cap_left = 0; + v->cap_right = 0; // Destroy it: if ((v->status & ZVS_CUST_WIPE_ON)) { @@ -544,25 +665,6 @@ void vect_destroy(vector v) { /*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -// Vector Structural Information report: - -bool vect_is_empty(vector v) { - // Check if the vector exists - vect_check(v); - - return v->size == 0; -} - -zvect_index vect_size(vector v) { - // Check if the vector exists - vect_check(v); - - return v->size; -} - -/*---------------------------------------------------------------------------*/ - /*---------------------------------------------------------------------------*/ // Vector Thread Safe user functions: @@ -598,11 +700,13 @@ void vect_clear(vector v) { #endif // Clear the vector: - _free_items(v, 0, (v->size - 1)); + if (!vect_is_empty(v)) + _free_items(v, 0, (_vect_size(v) - 1)); // Reset interested descriptors: - v->prev_size = v->size; - v->size = 0; + v->prev_end = _vect_size(v); + v->begin = 1; + v->end = 1; // Shrink Vector's capacity: _vect_shrink(v); @@ -630,16 +734,18 @@ static inline void _vect_add_at(vector v, const void *value, // check if the vector exists: vect_check(v); + zvect_index vsize = _vect_size(v); + // Check if the provided index is out of bounds: - if (i > v->size) - throw_error("Index out of bounds!"); + if (i > vsize) + throw_error("Index out of bounds!"); #if (ZVECT_FULL_REENTRANT == 1) // If we are in FULL_REENTRANT MODE prepare for potential // array copy: void **new_data = NULL; - if (i < v->size) { - new_data = (void **)malloc(sizeof(void *) * v->capacity); + if (i < vsize) { + new_data = (void **)malloc(sizeof(void *) * _vect_capacity(v)); if (new_data == NULL) throw_error("Not enough memory to resize the vector!"); } @@ -650,31 +756,53 @@ static inline void _vect_add_at(vector v, const void *value, #endif // Check if we need to expand the vector: - if (v->size >= v->capacity) - vect_increase_capacity(v); + //if ( vsize >= _vect_capacity(v) ) + // _vect_increase_capacity(v, i); + + if (!i) { + // Check if we need to expand on the left side: + if ( v->begin == 0 || v->cap_left == 1 ) + _vect_increase_capacity(v, 0); + } else { + // Check if we need to expand on thr right side: + if ( v->end >= v->cap_right ) + _vect_increase_capacity(v, 1); + } // Allocate memory for the new item: - if (i == v->size && !(v->flags & ZV_BYREF)) { - v->data[v->size] = (void *)malloc(v->data_size); - if (v->data[v->size] == NULL) - throw_error("Not enough memory to add new item in the vector!"); + zvect_index base = v->begin; + if (!i) { + // Prepare left side of the vector: + base--; + if (!(v->flags & ZV_BYREF)) { + v->data[base] = (void *)malloc(v->data_size); + if (v->data[base] == NULL) + throw_error("Not enough memory to add new item in the vector!"); + } + } else if (i == vsize) { + // Prepare right side of the vector: + if (!(v->flags & ZV_BYREF)) { + v->data[base + vsize] = (void *)malloc(v->data_size); + if (v->data[base + vsize] == NULL) + throw_error("Not enough memory to add new item in the vector!"); + } } // "Shift" right the array of one position to make space for the new item: int16_t array_changed = 0; - if (i < v->size) { + if ((i < vsize) && (i != 0)) { array_changed = 1; #if (ZVECT_FULL_REENTRANT == 1) // Algorithm to try to copy an array of pointers as fast as possible: if (i > 0) - vect_memcpy(new_data, v->data, sizeof(void *) * i); - vect_memcpy(new_data + (i + 1), v->data + i, - sizeof(void *) * (v->size - i)); + vect_memcpy(new_data + base, v->data + base, sizeof(void *) * i); + vect_memcpy(new_data + base + (i + 1), v->data + base + i, + sizeof(void *) * (_vect_size(v) - i)); #else // We can't use the vect_memcpy when not in full reentrant code // because it's not safe to use it on the same src and dst. - vect_memmove(v->data + (i + 1), v->data + i, - sizeof(void *) * (v->size - i)); + vect_memmove(v->data + base + (i + 1), v->data + base + i, + sizeof(void *) * (vsize - i)); #endif // (ZVECT_FULL_REENTRANT == 1) } @@ -682,31 +810,31 @@ static inline void _vect_add_at(vector v, const void *value, #if (ZVECT_FULL_REENTRANT == 1) if (array_changed) { if (v->flags & ZV_BYREF) { - new_data[i] = (void *)value; + new_data[base + i] = (void *)value; } else { - new_data[i] = (void *)malloc(v->data_size); - if (new_data[i] == NULL) + new_data[base + i] = (void *)malloc(v->data_size); + if (new_data[base + i] == NULL) throw_error("Not enough memory to add new item in the vector!"); - vect_memcpy(new_data[i], value, v->data_size); + vect_memcpy(new_data[base + i], value, v->data_size); } } else { if (v->flags & ZV_BYREF) - v->data[i] = (void *)value; + v->data[base + i] = (void *)value; else - vect_memcpy(v->data[i], value, v->data_size); + vect_memcpy(v->data[base + i], value, v->data_size); } #else if (array_changed && !(v->flags & ZV_BYREF)) { // We moved chunks of memory so we need to // allocate new memory for the item at position i: - v->data[i] = (void *)malloc(v->data_size); - if (v->data[i] == NULL) + v->data[base + i] = (void *)malloc(v->data_size); + if (v->data[base + i] == NULL) throw_error("Not enough memory to add new item in the vector!"); } if (v->flags & ZV_BYREF) - v->data[i] = (void *)value; + v->data[base + i] = (void *)value; else - vect_memcpy(v->data[i], value, v->data_size); + vect_memcpy(v->data[base + i], value, v->data_size); #endif // (ZVECT_FULL_REENTRANT == 1) // Apply changes: @@ -716,10 +844,13 @@ static inline void _vect_add_at(vector v, const void *value, v->data = new_data; } #endif - // Increment vector size - v->prev_size = v->size; - v->size++; + v->prev_end = vsize; + if (!i) { + v->begin = base; + } else { + v->end++; + } #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -733,12 +864,12 @@ static inline void _vect_add_at(vector v, const void *value, inline void vect_push(vector v, const void *value) { // Add an item at the END (top) of the vector - _vect_add_at(v, value, v->size); + _vect_add_at(v, value, _vect_size(v)); } void vect_add(vector v, const void *value) { // Add an item at the END of the vector - _vect_add_at(v, value, v->size); + _vect_add_at(v, value, _vect_size(v)); } void vect_add_at(vector v, const void *value, const zvect_index i) { @@ -757,15 +888,15 @@ static inline void *_vect_get_at(vector v, const zvect_index i) { vect_check(v); // Check if passed index is out of bounds: - if (i >= v->size) + if (i >= _vect_size(v)) throw_error("Index out of bounds!"); // Return found element: - return v->data[i]; + return v->data[v->begin + i]; } void *vect_get(vector v) { - return _vect_get_at(v, v->size - 1); + return _vect_get_at(v, _vect_size(v) - 1); } void *vect_get_at(vector v, const zvect_index i) { @@ -783,7 +914,7 @@ static inline void _vect_put_at(vector v, const void *value, vect_check(v); // Check if the index passed is out of bounds: - if (i >= v->size) + if (i >= _vect_size(v)) throw_error("Index out of bounds!"); #if (ZVECT_THREAD_SAFE == 1) @@ -793,12 +924,12 @@ static inline void _vect_put_at(vector v, const void *value, // Add value at the specified index, considering // if the vector has ZV_BYREF property enabled: if ( v->flags & ZV_BYREF ) { - void *temp = v->data[i]; - v->data[i] = (void *)value; + void *temp = v->data[v->begin + i]; + v->data[v->begin + i] = (void *)value; if ( v->flags & ZV_SEC_WIPE ) memset((void *)temp, 0, v->data_size); } else { - vect_memcpy(v->data[i], value, v->data_size); + vect_memcpy(v->data[v->begin + i], value, v->data_size); } #if (ZVECT_THREAD_SAFE == 1) @@ -807,7 +938,7 @@ static inline void _vect_put_at(vector v, const void *value, } void vect_put(vector v, const void *value) { - _vect_put_at(v, value, v->size - 1); + _vect_put_at(v, value, _vect_size(v) - 1); } void vect_put_at(vector v, const void *value, const zvect_index i) { @@ -823,14 +954,20 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { // check if the vector exists: vect_check(v); + zvect_index vsize = _vect_size(v); + // Check if the index is out of bounds: - if (i >= v->size) + if (i >= vsize) throw_error("Index out of bounds!"); // If the vector is empty just return null - if (v->size == 0) + if (vsize == 0) return NULL; + // Check if the vector got corrupted + if (v->begin > v->end) + throw_error("Vector corrupted, left side overwritten the right side!"); + // Start processing the vector: #if (ZVECT_THREAD_SAFE == 1) check_mutex_lock(v, 1); @@ -838,45 +975,56 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { #if (ZVECT_FULL_REENTRANT == 1) // Allocate memory for support Data Structure: - void **new_data = (void **)malloc(sizeof(void *) * v->capacity); + void **new_data = (void **)malloc(sizeof(void *) * _vect_capacity(v)); if (new_data == NULL) throw_error("Not enough memory to resize the vector!"); #endif // Get the value we are about to remove: + // If the vector is set as ZV_BYREF then just copy the pointer to the item + // If the vector is set as regular then copy the item void *rval; + zvect_index base = v->begin; if (v->flags & ZV_BYREF) { - rval = v->data[i]; + rval = v->data[base + i]; } else { rval = (void *)malloc(v->data_size); - vect_memcpy(rval, v->data[i], v->data_size); + vect_memcpy(rval, v->data[base + i], v->data_size); + // If the vector is set for secure wipe and we copied the item + // then we need to wipe the old copy: if (v->flags & ZV_SEC_WIPE) - item_safewipe(v, v->data[i]); + item_safewipe(v, v->data[base + i]); } // "shift" left the array of one position: uint16_t array_changed = 0; - if ((i < (v->size - 1)) && (v->size > 0)) { - array_changed = 1; - free(v->data[i]); + if ( i != 0 ) { + if ((i < (vsize - 1)) && (vsize > 0)) { + array_changed = 1; + free(v->data[base + i]); #if (ZVECT_FULL_REENTRANT == 1) - if (i > 0) - vect_memcpy(new_data, v->data, sizeof(void *) * i); - vect_memcpy(new_data + i, v->data + (i + 1), - sizeof(void *) * (v->size - i)); + vect_memcpy(new_data + base, v->data + base, sizeof(void *) * i); + vect_memcpy(new_data + base + i, v->data + base + (i + 1), + sizeof(void *) * (vsize - i)); #else - // We can't use the vect_memcpy when not in full reentrant code - // because it's not safe to use it on the same src and dst. - vect_memmove(v->data + i, v->data + (i + 1), - sizeof(void *) * (v->size - i)); + // We can't use the vect_memcpy when not in full reentrant code + // because it's not safe to use it on the same src and dst. + vect_memmove(v->data + base + i, v->data + base + (i + 1), + sizeof(void *) * (vsize - i)); #endif + } + } else { + if ( base < v->end ) { + array_changed = 1; + free(v->data[base]); + } } // Reduce vector size: #if (ZVECT_FULL_REENTRANT == 0) if (!(v->flags & ZV_BYREF)) { if (!array_changed) - _free_items(v, v->size - 1, 0); + _free_items(v, vsize - 1, 0); } #else // Apply changes @@ -885,12 +1033,23 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { v->data = new_data; } #endif - v->prev_size = v->size; - v->size--; - + v->prev_end = vsize; + if ( i != 0 ) { + if (v->end > v->begin) { + v->end--; + } else { + v->end = v->begin; + } + } else { + if (v->begin < v->end) { + v->begin++; + } else { + v->begin = v->end; + } + } // Check if we need to shrink vector's capacity: - if ((4 * v->size) < v->capacity) - vect_decrease_capacity(v); + if ((4 * vsize) < _vect_capacity(v) ) + _vect_decrease_capacity(v, i); // All done, return control: #if (ZVECT_THREAD_SAFE == 1) @@ -901,11 +1060,11 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { } inline void *vect_pop(vector v) { - return _vect_remove_at(v, v->size - 1); + return _vect_remove_at(v, _vect_size(v) - 1); } void *vect_remove(vector v) { - return _vect_remove_at(v, v->size - 1); + return _vect_remove_at(v, _vect_size(v) - 1); } void *vect_remove_at(vector v, const zvect_index i) { @@ -920,12 +1079,14 @@ static inline void _vect_delete_at(vector v, const zvect_index start, // check if the vector exists: vect_check(v); + zvect_index vsize = _vect_size(v); + // Check if the index is out of bounds: - if ((start + offset) >= v->size) + if ((start + offset) >= vsize) throw_error("Index out of bounds!"); // If the vector is empty just return null - if (v->size == 0) + if (vsize == 0) return; #if (ZVECT_THREAD_SAFE == 1) @@ -936,24 +1097,46 @@ static inline void _vect_delete_at(vector v, const zvect_index start, // "shift" left the data of one position: zvect_index tot_items = start + offset; - if (tot_items < (v->size - 1)) { + if ( tot_items < (vsize - 1) ) { array_changed = 1; _free_items(v, start, offset); - vect_memmove(v->data + start, v->data + (tot_items + 1), - sizeof(void *) * (v->size - start)); + if ( tot_items ) + vect_memmove(v->data + (v->begin + start), v->data + (v->begin + (tot_items + 1)), + sizeof(void *) * (vsize - start)); } // Reduce vector size: if (!(v->flags & ZV_BYREF)) { if (!array_changed) - _free_items(v, ((v->size - 1) - offset), offset); + _free_items(v, ((vsize - 1) - offset), offset); + } + v->prev_end = vsize; + if ( start ) { + if ((v->end - (offset + 1)) > v->begin) { + v->end -= (offset + 1); + } else { + v->end = v->begin; } - v->prev_size = v->size; - v->size -= (offset + 1); + } else { + if ((v->begin + (offset + 1)) < v->end) { + v->begin += (offset + 1); + } else { + v->begin = v->end; + } + } // Check if we need to shrink the vector: - if ((4 * v->size) < v->capacity) - vect_decrease_capacity(v); + if ((4 * vsize) < _vect_capacity(v)) + _vect_decrease_capacity(v, start); + /* if (!start) { + // Check if we need to expand on the left side: + if ( (v->begin * 4) < v->cap_left ) + _vect_decrease_capacity(v, 0); + } else { + // Check if we need to expand on thr right side: + if ( (v->end * 4) < v->cap_right ) + _vect_decrease_capacity(v, 1); + } */ #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -961,7 +1144,7 @@ static inline void _vect_delete_at(vector v, const zvect_index start, } void vect_delete(vector v) { - _vect_delete_at(v, v->size - 1, 0); + _vect_delete_at(v, _vect_size(v) - 1, 0); } void vect_delete_at(vector v, zvect_index i) { @@ -989,10 +1172,10 @@ void vect_swap(vector v, const zvect_index i1, const zvect_index i2) { vect_check(v); // Check parameters: - if (i1 > v->size) + if (i1 > _vect_size(v)) throw_error("Index out of bounds!"); - if (i2 > v->size) + if (i2 > _vect_size(v)) throw_error("Index out of bounds!"); if (i1 == i2) @@ -1003,9 +1186,9 @@ void vect_swap(vector v, const zvect_index i1, const zvect_index i2) { check_mutex_lock(v, 1); #endif - void *temp = v->data[i2]; - v->data[i2] = v->data[i1]; - v->data[i1] = temp; + void *temp = v->data[v->begin + i2]; + v->data[v->begin + i2] = v->data[v->begin + i1]; + v->data[v->begin + i1] = temp; #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -1022,10 +1205,10 @@ void vect_swap_range(vector v, const zvect_index s1, const zvect_index e1, if (e1 != 0) end = e1 - s1; - if ((s1 + end) > v->size) + if ((s1 + end) > _vect_size(v)) throw_error("Index out of bounds!"); - if ((s2 + end) > v->size) + if ((s2 + end) > _vect_size(v)) throw_error("Index out of bounds!"); if (s2 < (s1 + end)) @@ -1042,9 +1225,9 @@ void vect_swap_range(vector v, const zvect_index s1, const zvect_index e1, for (j = s1; j <= (s1 + end); j++) { i = j - s1; - void *temp = v->data[j]; - v->data[j] = v->data[s2 + i]; - v->data[s2 + i] = temp; + void *temp = v->data[v->begin + j]; + v->data[v->begin + j] = v->data[v->begin + (s2 + i)]; + v->data[v->begin + (s2 + i)] = temp; } #if (ZVECT_THREAD_SAFE == 1) @@ -1060,10 +1243,10 @@ void vect_rotate_left(vector v, const zvect_index i) { if (i == 0) return; - if (i > v->size) + if (i > _vect_size(v)) throw_error("Index out of bounds!"); - if (i == v->size) + if (i == _vect_size(v)) return; // Process the vector @@ -1074,17 +1257,17 @@ void vect_rotate_left(vector v, const zvect_index i) { if (i == 1) { // Rotate left the vector of 1 position: void *temp = v->data[0]; - vect_memmove(v->data, v->data + 1, sizeof(void *) * (v->size - 1)); - v->data[v->size - 1] = temp; + vect_memmove(v->data, v->data + 1, sizeof(void *) * (_vect_size(v) - 1)); + v->data[_vect_size(v) - 1] = temp; } else { - void **new_data = (void **)malloc(sizeof(void *) * v->capacity); + void **new_data = (void **)malloc(sizeof(void *) * _vect_capacity(v)); if (new_data == NULL) throw_error("Not enough memory to rotate the vector!"); // Rotate left the vector of i positions: - vect_memcpy(new_data, v->data, sizeof(void *) * i); - vect_memmove(v->data, v->data + i, sizeof(void *) * (v->size - i)); - vect_memcpy(v->data + (v->size - i), new_data, sizeof(void *) * i); + vect_memcpy(new_data + v->begin, v->data + v->begin, sizeof(void *) * i); + vect_memmove(v->data + v->begin, v->data + v->begin + i, sizeof(void *) * (_vect_size(v) - i)); + vect_memcpy(v->data + v->begin + (_vect_size(v) - i), new_data + v->begin, sizeof(void *) * i); free(new_data); } @@ -1102,10 +1285,10 @@ void vect_rotate_right(vector v, const zvect_index i) { if (i == 0) return; - if (i > v->size) + if (i > _vect_size(v)) throw_error("Index out of bounds!"); - if (i == v->size) + if (i == _vect_size(v)) return; // Process the vector @@ -1115,18 +1298,18 @@ void vect_rotate_right(vector v, const zvect_index i) { if (i == 1) { // Rotate right the vector of 1 position: - void *temp = v->data[v->size - 1]; - vect_memmove(v->data + 1, v->data, sizeof(void *) * (v->size - 1)); - v->data[0] = temp; + void *temp = v->data[v->begin + _vect_size(v) - 1]; + vect_memmove(v->data + v->begin + 1, v->data + v->begin, sizeof(void *) * (_vect_size(v) - 1)); + v->data[v->begin] = temp; } else { - void **new_data = (void **)malloc(sizeof(void *) * v->capacity); + void **new_data = (void **)malloc(sizeof(void *) * _vect_capacity(v)); if (new_data == NULL) throw_error("Not enough memory to rotate the vector!"); // Rotate right the vector of i positions: - vect_memcpy(new_data, v->data + (v->size - i), sizeof(void *) * i); - vect_memmove(v->data + i, v->data, sizeof(void *) * (v->size - i)); - vect_memcpy(v->data, new_data, sizeof(void *) * i); + vect_memcpy(new_data + v->begin, v->data + v->begin + (_vect_size(v) - i), sizeof(void *) * i); + vect_memmove(v->data + v->begin + i, v->data + v->begin, sizeof(void *) * (_vect_size(v) - i)); + vect_memcpy(v->data + v->begin, new_data + v->begin, sizeof(void *) * i); free(new_data); } @@ -1140,16 +1323,16 @@ void vect_rotate_right(vector v, const zvect_index i) { static inline zvect_index _partition(vector v, zvect_index low, zvect_index high, int (*compare_func)(const void *, const void *)) { - if (high >= v->size) - high = v->size - 1; + if (high >= _vect_size(v)) + high = _vect_size(v) - 1; - void *pivot = v->data[high]; + void *pivot = v->data[v->begin + high]; zvect_index i = (low - 1); zvect_index j; for (j = low; j <= (high - 1); j++) { // v->data[j] <= pivot - if ((*compare_func)(v->data[j], pivot) <= 0) + if ((*compare_func)(v->data[v->begin + j], pivot) <= 0) vect_swap(v, ++i, j); } @@ -1190,22 +1373,22 @@ static void _vect_qsort(vector v, zvect_index l, zvect_index r, j = r; p = i; q = r; - ref_val = v->data[r]; + ref_val = v->data[v->begin + r]; for (;;) { - while ((*compare_func)(v->data[i], ref_val) < 0) + while ((*compare_func)(v->data[v->begin + i], ref_val) < 0) i++; - while ((*compare_func)(ref_val, v->data[--j]) < 0) + while ((*compare_func)(ref_val, v->data[(--j) + v->begin]) < 0) if (j == l) break; if (i >= j) break; vect_swap(v, i, j); - if ((*compare_func)(v->data[i], ref_val) == 0) { + if ((*compare_func)(v->data[v->begin + i], ref_val) == 0) { p++; vect_swap(v, p, i); } - if ((*compare_func)(ref_val, v->data[j]) == 0) { + if ((*compare_func)(ref_val, v->data[v->begin + j]) == 0) { q--; vect_swap(v, q, j); } @@ -1227,7 +1410,7 @@ void vect_qsort(vector v, int (*compare_func)(const void *, const void *)) { vect_check(v); // Check parameters: - if (v->size <= 1) + if (_vect_size(v) <= 1) return; if (compare_func == NULL) @@ -1238,7 +1421,7 @@ void vect_qsort(vector v, int (*compare_func)(const void *, const void *)) { check_mutex_lock(v, 1); #endif - _vect_qsort(v, 0, v->size - 1, compare_func); + _vect_qsort(v, 0, _vect_size(v) - 1, compare_func); #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -1252,13 +1435,13 @@ static bool _standard_binary_search(vector v, const void *key, zvect_index bot, mid, top; bot = 0; - top = v->size - 1; + top = _vect_size(v) - 1; while (bot < top) { mid = top - (top - bot) / 2; // key < array[mid] - if ((*f1)(key, v->data[mid]) < 0) { + if ((*f1)(key, v->data[v->begin + mid]) < 0) { top = mid - 1; } else { bot = mid; @@ -1266,7 +1449,7 @@ static bool _standard_binary_search(vector v, const void *key, } // key == array[top] - if ((*f1)(key, v->data[top]) == 0) { + if ((*f1)(key, v->data[v->begin + top]) == 0) { *item_index = top; return true; } @@ -1287,25 +1470,25 @@ static bool _adaptive_binary_search(vector v, const void *key, int (*f1)(const void *, const void *)) { zvect_index bot, top, mid; - if ((v->balance >= 32) || (v->size <= 64)) { + if ((v->balance >= 32) || (_vect_size(v) <= 64)) { bot = 0; - top = v->size; + top = _vect_size(v); goto monobound; } bot = v->bottom; top = 32; // key >= array[bot] - if ((*f1)(key, v->data[bot]) >= 0) { + if ((*f1)(key, v->data[v->begin + bot]) >= 0) { while (1) { - if ((bot + top) >= v->size) { - top = v->size - bot; + if ((bot + top) >= _vect_size(v)) { + top = _vect_size(v) - bot; break; } bot += top; // key < array[bot] - if ((*f1)(key, v->data[bot]) < 0) { + if ((*f1)(key, v->data[v->begin + bot]) < 0) { bot -= top; break; } @@ -1321,7 +1504,7 @@ static bool _adaptive_binary_search(vector v, const void *key, bot -= top; // key >= array[bot] - if ((*f1)(key, v->data[bot]) >= 0) + if ((*f1)(key, v->data[v->begin + bot]) >= 0) break; top *= 2; } @@ -1331,7 +1514,7 @@ static bool _adaptive_binary_search(vector v, const void *key, while (top > 3) { mid = top / 2; // key >= array[bot + mid] - if ((*f1)(key, v->data[bot + mid]) >= 0) + if ((*f1)(key, v->data[v->begin + (bot + mid)]) >= 0) bot += mid; top -= mid; } @@ -1342,7 +1525,7 @@ static bool _adaptive_binary_search(vector v, const void *key, int test = 0; while (top) { // key == array[bot + --top] - test = (*f1)(key, v->data[bot + (--top)]); + test = (*f1)(key, v->data[v->begin + (bot + (--top))]); if (test == 0) { *item_index = bot + top; return true; @@ -1372,7 +1555,7 @@ bool vect_bsearch(vector v, const void *key, if (f1 == NULL) return false; - if (v->size == 0) + if (_vect_size(v) == 0) return false; *item_index = 0; @@ -1409,14 +1592,14 @@ void vect_add_ordered(vector v, const void *value, return; // Few tricks to make it faster: - if (v->size == 0) { + if (_vect_size(v) == 0) { // If the vector is empty clearly we can just // use vect_add and add the value normaly! vect_add(v, value); return; } - if ((*f1)(value, v->data[v->size - 1]) > 0) { + if ((*f1)(value, v->data[v->begin + (_vect_size(v) - 1)]) > 0) { // If the compare function returns that // the value passed should go after the // last value in the vector, just do so! @@ -1463,8 +1646,8 @@ void vect_apply(vector v, void (*f)(void *)) { check_mutex_lock(v, 1); #endif - for (i = v->size; i--;) - (*f)(v->data[i]); + for (i = _vect_size(v); i--;) + (*f)(v->data[v->begin + i]); #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -1480,10 +1663,10 @@ void vect_apply_range(vector v, void (*f)(void *), const zvect_index x, if (f == NULL) return; - if (x > v->size) + if (x > _vect_size(v)) throw_error("Index out of bounds!"); - if (y > v->size) + if (y > _vect_size(v)) throw_error("Index out of bounds!"); zvect_index start; @@ -1503,7 +1686,7 @@ void vect_apply_range(vector v, void (*f)(void *), const zvect_index x, #endif for (i = start; i <= end; i++) - (*f)(v->data[i]); + (*f)(v->data[v->begin + i]); #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -1517,7 +1700,7 @@ void vect_apply_if(vector v1, vector v2, void (*f1)(void *), vect_check(v2); // Check parameters: - if (v1->size > v2->size) + if (_vect_size(v1) > _vect_size(v2)) throw_error("Vector 2 size too small, can't apply 'if' function for all " "items in vector 1!"); @@ -1527,9 +1710,9 @@ void vect_apply_if(vector v1, vector v2, void (*f1)(void *), check_mutex_lock(v1, 1); #endif - for (i = v1->size; i--;) - if ((*f2)(v1->data[i], v2->data[i])) - (*f1)(v1->data[i]); + for (i = _vect_size(v1); i--;) + if ((*f2)(v1->data[v1->begin + i], v2->data[v2->begin + i])) + (*f1)(v1->data[v1->begin + i]); #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v1, 1); @@ -1550,7 +1733,7 @@ void vect_copy(vector v1, vector v2, const zvect_index s2, // Let's check if the indexes provided are correct for // v2: - if (e2 > v2->size || s2 > v2->size) + if (e2 > _vect_size(v2) || s2 > _vect_size(v2)) throw_error("Index out of bounds!"); // If the user specified 0 max_elements then @@ -1558,7 +1741,7 @@ void vect_copy(vector v1, vector v2, const zvect_index s2, // till the last item in the vector 2: zvect_index ee2; if (e2 == 0) - ee2 = (v2->size - 1) - s2; + ee2 = (_vect_size(v2) - 1) - s2; else ee2 = e2; @@ -1566,17 +1749,17 @@ void vect_copy(vector v1, vector v2, const zvect_index s2, check_mutex_lock(v1, 2); #endif // Set the correct capacity for v1 to get the whole v2: - while (v1->capacity <= (v1->size + ee2)) - vect_increase_capacity(v1); + while ( _vect_capacity(v1) <= (_vect_size(v1) + ee2)) + _vect_increase_capacity(v1, 1); // Copy v2 (from s2) in v1 at the end of v1: // zvect_index i; // for (i = s2; i <= s2+ee2; i++) // vect_add(v1, v2->data[i]); - vect_memcpy(v1->data + v1->size, v2->data + s2, sizeof(void *) * ee2); + vect_memcpy(v1->data + v1->begin + _vect_size(v1), v2->data + v2->begin + s2, sizeof(void *) * ee2); // Update v1 size: - v1->size += ee2; + v1->end += ee2; #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v1, 2); @@ -1607,7 +1790,7 @@ void vect_insert(vector v1, vector v2, const zvect_index s2, // Let's check if the indexes provided are correct for // v2: - if ((e2 > v2->size) || (s2 > v2->size)) + if ((e2 > _vect_size(v2)) || (s2 > _vect_size(v2))) throw_error("Index out of bounds!"); // If the user specified 0 max_elements then @@ -1615,7 +1798,7 @@ void vect_insert(vector v1, vector v2, const zvect_index s2, // till the last item in the vector 2: zvect_index ee2; if (e2 == 0) - ee2 = (v2->size - 1) - s2; + ee2 = (_vect_size(v2) - 1) - s2; else ee2 = e2; @@ -1627,7 +1810,7 @@ void vect_insert(vector v1, vector v2, const zvect_index s2, // Copy v2 items (from s2) in v1 (from s1): for (i = s2; i <= s2 + ee2; i++, j++) - vect_add_at(v1, v2->data[i], s1 + j); + vect_add_at(v1, v2->data[v2->begin + i], s1 + j); #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v1, 2); @@ -1657,7 +1840,7 @@ void vect_move(vector v1, vector v2, const zvect_index s2, // Let's check if the indexes provided are correct for // v2: - if ((e2 > v2->data_size) || (s2 > v2->size)) + if ((e2 > v2->data_size) || (s2 > _vect_size(v2))) throw_error("Index out of bounds!"); // If the user specified 0 max_elements then @@ -1665,7 +1848,7 @@ void vect_move(vector v1, vector v2, const zvect_index s2, // till the last item in the vector 2: zvect_index ee2; if (e2 == 0) - ee2 = (v2->size - 1) - s2; + ee2 = (_vect_size(v2) - 1) - s2; else ee2 = e2; @@ -1674,14 +1857,14 @@ void vect_move(vector v1, vector v2, const zvect_index s2, #endif // Set the correct capacity for v1 to get the whole v2: - while (v1->capacity <= (v1->size + ee2)) - vect_increase_capacity(v1); + while (_vect_capacity(v1) <= (_vect_size(v1) + ee2)) + _vect_increase_capacity(v1, 1); // Copy v2 (from s2) in v1 at the end of v1: - vect_memcpy(v1->data + v1->size, v2->data + s2, sizeof(void *) * ee2); + vect_memcpy(v1->data + v1->begin + _vect_size(v1), v2->data + v2->begin + s2, sizeof(void *) * ee2); // Update v1 size: - v1->size += ee2; + v1->end += ee2; zvect_index i; for (i = s2; i <= s2 + ee2; i++) @@ -1708,17 +1891,17 @@ void vect_merge(vector v1, vector v2) { #endif // Set the correct capacity for v1 to get the whole v2: - while (v1->capacity <= (v1->size + v2->size)) - vect_increase_capacity(v1); + while (_vect_capacity(v1) <= (_vect_size(v1) + _vect_size(v2))) + _vect_increase_capacity(v1, 1); // Copy the whole v2 in v1 at the end of v1: // zvect_index i; - // for (i = 0; i < v2->size; i++) + // for (i = 0; i < _vect_size(v2); i++) // vect_add(v1, v2->data[i]); - vect_memcpy(v1->data + v1->size, v2->data, sizeof(void *) * v2->size); + vect_memcpy(v1->data + v1->begin + _vect_size(v1), v2->data + v2->begin, sizeof(void *) * _vect_size(v2)); // Update v1 size: - v1->size += v2->size; + v1->end += _vect_size(v2); // Because we are merging two vectors in one // after merged v2 to v1 there is no need for diff --git a/tests/02ITest002.c b/tests/02ITest002.c index 6985549..9d6ab05 100644 --- a/tests/02ITest002.c +++ b/tests/02ITest002.c @@ -214,7 +214,8 @@ int main() { //usleep(100); // Now wait until the Queue is empty: - while (!vect_is_empty(v)); + while (!vect_is_empty(v)) + ; printf("Test %s_%d: Delete all left over events (if any):\n", testGrp, testID); fflush(stdout); diff --git a/tests/04PTest002.c b/tests/04PTest002.c index 49d7592..8a33e6e 100644 --- a/tests/04PTest002.c +++ b/tests/04PTest002.c @@ -30,7 +30,7 @@ #endif #include ZVECTORH -#define MAX_ITEMS 100000 +#define MAX_ITEMS 10000000 // Setup tests: char *testGrp = "002"; @@ -77,7 +77,7 @@ int main() { fflush(stdout); - printf("Test %s_%d: Create a vector of 1000 elements and using int for the vector data:\n", testGrp, testID); + printf("Test %s_%d: Create a vector of 10 elements and using int for the vector data:\n", testGrp, testID); fflush(stdout); vector v; From 9a561c6eb89fbe25508e408c135abda498f6a1e1 Mon Sep 17 00:00:00 2001 From: Paolo Fabio Zaino Date: Fri, 3 Sep 2021 02:55:58 +0100 Subject: [PATCH 2/3] Some code clean up and re-organisation --- src/zvector.c | 234 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 139 insertions(+), 95 deletions(-) diff --git a/src/zvector.c b/src/zvector.c index cb770bc..865641f 100644 --- a/src/zvector.c +++ b/src/zvector.c @@ -78,12 +78,17 @@ enum { # define ADDR_TYPE3 uint32_t #endif // Arch32 +/*---------------------------------------------------------------------------*/ // Useful macros #define min(x, y) (((x) < (y)) ? (x) : (y)) #define max(x, y) (((x) > (y)) ? (x) : (y)) #define UNUSED(x) (void)x +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ // Define the vector data structure: + struct _vector { zvect_index init_capacity; // - Initial Capacity (this is set at // creation time). @@ -94,8 +99,6 @@ struct _vector { zvect_index end; // - Current Array size. size - 1 gives // us the pointer to the last element // in the vector. - int64_t alloc_dir; // - This variable tracks where we have allocated - // memory for this vector ( < 0 = left, 0 = no allocations yet, > 0 right) size_t data_size; // - User DataType size. uint32_t flags; // - If this flag set is used to // represent ALL Vector's properties. @@ -139,9 +142,14 @@ struct _vector { // Initialisation state: static uint32_t init_state = 0; -/*********************** - ** Support Functions ** - ***********************/ +/*---------------------------------------------------------------------------*/ + +/***************************************************************************** + ** ZVector Support Functions ** + *****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +// Errors and messages handling: static void throw_error(const char *error_message) { #if OS_TYPE == 1 @@ -153,51 +161,10 @@ static void throw_error(const char *error_message) { #endif // OS_TYPE } -static inline void vect_check(vector x) { - if (x == NULL) - throw_error("Vector not defined!"); -} - -static inline zvect_index _vect_capacity(vector v) { - return v->cap_left + v->cap_right; -} - -static inline zvect_index _vect_size(vector v) { - return ( v->end - v->begin ); -} - -static inline void item_safewipe(vector v, const void *item) { - if (item != NULL) { - if (!(v->status & ZVS_CUST_WIPE_ON)) { - memset((void *)item, 0, v->data_size); - } else { - (*(v->SfWpFunc))(item, v->data_size); - } - } -} - -static void _free_items(vector v, zvect_index first, zvect_index offset) { - if (_vect_size(v) == 0) - return; +/*---------------------------------------------------------------------------*/ - register zvect_index j; - for (j = (first + offset); j >= first; j--) { - if (v->data[v->begin + j] != NULL) { - if (v->flags & ZV_SEC_WIPE) - item_safewipe(v, v->data[v->begin + j]); - if (!(v->flags & ZV_BYREF)) { - free(v->data[v->begin + j]); - v->data[v->begin + j] = NULL; - } - } - if (j == first) - break; // this is required if we are using - // uint and the first element is elemnt - // 0, because on GCC a uint will fail - // then check in the for ( j >= first ) - // in this particoular case! - } -} +/*---------------------------------------------------------------------------*/ +// Memory management: #if (ZVECT_MEMX_METHOD == 0) static inline @@ -238,6 +205,11 @@ static inline void *vect_memmove(void *__restrict dst, return memmove(dst, src, size); } +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +// Thread Safe functions: + #if (ZVECT_THREAD_SAFE == 1) static volatile bool lock_enabled = true; # if MUTEX_TYPE == 0 @@ -320,15 +292,19 @@ static inline void check_mutex_unlock(vector v, volatile uint8_t lock_type) { } } #endif // ZVECT_THREAD_SAFE +/*---------------------------------------------------------------------------*/ -/****************************** - ** ZVector Primitives ** - ******************************/ +/***************************************************************************** + ** ZVector Primitives ** + *****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +// Library Initialisation: void init_zvect(void) { #if (OS_TYPE == 1) # if ( !defined(macOS) ) - // mallopt(M_MXFAST, 80*sizeof(size_t)/4); + //mallopt(M_MXFAST, 196*sizeof(size_t)/4); # endif #endif // OS_TYPE == 1 @@ -337,10 +313,65 @@ void init_zvect(void) { init_state = 1; } +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +// Vector's Utilities: + +static inline void _vect_check(vector x) { + if (x == NULL) + throw_error("Vector not defined!"); +} + +static inline zvect_index _vect_capacity(vector v) { + return v->cap_left + v->cap_right; +} + +static inline zvect_index _vect_size(vector v) { + return ( v->end - v->begin ); +} + +static inline void _item_safewipe(vector v, const void *item) { + if (item != NULL) { + if (!(v->status & ZVS_CUST_WIPE_ON)) { + memset((void *)item, 0, v->data_size); + } else { + (*(v->SfWpFunc))(item, v->data_size); + } + } +} + +static void _free_items(vector v, zvect_index first, zvect_index offset) { + if (_vect_size(v) == 0) + return; + + register zvect_index j; + for (j = (first + offset); j >= first; j--) { + if (v->data[v->begin + j] != NULL) { + if (v->flags & ZV_SEC_WIPE) + _item_safewipe(v, v->data[v->begin + j]); + if (!(v->flags & ZV_BYREF)) { + free(v->data[v->begin + j]); + v->data[v->begin + j] = NULL; + } + } + if (j == first) + break; // this is required if we are using + // uint and the first element is elemnt + // 0, because on GCC a uint will fail + // then check in the for ( j >= first ) + // in this particoular case! + } +} + +/*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ // Vector Size and Capacity management functions: -// This function double the CAPACITY of a vector. +/* + * This function increase the CAPACITY of a vector. + */ static void _vect_increase_capacity(vector v, zvect_index direction) { zvect_index new_capacity = 0; @@ -391,7 +422,9 @@ static void _vect_increase_capacity(vector v, zvect_index direction) { } } -// This function halves the CAPACITY of a vector. +/* + * This function decrease the CAPACITY of a vector. + */ static void _vect_decrease_capacity(vector v, zvect_index direction) { // Check if new capacity is smaller than initial capacity if ( _vect_capacity(v) <= v->init_capacity) @@ -444,12 +477,14 @@ static void _vect_decrease_capacity(vector v, zvect_index direction) { } } -// Thi sfunction shrinks the CAPACITY of a vector -// not its size. To reduce the size of a vector we -// need to remove items from it. -void _vect_shrink(vector v) { +/* + * This function shrinks the CAPACITY of a vector + * not its size. To reduce the size of a vector we + * need to remove items from it. + */ +static void _vect_shrink(vector v) { // Check if the vector exists: - vect_check(v); + _vect_check(v); if (v->init_capacity < 2) v->init_capacity = 2; @@ -457,7 +492,7 @@ void _vect_shrink(vector v) { if (_vect_capacity(v) == v->init_capacity) return; - if ( _vect_capacity(v) <= _vect_size(v)) + if (_vect_capacity(v) <= _vect_size(v)) return; // Determine the correct shrunk size: @@ -492,6 +527,19 @@ void _vect_shrink(vector v) { v->cap_right = new_capacity / 2; } +/*---------------------------------------------------------------------------*/ + +/***************************************************************************** + ** ZVector API ** + *****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +// Vector Size and Capacity management functions: + +/* + * Public method to request ZVector to + * shrink a vector. + */ void vect_shrink(vector v) { #if (ZVECT_THREAD_SAFE == 1) check_mutex_lock(v, 1); @@ -506,23 +554,19 @@ void vect_shrink(vector v) { /*---------------------------------------------------------------------------*/ -/*********************** - ** ZVector API ** - ***********************/ - /*---------------------------------------------------------------------------*/ // Vector Structural Information report: bool vect_is_empty(vector v) { // Check if the vector exists - vect_check(v); + _vect_check(v); return _vect_size(v) == 0; } zvect_index vect_size(vector v) { // Check if the vector exists - vect_check(v); + _vect_check(v); // return v->end; return _vect_size(v); @@ -605,7 +649,7 @@ static void _vect_destroy(vector v, uint32_t flags) { while (i--) { if (v->data[v->begin + i] != NULL) { if ((v->flags & ZV_SEC_WIPE)) - item_safewipe(v, v->data[v->begin + i]); + _item_safewipe(v, v->data[v->begin + i]); if (!(v->flags & ZV_BYREF)) { free(v->data[v->begin + i]); @@ -655,7 +699,7 @@ static void _vect_destroy(vector v, uint32_t flags) { void vect_destroy(vector v) { // Check if the vector exists: - vect_check(v); + _vect_check(v); // Call _vect_destroy with flags set to 1 // to destroy data according to the vector @@ -693,7 +737,7 @@ inline void vect_unlock(vector v) { void vect_clear(vector v) { // check if the vector exists: - vect_check(v); + _vect_check(v); #if (ZVECT_THREAD_SAFE == 1) check_mutex_lock(v, 1); @@ -732,7 +776,7 @@ void vect_set_wipefunct(vector v, void (*f1)(const void *, size_t)) { static inline void _vect_add_at(vector v, const void *value, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); zvect_index vsize = _vect_size(v); @@ -885,7 +929,7 @@ void vect_add_front(vector v, const void *value) { // inline implementation for all get(s): static inline void *_vect_get_at(vector v, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check if passed index is out of bounds: if (i >= _vect_size(v)) @@ -911,7 +955,7 @@ void *vect_get_front(vector v) { static inline void _vect_put_at(vector v, const void *value, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check if the index passed is out of bounds: if (i >= _vect_size(v)) @@ -952,7 +996,7 @@ void vect_put_front(vector v, const void *value) { // This is the inline implementation for all the remove and pop static inline void *_vect_remove_at(vector v, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); zvect_index vsize = _vect_size(v); @@ -993,7 +1037,7 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { // If the vector is set for secure wipe and we copied the item // then we need to wipe the old copy: if (v->flags & ZV_SEC_WIPE) - item_safewipe(v, v->data[base + i]); + _item_safewipe(v, v->data[base + i]); } // "shift" left the array of one position: @@ -1077,7 +1121,7 @@ void *vect_remove_front(vector v) { return _vect_remove_at(v, 0); } static inline void _vect_delete_at(vector v, const zvect_index start, const zvect_index offset) { // check if the vector exists: - vect_check(v); + _vect_check(v); zvect_index vsize = _vect_size(v); @@ -1169,7 +1213,7 @@ void vect_delete_front(vector v) { void vect_swap(vector v, const zvect_index i1, const zvect_index i2) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (i1 > _vect_size(v)) @@ -1198,7 +1242,7 @@ void vect_swap(vector v, const zvect_index i1, const zvect_index i2) { void vect_swap_range(vector v, const zvect_index s1, const zvect_index e1, const zvect_index s2) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: zvect_index end = e1; @@ -1237,7 +1281,7 @@ void vect_swap_range(vector v, const zvect_index s1, const zvect_index e1, void vect_rotate_left(vector v, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (i == 0) @@ -1279,7 +1323,7 @@ void vect_rotate_left(vector v, const zvect_index i) { void vect_rotate_right(vector v, const zvect_index i) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (i == 0) @@ -1407,7 +1451,7 @@ static void _vect_qsort(vector v, zvect_index l, zvect_index r, void vect_qsort(vector v, int (*compare_func)(const void *, const void *)) { // check if the vector v1 exists: - vect_check(v); + _vect_check(v); // Check parameters: if (_vect_size(v) <= 1) @@ -1544,7 +1588,7 @@ bool vect_bsearch(vector v, const void *key, int (*f1)(const void *, const void *), zvect_index *item_index) { // check if the vector exists: - vect_check(v); + _vect_check(v); *item_index = 0; @@ -1585,7 +1629,7 @@ bool vect_bsearch(vector v, const void *key, void vect_add_ordered(vector v, const void *value, int (*f1)(const void *, const void *)) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (value == NULL) @@ -1634,7 +1678,7 @@ void vect_add_ordered(vector v, const void *value, void vect_apply(vector v, void (*f)(void *)) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (f == NULL) @@ -1657,7 +1701,7 @@ void vect_apply(vector v, void (*f)(void *)) { void vect_apply_range(vector v, void (*f)(void *), const zvect_index x, const zvect_index y) { // check if the vector exists: - vect_check(v); + _vect_check(v); // Check parameters: if (f == NULL) @@ -1696,8 +1740,8 @@ void vect_apply_range(vector v, void (*f)(void *), const zvect_index x, void vect_apply_if(vector v1, vector v2, void (*f1)(void *), bool (*f2)(void *, void *)) { // check if the vector exists: - vect_check(v1); - vect_check(v2); + _vect_check(v1); + _vect_check(v2); // Check parameters: if (_vect_size(v1) > _vect_size(v2)) @@ -1722,10 +1766,10 @@ void vect_apply_if(vector v1, vector v2, void (*f1)(void *), void vect_copy(vector v1, vector v2, const zvect_index s2, const zvect_index e2) { // check if the vector v1 exists: - vect_check(v1); + _vect_check(v1); // check if the vector v2 exists: - vect_check(v2); + _vect_check(v2); // We can only copy vectors with the same data_size! if (v1->data_size != v2->data_size) @@ -1779,10 +1823,10 @@ void vect_copy(vector v1, vector v2, const zvect_index s2, void vect_insert(vector v1, vector v2, const zvect_index s2, const zvect_index e2, const zvect_index s1) { // check if the vector v1 exists: - vect_check(v1); + _vect_check(v1); // check if the vector v2 exists: - vect_check(v2); + _vect_check(v2); // We can only copy vectors with the same data_size! if (v1->data_size != v2->data_size) @@ -1829,10 +1873,10 @@ void vect_insert(vector v1, vector v2, const zvect_index s2, void vect_move(vector v1, vector v2, const zvect_index s2, const zvect_index e2) { // check if the vector v1 exists: - vect_check(v1); + _vect_check(v1); // check if the vector v2 exists: - vect_check(v2); + _vect_check(v2); // We can only copy vectors with the same data_size! if (v1->data_size != v2->data_size) @@ -1877,10 +1921,10 @@ void vect_move(vector v1, vector v2, const zvect_index s2, void vect_merge(vector v1, vector v2) { // check if the vector v1 exists: - vect_check(v1); + _vect_check(v1); // check if the vector v2 exists: - vect_check(v2); + _vect_check(v2); // We can only copy vectors with the same data_size! if (v1->data_size != v2->data_size) From b9377db7b95e39d0028c39e748357cbb4f1d590e Mon Sep 17 00:00:00 2001 From: Paolo Fabio Zaino Date: Mon, 6 Sep 2021 16:08:01 +0100 Subject: [PATCH 3/3] more code cleaning for forthcoming RC3 --- src/zvector.c | 81 +++++++++++++++++++++++++++++++++------------- tests/04PTest001.c | 2 +- tests/04PTest002.c | 2 +- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/zvector.c b/src/zvector.c index 865641f..714ec92 100644 --- a/src/zvector.c +++ b/src/zvector.c @@ -775,9 +775,7 @@ void vect_set_wipefunct(vector v, void (*f1)(const void *, size_t)) { // inline implementation for all add(s): static inline void _vect_add_at(vector v, const void *value, const zvect_index i) { - // check if the vector exists: - _vect_check(v); - + // Get vector size: zvect_index vsize = _vect_size(v); // Check if the provided index is out of bounds: @@ -890,11 +888,10 @@ static inline void _vect_add_at(vector v, const void *value, #endif // Increment vector size v->prev_end = vsize; - if (!i) { + if (!i) v->begin = base; - } else { + else v->end++; - } #if (ZVECT_THREAD_SAFE == 1) check_mutex_unlock(v, 1); @@ -907,30 +904,39 @@ static inline void _vect_add_at(vector v, const void *value, } inline void vect_push(vector v, const void *value) { + // check if the vector exists: + _vect_check(v); + // Add an item at the END (top) of the vector _vect_add_at(v, value, _vect_size(v)); } void vect_add(vector v, const void *value) { + // check if the vector exists: + _vect_check(v); + // Add an item at the END of the vector _vect_add_at(v, value, _vect_size(v)); } void vect_add_at(vector v, const void *value, const zvect_index i) { + // check if the vector exists: + _vect_check(v); + // Add an item at position "i" of the vector _vect_add_at(v, value, i); } void vect_add_front(vector v, const void *value) { + // check if the vector exists: + _vect_check(v); + // Add an item at the FRONT of the vector _vect_add_at(v, value, 0); } // inline implementation for all get(s): static inline void *_vect_get_at(vector v, const zvect_index i) { - // check if the vector exists: - _vect_check(v); - // Check if passed index is out of bounds: if (i >= _vect_size(v)) throw_error("Index out of bounds!"); @@ -940,23 +946,29 @@ static inline void *_vect_get_at(vector v, const zvect_index i) { } void *vect_get(vector v) { + // check if the vector exists: + _vect_check(v); + return _vect_get_at(v, _vect_size(v) - 1); } void *vect_get_at(vector v, const zvect_index i) { + // check if the vector exists: + _vect_check(v); + return _vect_get_at(v, i); } void *vect_get_front(vector v) { + // check if the vector exists: + _vect_check(v); + return _vect_get_at(v, 0); } // inlin eimplementation for all put: static inline void _vect_put_at(vector v, const void *value, const zvect_index i) { - // check if the vector exists: - _vect_check(v); - // Check if the index passed is out of bounds: if (i >= _vect_size(v)) throw_error("Index out of bounds!"); @@ -982,22 +994,29 @@ static inline void _vect_put_at(vector v, const void *value, } void vect_put(vector v, const void *value) { + // check if the vector exists: + _vect_check(v); + _vect_put_at(v, value, _vect_size(v) - 1); } void vect_put_at(vector v, const void *value, const zvect_index i) { + // check if the vector exists: + _vect_check(v); + _vect_put_at(v, value, i); } void vect_put_front(vector v, const void *value) { + // check if the vector exists: + _vect_check(v); + _vect_put_at(v, value, 0); } // This is the inline implementation for all the remove and pop static inline void *_vect_remove_at(vector v, const zvect_index i) { - // check if the vector exists: - _vect_check(v); - + // Get the vector size: zvect_index vsize = _vect_size(v); // Check if the index is out of bounds: @@ -1064,7 +1083,7 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { } } - // Reduce vector size: + // Reduce vector size: #if (ZVECT_FULL_REENTRANT == 0) if (!(v->flags & ZV_BYREF)) { if (!array_changed) @@ -1104,15 +1123,24 @@ static inline void *_vect_remove_at(vector v, const zvect_index i) { } inline void *vect_pop(vector v) { + // check if the vector exists: + _vect_check(v); + return _vect_remove_at(v, _vect_size(v) - 1); } void *vect_remove(vector v) { + // check if the vector exists: + _vect_check(v); + return _vect_remove_at(v, _vect_size(v) - 1); } void *vect_remove_at(vector v, const zvect_index i) { - return _vect_remove_at(v, i); + // check if the vector exists: + _vect_check(v); + + return _vect_remove_at(v, i); } void *vect_remove_front(vector v) { return _vect_remove_at(v, 0); } @@ -1120,9 +1148,6 @@ void *vect_remove_front(vector v) { return _vect_remove_at(v, 0); } // This is the inline implementation for all the delete static inline void _vect_delete_at(vector v, const zvect_index start, const zvect_index offset) { - // check if the vector exists: - _vect_check(v); - zvect_index vsize = _vect_size(v); // Check if the index is out of bounds: @@ -1155,7 +1180,7 @@ static inline void _vect_delete_at(vector v, const zvect_index start, _free_items(v, ((vsize - 1) - offset), offset); } v->prev_end = vsize; - if ( start ) { + if ( start != 0 ) { if ((v->end - (offset + 1)) > v->begin) { v->end -= (offset + 1); } else { @@ -1188,20 +1213,32 @@ static inline void _vect_delete_at(vector v, const zvect_index start, } void vect_delete(vector v) { + // check if the vector exists: + _vect_check(v); + _vect_delete_at(v, _vect_size(v) - 1, 0); } void vect_delete_at(vector v, zvect_index i) { + // check if the vector exists: + _vect_check(v); + _vect_delete_at(v, i, 0); } void vect_delete_range(vector v, const zvect_index first_element, const zvect_index last_element) { + // check if the vector exists: + _vect_check(v); + zvect_index end = (last_element - first_element); _vect_delete_at(v, first_element, end); } void vect_delete_front(vector v) { + // check if the vector exists: + _vect_check(v); + _vect_delete_at(v, 0, 0); } @@ -1590,8 +1627,6 @@ bool vect_bsearch(vector v, const void *key, // check if the vector exists: _vect_check(v); - *item_index = 0; - // Check parameters: if (key == NULL) return false; diff --git a/tests/04PTest001.c b/tests/04PTest001.c index 5c471de..14f71c5 100644 --- a/tests/04PTest001.c +++ b/tests/04PTest001.c @@ -74,7 +74,7 @@ int main() { CCPAL_INIT_LIB; printf("=== PTest%s ===\n", testGrp); - printf("Testing basic vector PERFORMANCE (BEST POSSIBLE SCENARIO)\n"); + printf("Testing basic vector PERFORMANCE (Typical Dynamic Arrays BEST USE CASE SCENARIO)\n"); fflush(stdout); diff --git a/tests/04PTest002.c b/tests/04PTest002.c index 8a33e6e..3c340a7 100644 --- a/tests/04PTest002.c +++ b/tests/04PTest002.c @@ -73,7 +73,7 @@ int main() { CCPAL_INIT_LIB; printf("=== PTest%s ===\n", testGrp); - printf("Testing basic vector PERFORMANCE (WORST POSSIBLE SCENARIO)\n"); + printf("Testing basic vector PERFORMANCE (Typical Dynamic Arrays WORST USE CASE SCENARIO)\n"); fflush(stdout);