vector.h revision 4ba684c495481036e2cd9ad27ef668841e21493e
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** @file
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * STL-inspired vector implementation in C
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * @note functions in this file are inline to prevent warnings about
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * unused static functions. I assume that in this day and age a
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * compiler makes its own decisions about whether to actually
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * inline a function.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * @note as this header is included in rdesktop-vrdp, we do not include other
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * required header files here (to wit assert.h, err.h, mem.h and
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * types.h). These must be included first. If this moves to iprt, we
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * should write a wrapper around it doing that.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * @todo can we do more of the type checking at compile time somehow?
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/*
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * Copyright (C) 2008-2010 Oracle Corporation
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync *
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * available from http://www.virtualbox.org. This file is free software;
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * General Public License (GPL) as published by the Free Software
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#ifndef MAIN_VECTOR_H
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync# define MAIN_VECTOR_H
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/*** Helper macros and deinitions ***/
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** The unit by which the vector capacity is increased */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#define VECTOR_ALLOC_UNIT 16
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** Calculate a hash of a string of tokens for sanity type checking */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#define VECTOR_TOKEN_HASH(token) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ((unsigned) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ( VECTOR_TOKEN_HASH4(token, 0) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH4(token, 4) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH4(token, 8) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH4(token, 12)))
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** Helper macro for @a VECTOR_TOKEN_HASH */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#define VECTOR_TOKEN_HASH_VALUE(token, place, mul) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync (sizeof(#token) > place ? #token[place] * mul : 0)
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** Helper macro for @a VECTOR_TOKEN_HASH */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#define VECTOR_TOKEN_HASH4(token, place) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync VECTOR_TOKEN_HASH_VALUE(token, place, 0x1) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH_VALUE(token, place + 1, 0x100) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH_VALUE(token, place + 2, 0x10000) \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync ^ VECTOR_TOKEN_HASH_VALUE(token, place + 3, 0x1000000)
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** Generic vector structure, used by @a VECTOR_OBJ and @a VECTOR_PTR */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync#define VECTOR_STRUCT \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync{ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** The number of elements in the vector */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync size_t mcElements; \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** The current capacity of the vector */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync size_t mcCapacity; \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** The size of an element */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync size_t mcbElement; \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** Hash value of the element type */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync unsigned muTypeHash; \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** The elements themselves */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync void *mpvaElements; \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** Destructor for elements - takes a pointer to an element. */ \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync void (*mpfnCleanup)(void *); \
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync}
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
fb98ad2c5db683e0704e0cba88f305e95dc1b73avboxsync/*** Structure definitions ***/
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** A vector of values or objects */
fb98ad2c5db683e0704e0cba88f305e95dc1b73avboxsynctypedef struct VECTOR_OBJ VECTOR_STRUCT VECTOR_OBJ;
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/** A vector of pointer values. (A handy special case.) */
typedef struct VECTOR_PTR VECTOR_STRUCT VECTOR_PTR;
/** Convenience macro for annotating the type of the vector. Unfortunately the
* type name is only cosmetic. */
/** @todo can we do something useful with the type? */
#define VECTOR_OBJ(type) VECTOR_OBJ
/** Convenience macro for annotating the type of the vector. Unfortunately the
* type name is only cosmetic. */
#define VECTOR_PTR(type) VECTOR_PTR
/*** Private helper functions and macros ***/
#define VEC_GET_ELEMENT_OBJ(pvaElements, cbElement, cElement) \
((void *)((char *)(pvaElements) + (cElement) * (cbElement)))
#define VEC_GET_ELEMENT_PTR(pvaElements, cElement) \
(*(void **)VEC_GET_ELEMENT_OBJ(pvaElements, sizeof(void *), cElement))
/** Default cleanup function that does nothing. */
DECLINLINE(void) vecNoCleanup(void *pvElement)
{
(void) pvElement;
}
/** Expand an existing vector, implementation */
DECLINLINE(int) vecExpand(size_t *pcCapacity, void **ppvaElements,
size_t cbElement)
{
size_t cOldCap, cNewCap;
void *pRealloc;
cOldCap = *pcCapacity;
cNewCap = cOldCap + VECTOR_ALLOC_UNIT;
pRealloc = RTMemRealloc(*ppvaElements, cNewCap * cbElement);
if (!pRealloc)
return VERR_NO_MEMORY;
*pcCapacity = cNewCap;
*ppvaElements = pRealloc;
return VINF_SUCCESS;
}
/** Expand an existing vector */
#define VEC_EXPAND(pvec) vecExpand(&(pvec)->mcCapacity, &(pvec)->mpvaElements, \
(pvec)->mcbElement)
/** Reset a vector, cleaning up all its elements. */
DECLINLINE(void) vecClearObj(VECTOR_OBJ *pvec)
{
unsigned i;
for (i = 0; i < pvec->mcElements; ++i)
pvec->mpfnCleanup(VEC_GET_ELEMENT_OBJ(pvec->mpvaElements,
pvec->mcbElement, i));
pvec->mcElements = 0;
}
/** Reset a pointer vector, cleaning up all its elements. */
DECLINLINE(void) vecClearPtr(VECTOR_PTR *pvec)
{
unsigned i;
for (i = 0; i < pvec->mcElements; ++i)
pvec->mpfnCleanup(VEC_GET_ELEMENT_PTR(pvec->mpvaElements, i));
pvec->mcElements = 0;
}
/** Clean up a vector */
DECLINLINE(void) vecCleanupObj(VECTOR_OBJ *pvec)
{
vecClearObj(pvec);
RTMemFree(pvec->mpvaElements);
pvec->mpvaElements = NULL;
}
/** Clean up a pointer vector */
DECLINLINE(void) vecCleanupPtr(VECTOR_PTR *pvec)
{
vecClearPtr(pvec);
RTMemFree(pvec->mpvaElements);
pvec->mpvaElements = NULL;
}
/** Initialise a vector structure, implementation */
#define VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup) \
pvec->mcElements = pvec->mcCapacity = 0; \
pvec->mcbElement = cbElement; \
pvec->muTypeHash = uTypeHash; \
pvec->mpfnCleanup = pfnCleanup ? pfnCleanup : vecNoCleanup; \
pvec->mpvaElements = NULL;
/** Initialise a vector. */
DECLINLINE(void) vecInitObj(VECTOR_OBJ *pvec, size_t cbElement,
unsigned uTypeHash, void (*pfnCleanup)(void *))
{
VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup)
}
/** Initialise a pointer vector. */
DECLINLINE(void) vecInitPtr(VECTOR_PTR *pvec, size_t cbElement,
unsigned uTypeHash, void (*pfnCleanup)(void *))
{
VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup)
}
/** Add an element onto the end of a vector */
DECLINLINE(int) vecPushBackObj(VECTOR_OBJ *pvec, unsigned uTypeHash,
void *pvElement)
{
int rc2;
AssertReturn(pvec->muTypeHash == uTypeHash, VERR_INVALID_PARAMETER);
if ( pvec->mcElements == pvec->mcCapacity
&& RT_FAILURE((rc2 = VEC_EXPAND(pvec))))
return rc2;
memcpy(VEC_GET_ELEMENT_OBJ(pvec->mpvaElements, pvec->mcbElement,
pvec->mcElements), pvElement, pvec->mcbElement);
++pvec->mcElements;
return VINF_SUCCESS;
}
/** Add a pointer onto the end of a pointer vector */
DECLINLINE(int) vecPushBackPtr(VECTOR_PTR *pvec, unsigned uTypeHash,
void *pv)
{
int rc2;
AssertReturn(pvec->muTypeHash == uTypeHash, VERR_INVALID_PARAMETER);
if ( pvec->mcElements == pvec->mcCapacity
&& RT_FAILURE((rc2 = VEC_EXPAND(pvec))))
return rc2;
VEC_GET_ELEMENT_PTR(pvec->mpvaElements, pvec->mcElements) = pv;
++pvec->mcElements;
return VINF_SUCCESS;
}
/*** Public interface macros ***/
/**
* Initialise a vector structure. Always succeeds.
* @param pvec pointer to an uninitialised vector structure
* @param type the type of the objects in the vector. As this is
* hashed by the preprocessor use of space etc is
* important.
* @param pfnCleanup cleanup function (void (*pfn)(void *)) that is called
* on a pointer to a vector element when that element is
* dropped
*/
#define VEC_INIT_OBJ(pvec, type, pfnCleanup) \
vecInitObj(pvec, sizeof(type), VECTOR_TOKEN_HASH(type), \
(void (*)(void*)) pfnCleanup)
/**
* Initialise a vector-of-pointers structure. Always succeeds.
* @param pvec pointer to an uninitialised vector structure
* @param type the type of the pointers in the vector, including the
* final "*". As this is hashed by the preprocessor use
* of space etc is important.
* @param pfnCleanup cleanup function (void (*pfn)(void *)) that is called
* directly on a vector element when that element is
* dropped
*/
#define VEC_INIT_PTR(pvec, type, pfnCleanup) \
vecInitPtr(pvec, sizeof(type), VECTOR_TOKEN_HASH(type), \
(void (*)(void*)) pfnCleanup)
/**
* Clean up a vector.
* @param pvec pointer to the vector to clean up. The clean up function
* specified at initialisation (if any) is called for each element
* in the vector. After clean up, the vector structure is invalid
* until it is re-initialised
*/
#define VEC_CLEANUP_OBJ vecCleanupObj
/**
* Clean up a vector-of-pointers.
* @param pvec pointer to the vector to clean up. The clean up function
* specified at initialisation (if any) is called for each element
* in the vector. After clean up, the vector structure is invalid
* until it is re-initialised
*/
#define VEC_CLEANUP_PTR vecCleanupPtr
/**
* Reinitialises a vector structure to empty.
* @param pvec pointer to the vector to re-initialise. The clean up function
* specified at initialisation (if any) is called for each element
* in the vector.
*/
#define VEC_CLEAR_OBJ vecClearObj
/**
* Reinitialises a vector-of-pointers structure to empty.
* @param pvec pointer to the vector to re-initialise. The clean up function
* specified at initialisation (if any) is called for each element
* in the vector.
*/
#define VEC_CLEAR_PTR vecClearPtr
/**
* Adds an element to the back of a vector. The element will be byte-copied
* and become owned by the vector, to be cleaned up by the vector's clean-up
* routine when the element is dropped.
* @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
* @returns VERR_INVALID_PARAMETER if the type does not match the type given
* when the vector was initialised (asserted)
* @param pvec pointer to the vector on to which the element should be
* added
* @param type the type of the vector as specified at initialisation.
* Spacing etc is important.
* @param pvElement void pointer to the element to be added
*/
#define VEC_PUSH_BACK_OBJ(pvec, type, pvElement) \
vecPushBackObj(pvec, VECTOR_TOKEN_HASH(type), \
(pvElement) + ((pvElement) - (type *)(pvElement)))
/**
* Adds a pointer to the back of a vector-of-pointers. The pointer will become
* owned by the vector, to be cleaned up by the vector's clean-up routine when
* it is dropped.
* @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
* @returns VERR_INVALID_PARAMETER if the type does not match the type given
* when the vector was initialised (asserted)
* @param pvec pointer to the vector on to which the element should be
* added
* @param type the type of the vector as specified at initialisation.
* Spacing etc is important.
* @param pvElement the pointer to be added, typecast to pointer-to-void
*/
#define VEC_PUSH_BACK_PTR(pvec, type, pvElement) \
vecPushBackPtr(pvec, VECTOR_TOKEN_HASH(type), \
(pvElement) + ((pvElement) - (type)(pvElement)))
/**
* Returns the count of elements in a vector.
* @param pvec pointer to the vector.
*/
#define VEC_SIZE_OBJ(pvec) (pvec)->mcElements
/**
* Returns the count of elements in a vector-of-pointers.
* @param pvec pointer to the vector.
*/
#define VEC_SIZE_PTR VEC_SIZE_OBJ
/**
* Iterates over the vector elements from first to last and execute the
* following instruction or block on each iteration with @a pIterator set to
* point to the current element (that is, a pointer to the pointer element for
* a vector-of-pointers). Use in the same way as a "for" statement.
* @param pvec pointer to the vector to be iterated over
* @param type the type of the vector, must match the type specified at
* vector initialisation (including whitespace etc)
* @todo can we assert the correctness of the type in some way?
* @param pIterator a pointer to @a type which will be set to point to the
* current vector element on each iteration
*/
#define VEC_FOR_EACH(pvec, type, pIterator) \
for (pIterator = (type *) (pvec)->mpvaElements; \
(pvec)->muTypeHash == VECTOR_TOKEN_HASH(type) \
&& pIterator < (type *) (pvec)->mpvaElements + (pvec)->mcElements; \
++pIterator)
#endif /* MAIN_VECTOR_H */