/* * This file is part of LibParserUtils. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> */ #if defined PLAN9#include <limits.h>#define INT32_MAX INT_MAX#endif #include <inttypes.h>#include <string.h> #include <parserutils/utils/vector.h> /** * Vector object */struct parserutils_vector{ size_t item_size; /**< Size of an item in the vector */ size_t chunk_size; /**< Size of a vector chunk */ size_t items_allocated; /**< Number of slots allocated */ int32_t current_item; /**< Index of current item */ void *items; /**< Items in vector */ parserutils_alloc alloc; /**< Memory (de)allocation function */ void *pw; /**< Client-specific data */}; /** * Create a vector * * \param item_size Length, in bytes, of an item in the vector * \param chunk_size Number of vector slots in a chunk * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param vector Pointer to location to receive vector instance * \return PARSERUTILS_OK on success, * PARSERUTILS_BADPARM on bad parameters, * PARSERUTILS_NOMEM on memory exhaustion */parserutils_error parserutils_vector_create(size_t item_size, size_t chunk_size, parserutils_alloc alloc, void *pw, parserutils_vector **vector){ parserutils_vector *v; if (item_size == 0 || chunk_size == 0 || alloc == NULL || vector == NULL) return PARSERUTILS_BADPARM; v = alloc(NULL, sizeof(parserutils_vector), pw); if (v == NULL) return PARSERUTILS_NOMEM; v->items = alloc(NULL, item_size * chunk_size, pw); if (v->items == NULL) { alloc(v, 0, pw); return PARSERUTILS_NOMEM; } v->item_size = item_size; v->chunk_size = chunk_size; v->items_allocated = chunk_size; v->current_item = -1; v->alloc = alloc; v->pw = pw; *vector = v; return PARSERUTILS_OK;} /** * Destroy a vector instance * * \param vector The vector to destroy * \return PARSERUTILS_OK on success, appropriate error otherwise. */parserutils_error parserutils_vector_destroy(parserutils_vector *vector){ if (vector == NULL) return PARSERUTILS_BADPARM; vector->alloc(vector->items, 0, vector->pw); vector->alloc(vector, 0, vector->pw); return PARSERUTILS_OK;} /** * Append an item to the vector * * \param vector The vector to append to * \param item The item to append * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_vector_append(parserutils_vector *vector, void *item){ int32_t slot; if (vector == NULL || item == NULL) return PARSERUTILS_BADPARM; /* Ensure we'll get a valid slot */ if (vector->current_item < -1 || vector->current_item == INT32_MAX) return PARSERUTILS_INVALID; slot = vector->current_item + 1; if ((size_t) slot >= vector->items_allocated) { void *temp = vector->alloc(vector->items, (vector->items_allocated + vector->chunk_size) * vector->item_size, vector->pw); if (temp == NULL) return PARSERUTILS_NOMEM; vector->items = temp; vector->items_allocated += vector->chunk_size; } memcpy((uint8_t *) vector->items + (slot * vector->item_size), item, vector->item_size); vector->current_item = slot; return PARSERUTILS_OK;} /** * Clear a vector * * \param vector The vector to clear * \return PARSERUTILS_OK on success, appropriate error otherwise. */parserutils_error parserutils_vector_clear(parserutils_vector *vector){ if (vector == NULL) return PARSERUTILS_BADPARM; if (vector->current_item < 0) return PARSERUTILS_INVALID; vector->current_item = -1; return PARSERUTILS_OK;} /** * Remove the last item from a vector * * \param vector The vector to remove from * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_vector_remove_last(parserutils_vector *vector){ if (vector == NULL) return PARSERUTILS_BADPARM; if (vector->current_item < 0) return PARSERUTILS_INVALID; vector->current_item--; return PARSERUTILS_OK;} /** * Acquire the length (in items) of the vector. * * \param vector The vector to interrogate. * \param length Pointer to location to receive length information. * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_vector_get_length(parserutils_vector *vector, size_t *length){ if (vector == NULL) return PARSERUTILS_BADPARM; if (length == NULL) return PARSERUTILS_BADPARM; *length = vector->current_item + 1; return PARSERUTILS_OK;} /** * Iterate over a vector * * \param vector The vector to iterate over * \param ctx Pointer to an integer for the iterator to use as context. * \return Pointer to current item, or NULL if no more * * \note The value pointed to by \a ctx must be zero to begin the iteration. */const void *parserutils_vector_iterate(const parserutils_vector *vector, int32_t *ctx){ void *item; if (vector == NULL || ctx == NULL || vector->current_item < 0) return NULL; if ((*ctx) > vector->current_item) return NULL; item = (uint8_t *) vector->items + ((*ctx) * vector->item_size); (*ctx)++; return item;} /** * Peek at an item in a vector * * \param vector The vector to iterate over * \param ctx Integer for the iterator to use as context. * \return Pointer to item, or NULL if no more */const void *parserutils_vector_peek(const parserutils_vector *vector, int32_t ctx){ if (vector == NULL || vector->current_item < 0) return NULL; if (ctx > vector->current_item) return NULL; return (uint8_t *) vector->items + (ctx * vector->item_size);} #ifndef NDEBUG#include <stdio.h> extern void parserutils_vector_dump(parserutils_vector *vector, const char *prefix, void (*printer)(void *item)); void parserutils_vector_dump(parserutils_vector *vector, const char *prefix, void (*printer)(void *item)){ int32_t i; if (vector == NULL || printer == NULL) return; for (i = 0; i <= vector->current_item; i++) { printf("%s %d: ", prefix != NULL ? prefix : "", i); printer((uint8_t *) vector->items + (i * vector->item_size)); printf("\n"); }} #endif
/*
* This file is part of LibParserUtils.
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
*/
#if defined PLAN9
#include <limits.h>
#define INT32_MAX INT_MAX
#endif
#include <inttypes.h>
#include <string.h>
#include <parserutils/utils/vector.h>
/**
* Vector object
*/
struct parserutils_vector
{
size_t item_size; /**< Size of an item in the vector */
size_t chunk_size; /**< Size of a vector chunk */
size_t items_allocated; /**< Number of slots allocated */
int32_t current_item; /**< Index of current item */
void *items; /**< Items in vector */
parserutils_alloc alloc; /**< Memory (de)allocation function */
void *pw; /**< Client-specific data */
};
/**
* Create a vector
*
* \param item_size Length, in bytes, of an item in the vector
* \param chunk_size Number of vector slots in a chunk
* \param alloc Memory (de)allocation function
* \param pw Pointer to client-specific private data
* \param vector Pointer to location to receive vector instance
* \return PARSERUTILS_OK on success,
* PARSERUTILS_BADPARM on bad parameters,
* PARSERUTILS_NOMEM on memory exhaustion
*/
parserutils_error parserutils_vector_create(size_t item_size,
size_t chunk_size, parserutils_alloc alloc, void *pw,
parserutils_vector **vector)
{
parserutils_vector *v;
if (item_size == 0 || chunk_size == 0 || alloc == NULL ||
vector == NULL)
return PARSERUTILS_BADPARM;
v = alloc(NULL, sizeof(parserutils_vector), pw);
if (v == NULL)
return PARSERUTILS_NOMEM;
v->items = alloc(NULL, item_size * chunk_size, pw);
if (v->items == NULL) {
alloc(v, 0, pw);
return PARSERUTILS_NOMEM;
}
v->item_size = item_size;
v->chunk_size = chunk_size;
v->items_allocated = chunk_size;
v->current_item = -1;
v->alloc = alloc;
v->pw = pw;
*vector = v;
return PARSERUTILS_OK;
}
/**
* Destroy a vector instance
*
* \param vector The vector to destroy
* \return PARSERUTILS_OK on success, appropriate error otherwise.
*/
parserutils_error parserutils_vector_destroy(parserutils_vector *vector)
{
if (vector == NULL)
return PARSERUTILS_BADPARM;
vector->alloc(vector->items, 0, vector->pw);
vector->alloc(vector, 0, vector->pw);
return PARSERUTILS_OK;
}
/**
* Append an item to the vector
*
* \param vector The vector to append to
* \param item The item to append
* \return PARSERUTILS_OK on success, appropriate error otherwise
*/
parserutils_error parserutils_vector_append(parserutils_vector *vector,
void *item)
{
int32_t slot;
if (vector == NULL || item == NULL)
return PARSERUTILS_BADPARM;
/* Ensure we'll get a valid slot */
if (vector->current_item < -1 || vector->current_item == INT32_MAX)
return PARSERUTILS_INVALID;
slot = vector->current_item + 1;
if ((size_t) slot >= vector->items_allocated) {
void *temp = vector->alloc(vector->items,
(vector->items_allocated + vector->chunk_size) *
vector->item_size, vector->pw);
if (temp == NULL)
return PARSERUTILS_NOMEM;
vector->items = temp;
vector->items_allocated += vector->chunk_size;
}
memcpy((uint8_t *) vector->items + (slot * vector->item_size),
item, vector->item_size);
vector->current_item = slot;
return PARSERUTILS_OK;
}
/**
* Clear a vector
*
* \param vector The vector to clear
* \return PARSERUTILS_OK on success, appropriate error otherwise.
*/
parserutils_error parserutils_vector_clear(parserutils_vector *vector)
{
if (vector == NULL)
return PARSERUTILS_BADPARM;
if (vector->current_item < 0)
return PARSERUTILS_INVALID;
vector->current_item = -1;
return PARSERUTILS_OK;
}
/**
* Remove the last item from a vector
*
* \param vector The vector to remove from
* \return PARSERUTILS_OK on success, appropriate error otherwise
*/
parserutils_error parserutils_vector_remove_last(parserutils_vector *vector)
{
if (vector == NULL)
return PARSERUTILS_BADPARM;
if (vector->current_item < 0)
return PARSERUTILS_INVALID;
vector->current_item--;
return PARSERUTILS_OK;
}
/**
* Acquire the length (in items) of the vector.
*
* \param vector The vector to interrogate.
* \param length Pointer to location to receive length information.
* \return PARSERUTILS_OK on success, appropriate error otherwise
*/
parserutils_error parserutils_vector_get_length(parserutils_vector *vector,
size_t *length)
{
if (vector == NULL)
return PARSERUTILS_BADPARM;
if (length == NULL)
return PARSERUTILS_BADPARM;
*length = vector->current_item + 1;
return PARSERUTILS_OK;
}
/**
* Iterate over a vector
*
* \param vector The vector to iterate over
* \param ctx Pointer to an integer for the iterator to use as context.
* \return Pointer to current item, or NULL if no more
*
* \note The value pointed to by \a ctx must be zero to begin the iteration.
*/
const void *parserutils_vector_iterate(const parserutils_vector *vector,
int32_t *ctx)
{
void *item;
if (vector == NULL || ctx == NULL || vector->current_item < 0)
return NULL;
if ((*ctx) > vector->current_item)
return NULL;
item = (uint8_t *) vector->items + ((*ctx) * vector->item_size);
(*ctx)++;
return item;
}
/**
* Peek at an item in a vector
*
* \param vector The vector to iterate over
* \param ctx Integer for the iterator to use as context.
* \return Pointer to item, or NULL if no more
*/
const void *parserutils_vector_peek(const parserutils_vector *vector,
int32_t ctx)
{
if (vector == NULL || vector->current_item < 0)
return NULL;
if (ctx > vector->current_item)
return NULL;
return (uint8_t *) vector->items + (ctx * vector->item_size);
}
#ifndef NDEBUG
#include <stdio.h>
extern void parserutils_vector_dump(parserutils_vector *vector,
const char *prefix, void (*printer)(void *item));
void parserutils_vector_dump(parserutils_vector *vector, const char *prefix,
void (*printer)(void *item))
{
int32_t i;
if (vector == NULL || printer == NULL)
return;
for (i = 0; i <= vector->current_item; i++) {
printf("%s %d: ", prefix != NULL ? prefix : "", i);
printer((uint8_t *) vector->items + (i * vector->item_size));
printf("\n");
}
}
#endif