FTL/src/vector.c

124 lines
3.4 KiB
C

/* Pi-hole: A black hole for Internet advertisements
* (c) 2020 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* Dynamic vector routines
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
#include "vector.h"
// struct config
#include "config.h"
// logg()
#include "log.h"
sqlite3_stmt_vec *new_sqlite3_stmt_vec(unsigned int initial_size)
{
if(config.debug & DEBUG_VECTORS)
logg("Initializing new sqlite3_stmt* vector with size %u", initial_size);
sqlite3_stmt_vec *v = calloc(1, sizeof(sqlite3_stmt_vec));
v->capacity = initial_size;
// Calloc ensures they are all set to zero which is the default state
v->items = calloc(initial_size, sizeof(sqlite3_stmt *) * initial_size);
// Set correct subroutine pointers
v->set = set_sqlite3_stmt_vec;
v->get = get_sqlite3_stmt_vec;
return v;
}
static void resize_sqlite3_stmt_vec(sqlite3_stmt_vec *v, unsigned int capacity)
{
if(config.debug & DEBUG_VECTORS)
logg("Resizing sqlite3_stmt* vector %p from %u to %u", v, v->capacity, capacity);
// If ptr is NULL, the call to realloc(ptr, size) is equivalent to
// malloc(size) so we can use it also for initializing a vector for the
// first time.
sqlite3_stmt **items = realloc(v->items, sizeof(sqlite3_stmt *) * capacity);
if(!items)
{
logg("ERROR: Memory allocation failed in resize_sqlite3_stmt_vec(%p, %u)",
v, capacity);
return;
}
// Update items pointer
v->items = items;
// NULL-initialize newly allocated memory slots
for(unsigned int i = v->capacity; i < capacity; i++)
v->items[i] = NULL;
// Update capacity
v->capacity = capacity;
}
void set_sqlite3_stmt_vec(sqlite3_stmt_vec *v, unsigned int index, sqlite3_stmt *item)
{
if(config.debug & DEBUG_VECTORS)
logg("Setting sqlite3_stmt** %p[%u] <-- %p", v, index, item);
if(v == NULL)
{
logg("ERROR: Passed NULL vector to set_sqlite3_stmt_vec(%p, %u, %p)",
v, index, item);
return;
}
if(index >= v->capacity)
{
// Allocate more memory when trying to set a statement vector entry with
// an index larger than the current array size (this makes set an
// equivalent alternative to append)
resize_sqlite3_stmt_vec(v, index + VEC_ALLOC_STEP);
}
// Set item
v->items[index] = item;
}
// This function has no effects except to return a value. It can be subject to
// data flow analysis and might be eliminated. Hence, we add the "pure"
// attribute to this function.
sqlite3_stmt * __attribute__((pure)) get_sqlite3_stmt_vec(sqlite3_stmt_vec *v, unsigned int index)
{
if(v == NULL)
{
logg("ERROR: Passed NULL vector to get_sqlite3_stmt_vec(%p, %u)",
v, index);
return 0;
}
if(index >= v->capacity)
{
// Silently increase size of vector if trying to read out-of-bounds
resize_sqlite3_stmt_vec(v, index + VEC_ALLOC_STEP);
}
sqlite3_stmt* item = v->items[index];
if(config.debug & DEBUG_VECTORS)
logg("Getting sqlite3_stmt** %p[%u] --> %p", v, index, item);
return item;
}
void free_sqlite3_stmt_vec(sqlite3_stmt_vec **v)
{
if(config.debug & DEBUG_VECTORS)
logg("Freeing sqlite3_stmt* vector %p", *v);
// This vector was never allocated, invoking free_sqlite3_stmt_vec() on a
// NULL pointer should be a harmless no-op.
if(v == NULL || *v == NULL || (*v)->items == NULL)
return;
// Free elements of the vector...
free((*v)->items);
// ...and then the vector itself
free(*v);
*v = NULL;
}