Il s'agit d'une implémentation d'un tableau évolutif std::vector
, mais en code C89 simple. Le résultat est un tableau dynamique de type sûr, facile à utiliser et doté d'un ensemble d'opérations familier.
Il fonctionne en utilisant la même astuce que de nombreux allocateurs, qui consiste à allouer légèrement plus de données que demandé et à utiliser ce remplissage supplémentaire à l'avant comme stockage pour les métadonnées. Ainsi, tout vecteur non nul ressemble à ceci en mémoire :
+-----------------+------+----------+---------+
| elem_destructor | size | capacity | data... |
+-----------------+------+----------+---------+
^
| user's pointer
Où l'utilisateur reçoit un pointeur vers le premier élément de data
. De cette façon, le code a un accès trivial aux métadonnées nécessaires, mais l'utilisateur n'a pas besoin de se soucier de ces détails. La surcharge totale est 2 * sizeof(size_t) + sizeof(void (*)(void *))
par vecteur.
Pour permettre au code d'être au maximum générique, il est implémenté comme toutes les macros, et n'est donc qu'un en-tête. L'utilisation est simple :
/* if this is defined, then the vector will double in capacity each
* time it runs out of space. if it is not defined, then the vector will
* be conservative, and will have a capcity no larger than necessary.
* having this defined will minimize how often realloc gets called.
*/
#define CVECTOR_LOGARITHMIC_GROWTH
#include "cvector.h"
#include <stdio.h>
int main ( int argc , char * argv []) {
/* this is the variable that will store the array, you can have
* a vector of any type! For example, you may write float *v = NULL,
* and you'd have a vector of floats :-). NULL will have a size
* and capacity of 0. Additionally, vector_begin and vector_end will
* return NULL on a NULL vector. Alternatively, for clarity of writing
* you can use the cvector_vector_type macro to define a vector of a
* given type.
*/
cvector_vector_type ( int ) v = NULL ;
( void ) argc ;
( void ) argv ;
/* add some elements to the back */
cvector_push_back ( v , 10 );
cvector_push_back ( v , 20 );
cvector_push_back ( v , 30 );
cvector_push_back ( v , 40 );
/* remove an element by specifying an array subscript */
cvector_erase ( v , 2 );
/* remove an element from the back */
cvector_pop_back ( v );
/* print out some stats about the vector */
printf ( "pointer : %pn" , ( void * ) v );
printf ( "capacity: %lun" , cvector_capacity ( v ));
printf ( "size : %lun" , cvector_size ( v ));
/* iterator over the vector using "iterator" style */
if ( v ) {
int * it ;
int i = 0 ;
for ( it = cvector_begin ( v ); it != cvector_end ( v ); ++ it ) {
printf ( "v[%d] = %dn" , i , * it );
++ i ;
}
}
/* iterator over the vector standard indexing too! */
if ( v ) {
size_t i ;
for ( i = 0 ; i < cvector_size ( v ); ++ i ) {
printf ( "v[%lu] = %dn" , i , v [ i ]);
}
}
/* well, we don't have destructors, so let's clean things up */
cvector_free ( v );
return 0 ;
}
std::vector | cvector |
---|---|
std::vector<int> v | cvector(int) v |
Destructeur | cvector_free(v) |
v.at(3) | cvector_at(v, 3) |
v[3] | v[3] |
v.front() | cvector_front(v) |
v.back() | cvector_back(v) |
v.begin() | cvector_begin(v) |
v.end() | cvector_end(v) |
v.empty() | cvector_empty(v) |
v.size() | cvector_size(v) |
v.capacity() | cvector_capacity(v) |
v.shrink_to_fit() | cvector_shrink_to_fit(v) |
v.clear() | cvector_clear(v) |
v.insert(pos, value) | cvector_insert(v, pos, value) |
v.erase(v.begin() + 2) | cvector_erase(v, 2) |
v.push_back(value) | cvector_push_back(v, value) |
v.pop_back() | cvector_pop_back(v) |
v.reserve(new_cap) | cvector_reserve(v, new_cap) |
v.resize(count) | cvector_resize(v, count) |
v.swap(other) | cvector_swap(v, other) |
std::vector<int> other = v; | cvector(int) other; cvector_copy(v, other); |