2006-09-21 Nathan Sidwell <nathan@codesourcery.com>

gdb/
	* vec.h: New file.
	* vec.c: New file.
	* Makefile.in (SFILES): Add vec.c.
	(vec_h): New.
	(COMMON_OBJS): Add vec.o.
	(vec.o): New target.
gdb/doc/
	* gdbint.texinfo (Array Containers): New section.
This commit is contained in:
Daniel Jacobowitz 2006-09-21 13:47:56 +00:00
parent 5bd4b6af45
commit 350da6eece
6 changed files with 1312 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2006-09-21 Nathan Sidwell <nathan@codesourcery.com>
* vec.h: New file.
* vec.c: New file.
* Makefile.in (SFILES): Add vec.c.
(vec_h): New.
(COMMON_OBJS): Add vec.o.
(vec.o): New target.
2006-09-20 Daniel Jacobowitz <dan@codesourcery.com>
PR remote/2154

View File

@ -560,7 +560,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
typeprint.c \
ui-out.c utils.c ui-file.h ui-file.c \
user-regs.c \
valarith.c valops.c valprint.c value.c varobj.c \
valarith.c valops.c valprint.c value.c varobj.c vec.c \
wrapper.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@ -816,6 +816,7 @@ value_h = value.h $(doublest_h) $(frame_h) $(symtab_h) $(gdbtypes_h) \
$(expression_h)
varobj_h = varobj.h $(symtab_h) $(gdbtypes_h)
vax_tdep_h = vax-tdep.h
vec_h = vec.h $(gdb_assert_h) $(gdb_string_h)
version_h = version.h
wince_stub_h = wince-stub.h
wrapper_h = wrapper.h $(gdb_h)
@ -941,7 +942,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
ada-lang.o c-lang.o f-lang.o objc-lang.o \
ui-out.o cli-out.o \
varobj.o wrapper.o \
varobj.o vec.o wrapper.o \
jv-lang.o jv-valprint.o jv-typeprint.o \
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
scm-exp.o scm-lang.o scm-valprint.o \
@ -2826,6 +2827,7 @@ vax-tdep.o: vax-tdep.c $(defs_h) $(arch_utils_h) $(dis_asm_h) \
$(float_format_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \
$(gdbcore_h) $(gdbtypes_h) $(osabi_h) $(regcache_h) $(regset_h) \
$(trad_frame_h) $(value_h) $(gdb_string_h) $(vax_tdep_h)
vec.o: vec.c $(defs_h) $(vec_h)
win32-nat.o: win32-nat.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
$(exceptions_h) $(gdbcore_h) $(command_h) $(completer_h) \
$(regcache_h) $(top_h) $(buildsym_h) $(symfile_h) $(objfiles_h) \

View File

@ -1,3 +1,7 @@
2006-09-21 Nathan Sidwell <nathan@codesourcery.com>
* gdbint.texinfo (Array Containers): New section.
2006-09-17 Vladimir Prus <vladimir@codesourcery.com>
* gdb.texinfo (GDB/MI Stack Manipulation): Mention that

View File

@ -4913,6 +4913,181 @@ Regex conditionals.
@item sparc
@end table
@section Array Containers
@cindex Array Containers
@cindex VEC
Often it is necessary to manipulate a dynamic array of a set of
objects. C forces some bookkeeping on this, which can get cumbersome
and repetative. The @file{vec.h} file contains macros for defining
and using a typesafe vector type. The functions defined will be
inlined when compiling, and so the abstraction cost should be zero.
Domain checks are added to detect programming errors.
An example use would be an array of symbols or section information.
The array can be grown as symbols are read in (or preallocated), and
the accessor macros provided keep care of all the necessary
bookkeeping. Because the arrays are type safe, there is no danger of
accidentally mixing up the contents. Think of these as C++ templates,
but implemented in C.
Because of the different behavior of structure objects, scalar objects
and of pointers, there are three flavors of vector, one for each of
these variants. Both the structure object and pointer variants 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. The scalar
object variant is suitable for @code{int}-like objects, and the vector
elements are returned by value.
There are both @code{index} and @code{iterate} accessors. The iterator
returns a boolean iteration condition and updates the iteration
variable passed by reference. Because the iterator will be inlined,
the address-of can be optimized away.
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 @code{embedded_size} & @code{embedded_init} calls to create
such objects, and they will probably not be resizeable (so don't use
the @dfn{safe} allocation variants). The trailing array idiom is used
(rather than a pointer to an array of data), because, if we allow
@code{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 @dfn{quick} and @dfn{safe} variants. The former presumes
that there is sufficient allocated space for the operation to succeed
(it dies 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
@dfn{quick} operation. This will ensure there are at least as many
elements as you ask for, it will exponentially increase if there are
too few spare slots. If you want reserve a specific number of slots,
but do not want the exponential increase (for instance, you know this
is the last allocation), use a negative number for reservation. You
can also create a vector of a specific size from the get go.
You should prefer the push and pop operations, as they append and
remove from the end of the vector. If you need to remove several items
in one go, use the truncate operation. 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 @code{ordered_remove}, and one which does not
@code{unordered_remove}. The latter function copies the end element
into the removed slot, rather than invoke a memmove operation. The
@code{lower_bound} function will determine where to place an item in
the array using insert that will maintain sorted order.
If you need to directly manipulate a vector, then the @code{address}
accessor will return the address of the start of the vector. Also the
@code{space} predicate will tell you whether there is spare capacity in the
vector. You will not normally need to use these two functions.
Vector types are defined using a
@code{DEF_VEC_@{O,P,I@}(@var{typename})} macro. Variables of vector
type are declared using a @code{VEC(@var{typename})} macro. The
characters @code{O}, @code{P} and @code{I} indicate whether
@var{typename} is an object (@code{O}), pointer (@code{P}) or integral
(@code{I}) type. Be careful to pick the correct one, as you'll get an
awkward and inefficient API if you use the wrong one. There is a
check, which results in a compile-time warning, for the @code{P} and
@code{I} versions, but there is no check for the @code{O} versions, as
that is not possible in plain C.
An example of their use would be,
@smallexample
DEF_VEC_P(tree); // non-managed tree vector.
struct my_struct @{
VEC(tree) *v; // A (pointer to) a vector of tree pointers.
@};
struct my_struct *s;
if (VEC_length(tree, s->v)) @{ we have some contents @}
VEC_safe_push(tree, s->v, decl); // append some decl onto the end
for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++)
@{ do something with elt @}
@end smallexample
The @file{vec.h} file provides details on how to invoke the various
accessors provided. They are enumerated here:
@table @code
@item VEC_length
Return the number of items in the array,
@item VEC_empty
Return true if the array has no elements.
@item VEC_last
@itemx VEC_index
Return the last or arbitrary item in the array.
@item VEC_iterate
Access an array element and indicate whether the array has been
traversed.
@item VEC_alloc
@itemx VEC_free
Create and destroy an array.
@item VEC_embedded_size
@itemx VEC_embedded_init
Helpers for embedding an array as the final element of another struct.
@item VEC_copy
Duplicate an array.
@item VEC_space
Return the amount of free space in an array.
@item VEC_reserve
Ensure a certain amount of free space.
@item VEC_quick_push
@itemx VEC_safe_push
Append to an array, either assuming the space is available, or making
sure that it is.
@item VEC_pop
Remove the last item from an array.
@item VEC_truncate
Remove several items from the end of an array.
@item VEC_safe_grow
Add several items to the end of an array.
@item VEC_replace
Overwrite an item in the array.
@item VEC_quick_insert
@itemx VEC_safe_insert
Insert an item into the middle of the array. Either the space must
already exist, or the space is created.
@item VEC_ordered_remove
@itemx VEC_unordered_remove
Remove an item from the array, preserving order or not.
@item VEC_block_remove
Remove a set of items from the array.
@item VEC_address
Provide the address of the first element.
@item VEC_lower_bound
Binary search the array.
@end table
@section include
@node Coding

120
gdb/vec.c Normal file
View File

@ -0,0 +1,120 @@
/* Vector API for GDB.
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Nathan Sidwell <nathan@codesourcery.com>
This file is part of GDB.
This program 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 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#include "vec.h"
#include "defs.h"
struct vec_prefix
{
unsigned num;
unsigned alloc;
void *vec[1];
};
/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots
are free. If RESERVE < 0 grow exactly, otherwise grow
exponentially. */
static inline unsigned
calculate_allocation (const struct vec_prefix *pfx, int reserve)
{
unsigned alloc = 0;
unsigned num = 0;
if (pfx)
{
alloc = pfx->alloc;
num = pfx->num;
}
else if (!reserve)
/* If there's no prefix, and we've not requested anything, then we
will create a NULL vector. */
return 0;
/* We must have run out of room. */
gdb_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve));
if (reserve < 0)
/* Exact size. */
alloc = num + -reserve;
else
{
/* Exponential growth. */
if (!alloc)
alloc = 4;
else if (alloc < 16)
/* Double when small. */
alloc = alloc * 2;
else
/* Grow slower when large. */
alloc = (alloc * 3 / 2);
/* If this is still too small, set it to the right size. */
if (alloc < num + reserve)
alloc = num + reserve;
}
return alloc;
}
/* Ensure there are at least abs(RESERVE) free slots in VEC. If
RESERVE < 0 grow exactly, else grow exponentially. As a special
case, if VEC is NULL, and RESERVE is 0, no vector will be created. */
void *
vec_p_reserve (void *vec, int reserve)
{
return vec_o_reserve (vec, reserve,
offsetof (struct vec_prefix, vec), sizeof (void *));
}
/* As vec_p_reserve, but for object vectors. The vector's trailing
array is at VEC_OFFSET offset and consists of ELT_SIZE sized
elements. */
void *
vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size)
{
struct vec_prefix *pfx = vec;
unsigned alloc = calculate_allocation (pfx, reserve);
if (!alloc)
return NULL;
vec = xrealloc (vec, vec_offset + alloc * elt_size);
((struct vec_prefix *)vec)->alloc = alloc;
if (!pfx)
((struct vec_prefix *)vec)->num = 0;
return vec;
}
#if 0
/* Example uses. */
DEF_VEC_I (int);
typedef struct X
{
int i;
} obj_t;
typedef obj_t *ptr_t;
DEF_VEC_P (ptr_t);
DEF_VEC_O (obj_t);
#endif

1000
gdb/vec.h Normal file

File diff suppressed because it is too large Load Diff