vec.h, vec.c: New, type safe vector API.
* vec.h, vec.c: New, type safe vector API. * Makefile.in (OBJS-common): Add vec.o. (vec.o): New target. (gengtype-lex.o): Depend on vec.h. From-SVN: r83769
This commit is contained in:
parent
2851dd684b
commit
ada5515102
5 changed files with 824 additions and 3 deletions
|
@ -1,3 +1,10 @@
|
|||
2004-06-28 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* vec.h, vec.c: New, type safe vector API.
|
||||
* Makefile.in (OBJS-common): Add vec.o.
|
||||
(vec.o): New target.
|
||||
(gengtype-lex.o): Depend on vec.h.
|
||||
|
||||
2004-06-28 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
* fold-const.c (fold_cond_expr_with_comparison): Add ARG1
|
||||
|
|
|
@ -914,7 +914,7 @@ OBJS-common = \
|
|||
sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \
|
||||
simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \
|
||||
targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o \
|
||||
varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \
|
||||
varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \
|
||||
et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \
|
||||
rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o
|
||||
|
||||
|
@ -1990,6 +1990,7 @@ global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS
|
|||
toplev.h $(TM_P_H)
|
||||
varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h $(GGC_H) errors.h \
|
||||
$(HASHTAB_H)
|
||||
vec.o : vec.c $(CONFIG_H) coretypes.h vec.h ggc.h errors.h
|
||||
ra.o : ra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TM_P_H) insn-config.h \
|
||||
$(RECOG_H) $(INTEGRATE_H) function.h $(REGS_H) $(OBSTACK_H) hard-reg-set.h \
|
||||
$(BASIC_BLOCK_H) $(DF_H) $(EXPR_H) output.h toplev.h $(FLAGS_H) reload.h $(RA_H)
|
||||
|
@ -2515,7 +2516,7 @@ gengtype.o : gengtype.c gengtype.h $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H)
|
|||
real.h $(RTL_BASE_H) gtyp-gen.h
|
||||
|
||||
gengtype-lex.o : gengtype-lex.c gengtype.h gengtype-yacc.h \
|
||||
$(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H)
|
||||
$(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) vec.h
|
||||
$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) \
|
||||
$< $(OUTPUT_OPTION)
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include "gengtype.h"
|
||||
#include "gengtype-yacc.h"
|
||||
|
||||
#define YY_INPUT(BUF,RESULT,SIZE) ((RESULT) = macro_input (BUF,SIZE))
|
||||
|
||||
static unsigned macro_input (char *buffer, unsigned);
|
||||
static void push_macro_expansion (const char *, unsigned,
|
||||
const char *, unsigned);
|
||||
static void update_lineno (const char *l, size_t len);
|
||||
|
||||
struct fileloc lexer_line;
|
||||
|
@ -218,6 +223,35 @@ ITYPE {IWORD}({WS}{IWORD})*
|
|||
return ENT_YACCUNION;
|
||||
}
|
||||
|
||||
^"DEF_VEC_"[[:alnum:]_]*{WS}?"("{WS}?{ID}{WS}?")" {
|
||||
char *macro, *arg;
|
||||
unsigned macro_len, arg_len;
|
||||
char *ptr = yytext;
|
||||
type_p t;
|
||||
|
||||
/* Locate the macro and argument strings. */
|
||||
macro = ptr;
|
||||
while (*ptr != '(' && !ISSPACE (*ptr))
|
||||
ptr++;
|
||||
macro_len = ptr - macro;
|
||||
while (*ptr == '(' || ISSPACE (*ptr))
|
||||
ptr++;
|
||||
arg = ptr;
|
||||
while (*ptr != ')' && !ISSPACE (*ptr))
|
||||
ptr++;
|
||||
arg_len = ptr - arg;
|
||||
|
||||
/* Push the macro for later expansion. */
|
||||
push_macro_expansion (macro, macro_len, arg, arg_len);
|
||||
|
||||
/* Create the struct and typedef. */
|
||||
ptr = xmemdup ("VEC_", 4, 4 + arg_len + 1);
|
||||
memcpy (&ptr[4], arg, arg_len);
|
||||
ptr[4 + arg_len] = 0;
|
||||
t = find_structure (ptr, 0);
|
||||
do_typedef (ptr, t, &lexer_line);
|
||||
}
|
||||
|
||||
<in_struct>{
|
||||
|
||||
"/*" { BEGIN(in_struct_comment); }
|
||||
|
@ -229,7 +263,6 @@ ITYPE {IWORD}({WS}{IWORD})*
|
|||
{WS} { update_lineno (yytext, yyleng); }
|
||||
|
||||
"const"/[^[:alnum:]_] /* don't care */
|
||||
|
||||
"GTY"/[^[:alnum:]_] { return GTY_TOKEN; }
|
||||
"union"/[^[:alnum:]_] { return UNION; }
|
||||
"struct"/[^[:alnum:]_] { return STRUCT; }
|
||||
|
@ -254,6 +287,28 @@ ITYPE {IWORD}({WS}{IWORD})*
|
|||
return SCALAR;
|
||||
}
|
||||
|
||||
"VEC"{WS}?"("{WS}?{ID}{WS}?")" {
|
||||
char *macro, *arg;
|
||||
unsigned macro_len, arg_len;
|
||||
char *ptr = yytext;
|
||||
|
||||
macro = ptr;
|
||||
while (*ptr != '(' && !ISSPACE (*ptr))
|
||||
ptr++;
|
||||
macro_len = ptr - macro;
|
||||
while (*ptr == '(' || ISSPACE (*ptr))
|
||||
ptr++;
|
||||
arg = ptr;
|
||||
while (*ptr != ')' && !ISSPACE (*ptr))
|
||||
ptr++;
|
||||
arg_len = ptr - arg;
|
||||
ptr = xmemdup (macro, macro_len, macro_len + arg_len + 2);
|
||||
ptr[macro_len] = '_';
|
||||
memcpy (&ptr[macro_len+1], arg, arg_len);
|
||||
yylval.s = ptr;
|
||||
return ID;
|
||||
}
|
||||
|
||||
{ID}/[^[:alnum:]_] {
|
||||
yylval.s = xmemdup (yytext, yyleng, yyleng+1);
|
||||
return ID;
|
||||
|
@ -340,6 +395,93 @@ ITYPE {IWORD}({WS}{IWORD})*
|
|||
|
||||
%%
|
||||
|
||||
/* Deal with the expansion caused by the DEF_VEC_x macros. */
|
||||
|
||||
typedef struct macro
|
||||
{
|
||||
const char *name;
|
||||
const char *expansion;
|
||||
struct macro *next;
|
||||
} macro_t;
|
||||
|
||||
static const macro_t macro_defs[] =
|
||||
{
|
||||
#define IN_GENGTYPE 1
|
||||
#include "vec.h"
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Chain of macro expansions to do at end of scanning. */
|
||||
static macro_t *macro_expns;
|
||||
|
||||
/* Push macro NAME (NAME_LEN) with argument ARG (ARG_LEN) onto the
|
||||
expansion queue. We ensure NAME is known at this point. */
|
||||
|
||||
static void
|
||||
push_macro_expansion (const char *name, unsigned name_len,
|
||||
const char *arg, unsigned arg_len)
|
||||
{
|
||||
unsigned ix;
|
||||
|
||||
for (ix = 0; macro_defs[ix].name; ix++)
|
||||
if (strlen (macro_defs[ix].name) == name_len
|
||||
&& !memcmp (name, macro_defs[ix].name, name_len))
|
||||
{
|
||||
macro_t *expansion = xmalloc (sizeof (*expansion));
|
||||
|
||||
expansion->next = macro_expns;
|
||||
expansion->name = xmemdup (arg, arg_len, arg_len+1);
|
||||
expansion->expansion = macro_defs[ix].expansion;
|
||||
macro_expns = expansion;
|
||||
return;
|
||||
}
|
||||
error_at_line (&lexer_line, "unrecognized macro `%.*s(%.*s)'",
|
||||
name_len, name, arg_len, arg);
|
||||
}
|
||||
|
||||
/* Attempt to read some input. Use fread until we're at the end of
|
||||
file. At end of file expand the next queued macro. We presume the
|
||||
buffer is large enough for the entire expansion. */
|
||||
|
||||
static unsigned
|
||||
macro_input (char *buffer, unsigned size)
|
||||
{
|
||||
unsigned result;
|
||||
|
||||
result = fread (buffer, 1, size, yyin);
|
||||
if (result)
|
||||
/*NOP*/;
|
||||
else if (ferror (yyin))
|
||||
YY_FATAL_ERROR ("read of source file failed");
|
||||
else if (macro_expns)
|
||||
{
|
||||
const char *expn;
|
||||
unsigned len;
|
||||
|
||||
for (expn = macro_expns->expansion; *expn; expn++)
|
||||
{
|
||||
if (*expn == '#')
|
||||
{
|
||||
if (buffer[result-1] == ' ' && buffer[result-2] == '_')
|
||||
result--;
|
||||
len = strlen (macro_expns->name);
|
||||
memcpy (&buffer[result], macro_expns->name, len);
|
||||
result += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[result++] = *expn;
|
||||
if (*expn == ';' || *expn == '{')
|
||||
buffer[result++] = '\n';
|
||||
}
|
||||
}
|
||||
if (result > size)
|
||||
YY_FATAL_ERROR ("buffer too small to expand macro");
|
||||
macro_expns = macro_expns->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror (const char *s)
|
||||
{
|
||||
|
|
104
gcc/vec.c
Normal file
104
gcc/vec.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* Vector API for GNU compiler.
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
Contributed by Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "ggc.h"
|
||||
#include "vec.h"
|
||||
#include "errors.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
||||
struct vec_prefix
|
||||
{
|
||||
size_t num;
|
||||
size_t alloc;
|
||||
void *vec[1];
|
||||
};
|
||||
|
||||
/* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
|
||||
~0u. If RESERVE == ~0u increase the current allocation
|
||||
exponentially. VEC can be NULL, to create a new vector. */
|
||||
|
||||
void *
|
||||
vec_p_reserve (void *vec, size_t reserve)
|
||||
{
|
||||
return vec_o_reserve (vec, reserve,
|
||||
offsetof (struct vec_prefix, vec), sizeof (void *));
|
||||
}
|
||||
|
||||
/* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
|
||||
~0u. If RESERVE == ~0u, increase the current allocation
|
||||
exponentially. VEC can be NULL, in which case a new vector is
|
||||
created. The vector's trailing array is at VEC_OFFSET offset and
|
||||
consistes of ELT_SIZE sized elements. */
|
||||
|
||||
void *
|
||||
vec_o_reserve (void *vec, size_t reserve, size_t vec_offset, size_t elt_size)
|
||||
{
|
||||
struct vec_prefix *pfx = vec;
|
||||
size_t alloc;
|
||||
|
||||
if (reserve + 1)
|
||||
alloc = (pfx ? pfx->num : 0) + reserve;
|
||||
else
|
||||
alloc = pfx ? pfx->alloc * 2 : 4;
|
||||
|
||||
if (!pfx || pfx->alloc < alloc)
|
||||
{
|
||||
vec = ggc_realloc (vec, vec_offset + alloc * elt_size);
|
||||
((struct vec_prefix *)vec)->alloc = alloc;
|
||||
if (!pfx)
|
||||
((struct vec_prefix *)vec)->num = 0;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
/* Allocate a structure which contains a vector as a trailing element.
|
||||
The vector is at STRUCT_OFFSET offset within the struct and the
|
||||
vector's array is at VEC_OFFSET offset within the vector. */
|
||||
|
||||
void *
|
||||
vec_embedded_alloc (size_t struct_offset, size_t vec_offset,
|
||||
size_t elt_size, size_t reserve)
|
||||
{
|
||||
void *ptr = ggc_alloc (struct_offset + vec_offset + elt_size * reserve);
|
||||
struct vec_prefix *pfx = (struct vec_prefix *)((char *)ptr + struct_offset);
|
||||
|
||||
pfx->num = 0;
|
||||
pfx->alloc = reserve;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#if ENABLE_CHECKING
|
||||
/* Issue a vector domain error, and then fall over. */
|
||||
|
||||
void
|
||||
vec_assert_fail (const char *op, const char *struct_name,
|
||||
const char *file, size_t line, const char *function)
|
||||
{
|
||||
internal_error ("vector %s %s domain error, in %s at %s:%u",
|
||||
struct_name, op, function, function,
|
||||
trim_filename (file), line);
|
||||
}
|
||||
#endif
|
567
gcc/vec.h
Normal file
567
gcc/vec.h
Normal file
|
@ -0,0 +1,567 @@
|
|||
/* Vector API for GNU compiler.
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
Contributed by Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifndef GCC_VEC_H
|
||||
#define GCC_VEC_H
|
||||
|
||||
/* The macros here implement a set of templated vector types and
|
||||
associated interfaces. These templates are implemented with
|
||||
macros, as we're not in C++ land. The interface functions are
|
||||
typesafe and use static inline functions, sometimes backed by
|
||||
out-of-line generic functions. The vectors are designed to
|
||||
interoperate with the GTY machinery.
|
||||
|
||||
Because of the different behaviour of objects and of pointers to
|
||||
objects, there are two flavours. One to deal with a vector of
|
||||
pointers to objects, and one to deal with a vector of objects
|
||||
themselves. Both of these pass pointers to objects around -- in
|
||||
the former case the pointers are stored into the vector and in the
|
||||
latter case the pointers are dereferenced and the objects copied
|
||||
into the vector. Therefore, when using a vector of pointers, the
|
||||
objects pointed to must be long lived, but when dealing with a
|
||||
vector of objects, the source objects need not be.
|
||||
|
||||
The vectors are implemented using the trailing array idiom, thus
|
||||
they are not resizeable without changing the address of the vector
|
||||
object itself. This means you cannot have variables or fields of
|
||||
vector type -- always use a pointer to a vector. The one exception
|
||||
is the final field of a structure, which could be a vector type.
|
||||
You will have to use the embedded_alloc call to create such
|
||||
objects, and they will probably not be resizeable (so don't use the
|
||||
'safe' allocation variants). The trailing array idiom is used
|
||||
(rather than a pointer to an array of data), because, if we allow
|
||||
NULL to also represent an empty vector, empty vectors occupy
|
||||
minimal space in the structure containing them.
|
||||
|
||||
Each operation that increases the number of active elements is
|
||||
available in 'quick' and 'safe' variants. The former presumes that
|
||||
there is sufficient allocated space for the operation to succeed
|
||||
(it aborts if there is not). The latter will reallocate the
|
||||
vector, if needed. Reallocation causes an exponential increase in
|
||||
vector size. If you know you will be adding N elements, it would
|
||||
be more efficient to use the reserve operation before adding the
|
||||
elements with the 'quick' operation.
|
||||
|
||||
You should prefer the push and pop operations, as they append and
|
||||
remove from the end of the vector. The insert and remove
|
||||
operations allow you to change elements in the middle of the
|
||||
vector. There are two remove operations, one which preserves the
|
||||
element ordering 'ordered_remove', and one which does not
|
||||
'unordered_remove'. The latter function copies the end element
|
||||
into the removed slot, rather than invoke a memmove operation.
|
||||
|
||||
Vector types are defined using a DEF_VEC_x(TYPEDEF) macro, and
|
||||
variables of vector type are declared using a VEC(TYPEDEF)
|
||||
macro. The 'x' letter indicates whether TYPEDEF is a pointer (P) or
|
||||
object (O) type.
|
||||
|
||||
An example of their use would be,
|
||||
|
||||
DEF_VEC_P(tree); // define a vector of tree pointers. This must
|
||||
// appear at file scope.
|
||||
|
||||
struct my_struct {
|
||||
VEC(tree) *v; // A (pointer to) a vector of tree pointers.
|
||||
};
|
||||
|
||||
struct my_struct *s;
|
||||
|
||||
if (VEC_length(tree,s)) { we have some contents }
|
||||
VEC_safe_push(tree,s,decl); // append some decl onto the end
|
||||
for (ix = 0; (t = VEC_iterate(tree,s,ix)); ix++)
|
||||
{ do something with t }
|
||||
|
||||
*/
|
||||
|
||||
/* Macros to invoke API calls. A single macro works for both pointer
|
||||
and object vectors, but the argument and return types might well be
|
||||
different. In each macro, TDEF is the typedef of the vector
|
||||
elements. Some of these macros pass the vector, V, by reference
|
||||
(by taking its address), this is noted in the descriptions. */
|
||||
|
||||
/* Length of vector
|
||||
size_t VEC_T_length(const VEC(T) *v);
|
||||
|
||||
Return the number of active elements in V. V can be NULL, in which
|
||||
case zero is returned. */
|
||||
#define VEC_length(TDEF,V) (VEC_OP(TDEF,length)(V))
|
||||
|
||||
/* Get the final element of the vector.
|
||||
T VEC_T_last(VEC(T) *v); // Pointer
|
||||
T *VEC_T_last(VEC(T) *v); // Object
|
||||
|
||||
Return the final element. If V is empty, abort. */
|
||||
#define VEC_last(TDEF,V) (VEC_OP(TDEF,last)(V))
|
||||
|
||||
/* Index into vector
|
||||
T VEC_T_index(VEC(T) *v, size_t ix); // Pointer
|
||||
T *VEC_T_index(VEC(T) *v, size_t ix); // Object
|
||||
|
||||
Return the IX'th element. If IX is outside the domain of V,
|
||||
abort. */
|
||||
#define VEC_index(TDEF,V,I) (VEC_OP(TDEF,index)(V,I))
|
||||
|
||||
/* Iterate over vector
|
||||
T VEC_T_index(VEC(T) *v, size_t ix); // Pointer
|
||||
T *VEC_T_index(VEC(T) *v, size_t ix); // Object
|
||||
|
||||
Return the IX'th element or NULL. Use this to iterate over the
|
||||
elements of a vector as follows,
|
||||
|
||||
for (ix = 0; (ptr = VEC_iterate(T,v,ix)); ix++)
|
||||
continue; */
|
||||
#define VEC_iterate(TDEF,V,I) (VEC_OP(TDEF,iterate)(V,I))
|
||||
|
||||
/* Allocate new vector.
|
||||
VEC(T) *VEC_T_alloc(size_t reserve);
|
||||
|
||||
Allocate a new vector with space for RESERVE objects. */
|
||||
#define VEC_alloc(TDEF,A) (VEC_OP(TDEF,alloc)(A))
|
||||
|
||||
/* Allocate new vector offset within a structure
|
||||
void *VEC_T_embedded_alloc(size_t offset, size_t reserve);
|
||||
|
||||
Allocate a new vector which is at offset OFFSET within a structure,
|
||||
and with space for RESERVE objects. Return a pointer to the start
|
||||
of the structure containing the vector. Naturally, the vector must
|
||||
be the last member of the structure. */
|
||||
#define VEC_embedded_alloc(TDEF,O,A) (VEC_OP(TDEF,embedded_alloc)(O,A))
|
||||
|
||||
/* Reserve space.
|
||||
void VEC_T_reserve(VEC(T) *&v, size_t reserve);
|
||||
|
||||
Ensure that V has at least RESERVE slots available. Note this can
|
||||
cause V to be reallocated. */
|
||||
#define VEC_reserve(TDEF,V,R) (VEC_OP(TDEF,reserve)(&(V),R))
|
||||
|
||||
/* Push object with no reallocation
|
||||
T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
|
||||
T *VEC_T_quick_push (VEC(T) *v, T *obj); // Object
|
||||
|
||||
Push a new element onto the end, returns a pointer to the slot
|
||||
filled in. For object vectors, the new value can be NULL, in which
|
||||
case NO initialization is performed. Aborts if there is
|
||||
insufficient space in the vector. */
|
||||
#define VEC_quick_push(TDEF,V,O) (VEC_OP(TDEF,quick_push)(V,O))
|
||||
|
||||
/* Push object with reallocation
|
||||
T *VEC_T_safe_push (VEC(T) *&v, T obj); // Pointer
|
||||
T *VEC_T_safe_push (VEC(T) *&v, T *obj); // Object
|
||||
|
||||
Push a new element onto the end, returns a pointer to the slot
|
||||
filled in. For object vectors, the new value can be NULL, in which
|
||||
case NO initialization is performed. Reallocates V, if needed. */
|
||||
#define VEC_safe_push(TDEF,V,O) (VEC_OP(TDEF,safe_push)(&(V),O))
|
||||
|
||||
/* Pop element off end
|
||||
T VEC_T_pop (VEC(T) *v); // Pointer
|
||||
void VEC_T_pop (VEC(T) *v); // Object
|
||||
|
||||
Pop the last element off the end. Returns the element popped, for
|
||||
pointer vectors. */
|
||||
#define VEC_pop(TDEF,V) (VEC_OP(TDEF,pop)(V))
|
||||
|
||||
/* Replace element
|
||||
T VEC_T_replace (VEC(T) *v, size_t ix, T val); // Pointer
|
||||
T *VEC_T_replace (VEC(T) *v, size_t ix, T *val); // Object
|
||||
|
||||
Replace the IXth element of V with a new value, VAL. For pointer
|
||||
vectors returns the original value. For object vectors returns a
|
||||
pointer to the new value. For object vectors the new value can be
|
||||
NULL, in which case no overwriting of the slot is actually
|
||||
performed. */
|
||||
#define VEC_replace(TDEF,V,I,O) (VEC_OP(TDEF,replace)(V,I,O))
|
||||
|
||||
/* Insert object with no reallocation
|
||||
T *VEC_T_quick_insert (VEC(T) *v, size_t ix, T val); // Pointer
|
||||
T *VEC_T_quick_insert (VEC(T) *v, size_t ix, T *val); // Object
|
||||
|
||||
Insert an element, VAL, at the IXth position of V. Return a pointer
|
||||
to the slot created. For vectors of object, the new value can be
|
||||
NULL, in which case no initialization of the inserted slot takes
|
||||
place. Aborts if there is insufficient space. */
|
||||
#define VEC_quick_insert(TDEF,V,I,O) (VEC_OP(TDEF,quick_insert)(V,I,O))
|
||||
|
||||
/* Insert object with reallocation
|
||||
T *VEC_T_safe_insert (VEC(T) *&v, size_t ix, T val); // Pointer
|
||||
T *VEC_T_safe_insert (VEC(T) *&v, size_t ix, T *val); // Object
|
||||
|
||||
Insert an element, VAL, at the IXth position of V. Return a pointer
|
||||
to the slot created. For vectors of object, the new value can be
|
||||
NULL, in which case no initialization of the inserted slot takes
|
||||
place. Reallocate V, if necessary. */
|
||||
#define VEC_safe_insert(TDEF,V,I,O) (VEC_OP(TDEF,safe_insert)(&(V),I,O))
|
||||
|
||||
/* Remove element retaining order
|
||||
T VEC_T_ordered_remove (VEC(T) *v, size_t ix); // Pointer
|
||||
void VEC_T_ordered_remove (VEC(T) *v, size_t ix); // Object
|
||||
|
||||
Remove an element from the IXth position of V. Ordering of
|
||||
remaining elements is preserverd. For pointer vectors returns the
|
||||
removed object. This is an O(N) operation due to a memmove. */
|
||||
#define VEC_ordered_remove(TDEF,V,I) (VEC_OP(TDEF,ordered_remove)(V,I))
|
||||
|
||||
/* Remove element destroying order
|
||||
T VEC_T_unordered_remove (VEC(T) *v, size_t ix); // Pointer
|
||||
void VEC_T_unordered_remove (VEC(T) *v, size_t ix); // Object
|
||||
|
||||
Remove an element from the IXth position of V. Ordering of
|
||||
remaining elements is destroyed. For pointer vectors returns the
|
||||
removed object. This is an O(1) operation. */
|
||||
#define VEC_unordered_remove(TDEF,V,I) (VEC_OP(TDEF,unordered_remove)(V,I))
|
||||
|
||||
#if !IN_GENGTYPE
|
||||
#include "auto-host.h"
|
||||
|
||||
/* Reallocate an array of elements with prefix. */
|
||||
extern void *vec_p_reserve (void *, size_t);
|
||||
extern void *vec_o_reserve (void *, size_t, size_t, size_t);
|
||||
extern void *vec_embedded_alloc (size_t, size_t, size_t, size_t);
|
||||
|
||||
#if ENABLE_CHECKING
|
||||
extern void vec_assert_fail (const char *, const char *,
|
||||
const char *, size_t, const char *)
|
||||
ATTRIBUTE_NORETURN;
|
||||
#define VEC_ASSERT_FAIL(OP,VEC) \
|
||||
vec_assert_fail (OP,#VEC,__FILE__,__LINE__,__FUNCTION__)
|
||||
|
||||
#define VEC_ASSERT(EXPR,OP,TDEF) \
|
||||
(void)((EXPR) ? 0 : (VEC_ASSERT_FAIL(OP,VEC(TDEF)), 0))
|
||||
#else
|
||||
#define VEC_ASSERT(EXPR,OP,TYPE) (void)(EXPR)
|
||||
#endif
|
||||
|
||||
#define VEC(TDEF) VEC_##TDEF
|
||||
#define VEC_OP(TDEF,OP) VEC_OP_(VEC(TDEF),OP)
|
||||
#define VEC_OP_(VEC,OP) VEC_OP__(VEC,OP)
|
||||
#define VEC_OP__(VEC,OP) VEC ## _ ## OP
|
||||
#else /* IN_GENGTYPE */
|
||||
#define VEC(TDEF) VEC_ TDEF
|
||||
#define VEC_STRINGIFY(X) VEC_STRINGIFY_(X)
|
||||
#define VEC_STRINGIFY_(X) #X
|
||||
#undef GTY
|
||||
#endif /* IN_GENGTYPE */
|
||||
|
||||
#define VEC_TDEF(TDEF) \
|
||||
typedef struct VEC (TDEF) GTY(()) \
|
||||
{ \
|
||||
size_t num; \
|
||||
size_t alloc; \
|
||||
TDEF GTY ((length ("%h.num"))) vec[1]; \
|
||||
} VEC (TDEF)
|
||||
|
||||
/* Vector of pointer to object. */
|
||||
#if IN_GENGTYPE
|
||||
{"DEF_VEC_P", VEC_STRINGIFY (VEC_TDEF (#)) ";", NULL},
|
||||
#else
|
||||
|
||||
#define DEF_VEC_P(TDEF) \
|
||||
VEC_TDEF (TDEF); \
|
||||
\
|
||||
static inline size_t VEC_OP (TDEF,length) \
|
||||
(const VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
return vec_ ? vec_->num : 0; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,last) \
|
||||
(const VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
VEC_ASSERT (vec_ && vec_->num, "last", TDEF); \
|
||||
\
|
||||
return vec_->vec[vec->num - 1]; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,index) \
|
||||
(const VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
VEC_ASSERT (vec_ && ix_ < vec_->num, "index", TDEF); \
|
||||
\
|
||||
return vec_->vec[ix_]; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,iterate) \
|
||||
(const VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
return vec_ && ix_ < vec_->num ? vec_->vec[ix_] : NULL; \
|
||||
} \
|
||||
\
|
||||
static inline VEC (TDEF) *VEC_OP (TDEF,alloc) \
|
||||
(size_t alloc_) \
|
||||
{ \
|
||||
return vec_p_reserve (NULL, alloc_ - !alloc_); \
|
||||
} \
|
||||
\
|
||||
static inline void *VEC_OP (TDEF,embedded_alloc) \
|
||||
(size_t offset_, size_t alloc_) \
|
||||
{ \
|
||||
return vec_embedded_alloc (offset_, offsetof (VEC(TDEF),vec), \
|
||||
sizeof (TDEF), alloc_); \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (TDEF,reserve) \
|
||||
(VEC (TDEF) **vec_, size_t alloc_) \
|
||||
{ \
|
||||
*vec_ = vec_p_reserve (*vec_, alloc_); \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,quick_push) \
|
||||
(VEC (TDEF) *vec_, TDEF obj_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (vec_->num < vec_->alloc, "push", TDEF); \
|
||||
slot_ = &vec_->vec[vec_->num++]; \
|
||||
*slot_ = obj_; \
|
||||
\
|
||||
return slot_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,safe_push) \
|
||||
(VEC (TDEF) **vec_, TDEF obj_) \
|
||||
{ \
|
||||
if (!*vec_ || (*vec_)->num == (*vec_)->alloc) \
|
||||
VEC_OP (TDEF,reserve) (vec_, ~0u); \
|
||||
\
|
||||
return VEC_OP (TDEF,quick_push) (*vec_, obj_); \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,pop) \
|
||||
(VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
TDEF obj_; \
|
||||
\
|
||||
VEC_ASSERT (vec_->num, "pop", TDEF); \
|
||||
obj_ = vec_->vec[--vec_->num]; \
|
||||
\
|
||||
return obj_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,replace) \
|
||||
(VEC (TDEF) *vec_, size_t ix_, TDEF obj_) \
|
||||
{ \
|
||||
TDEF old_obj_; \
|
||||
\
|
||||
VEC_ASSERT (ix_ < vec_->num, "replace", TDEF); \
|
||||
old_obj_ = vec_->vec[ix_]; \
|
||||
vec_->vec[ix_] = obj_; \
|
||||
\
|
||||
return old_obj_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,quick_insert) \
|
||||
(VEC (TDEF) *vec_, size_t ix_, TDEF obj_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (vec_->num < vec_->alloc, "insert", TDEF); \
|
||||
VEC_ASSERT (ix_ <= vec_->num, "insert", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
memmove (slot_ + 1, slot_, vec_->num++ - ix_); \
|
||||
*slot_ = obj_; \
|
||||
\
|
||||
return slot_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,safe_insert) \
|
||||
(VEC (TDEF) **vec_, size_t ix_, TDEF obj_) \
|
||||
{ \
|
||||
if (!*vec_ || (*vec_)->num == (*vec_)->alloc) \
|
||||
VEC_OP (TDEF,reserve) (vec_, ~0u); \
|
||||
\
|
||||
return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_); \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,ordered_remove) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
TDEF obj_; \
|
||||
\
|
||||
VEC_ASSERT (ix_ < vec_->num, "remove", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
obj_ = *slot_; \
|
||||
memmove (slot_, slot_ + 1, --vec_->num - ix_); \
|
||||
\
|
||||
return obj_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF VEC_OP (TDEF,unordered_remove) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
TDEF obj_; \
|
||||
\
|
||||
VEC_ASSERT (ix_ < vec_->num, "remove", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
obj_ = *slot_; \
|
||||
*slot_ = vec_->vec[--vec_->num]; \
|
||||
\
|
||||
return obj_; \
|
||||
} \
|
||||
\
|
||||
struct vec_swallow_trailing_semi
|
||||
#endif
|
||||
|
||||
/* Vector of object. */
|
||||
#if IN_GENGTYPE
|
||||
{"DEF_VEC_O", VEC_STRINGIFY (VEC_TDEF (#)) ";", NULL},
|
||||
#else
|
||||
|
||||
#define DEF_VEC_O(TDEF) \
|
||||
VEC_TDEF (TDEF); \
|
||||
\
|
||||
static inline size_t VEC_OP (TDEF,length) \
|
||||
(const VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
return vec_ ? vec_->num : 0; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,last) \
|
||||
(VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
VEC_ASSERT (vec_ && vec_->num, "last", TDEF); \
|
||||
\
|
||||
return &vec_->vec[vec_->num - 1]; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,index) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
VEC_ASSERT (vec_ && ix_ < vec_->num, "index", TDEF); \
|
||||
\
|
||||
return &vec_->vec[ix_]; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,iterate) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
return vec_ && ix_ < vec_->num ? &vec_->vec[ix_] : NULL; \
|
||||
} \
|
||||
\
|
||||
static inline VEC (TDEF) *VEC_OP (TDEF,alloc) \
|
||||
(size_t alloc_) \
|
||||
{ \
|
||||
return vec_o_reserve (NULL, alloc_ - !alloc_, \
|
||||
offsetof (VEC(TDEF),vec), sizeof (TDEF)); \
|
||||
} \
|
||||
\
|
||||
static inline void *VEC_OP (TDEF,embedded_alloc) \
|
||||
(size_t offset_, size_t alloc_) \
|
||||
{ \
|
||||
return vec_embedded_alloc (offset_, offsetof (VEC(TDEF),vec), \
|
||||
sizeof (TDEF), alloc_); \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (TDEF,reserve) \
|
||||
(VEC (TDEF) **vec_, size_t alloc_) \
|
||||
{ \
|
||||
*vec_ = vec_o_reserve (*vec_, alloc_, \
|
||||
offsetof (VEC(TDEF),vec), sizeof (TDEF)); \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,quick_push) \
|
||||
(VEC (TDEF) *vec_, const TDEF *obj_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (vec_->num < vec_->alloc, "push", TDEF); \
|
||||
slot_ = &vec_->vec[vec_->num++]; \
|
||||
if (obj_) \
|
||||
*slot_ = *obj_; \
|
||||
\
|
||||
return slot_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,safe_push) \
|
||||
(VEC (TDEF) **vec_, const TDEF *obj_) \
|
||||
{ \
|
||||
if (!*vec_ || (*vec_)->num == (*vec_)->alloc) \
|
||||
VEC_OP (TDEF,reserve) (vec_, ~0u); \
|
||||
\
|
||||
return VEC_OP (TDEF,quick_push) (*vec_, obj_); \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (TDEF,pop) \
|
||||
(VEC (TDEF) *vec_) \
|
||||
{ \
|
||||
VEC_ASSERT (vec_->num, "pop", TDEF); \
|
||||
vec_->vec[--vec_->num]; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,replace) \
|
||||
(VEC (TDEF) *vec_, size_t ix_, const TDEF *obj_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (ix_ < vec_->num, "replace", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
if (obj_) \
|
||||
*slot_ = *obj_; \
|
||||
\
|
||||
return slot_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,quick_insert) \
|
||||
(VEC (TDEF) *vec_, size_t ix_, const TDEF *obj_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (vec_->num < vec_->alloc, "insert", TDEF); \
|
||||
VEC_ASSERT (ix_ <= vec_->num, "insert", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
memmove (slot_ + 1, slot_, vec_->num++ - ix_); \
|
||||
if (obj_) \
|
||||
*slot_ = *obj_; \
|
||||
\
|
||||
return slot_; \
|
||||
} \
|
||||
\
|
||||
static inline TDEF *VEC_OP (TDEF,safe_insert) \
|
||||
(VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_) \
|
||||
{ \
|
||||
if (!*vec_ || (*vec_)->num == (*vec_)->alloc) \
|
||||
VEC_OP (TDEF,reserve) (vec_, ~0u); \
|
||||
\
|
||||
return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_); \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (TDEF,ordered_remove) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
TDEF *slot_; \
|
||||
\
|
||||
VEC_ASSERT (ix_ < vec_->num, "remove", TDEF); \
|
||||
slot_ = &vec_->vec[ix_]; \
|
||||
memmove (slot_, slot_ + 1, --vec_->num - ix_); \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (TDEF,unordered_remove) \
|
||||
(VEC (TDEF) *vec_, size_t ix_) \
|
||||
{ \
|
||||
VEC_ASSERT (ix_ < vec_->num, "remove", TDEF); \
|
||||
vec_->vec[ix_] = vec_->vec[--vec_->num]; \
|
||||
} \
|
||||
\
|
||||
struct vec_swallow_trailing_semi
|
||||
#endif
|
||||
|
||||
#endif /* GCC_VEC_H */
|
Loading…
Add table
Reference in a new issue