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:
parent
5bd4b6af45
commit
350da6eece
6 changed files with 1312 additions and 2 deletions
|
@ -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>
|
2006-09-20 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
PR remote/2154
|
PR remote/2154
|
||||||
|
|
|
@ -560,7 +560,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
|
||||||
typeprint.c \
|
typeprint.c \
|
||||||
ui-out.c utils.c ui-file.h ui-file.c \
|
ui-out.c utils.c ui-file.h ui-file.c \
|
||||||
user-regs.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
|
wrapper.c
|
||||||
|
|
||||||
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.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)
|
$(expression_h)
|
||||||
varobj_h = varobj.h $(symtab_h) $(gdbtypes_h)
|
varobj_h = varobj.h $(symtab_h) $(gdbtypes_h)
|
||||||
vax_tdep_h = vax-tdep.h
|
vax_tdep_h = vax-tdep.h
|
||||||
|
vec_h = vec.h $(gdb_assert_h) $(gdb_string_h)
|
||||||
version_h = version.h
|
version_h = version.h
|
||||||
wince_stub_h = wince-stub.h
|
wince_stub_h = wince-stub.h
|
||||||
wrapper_h = wrapper.h $(gdb_h)
|
wrapper_h = wrapper.h $(gdb_h)
|
||||||
|
@ -941,7 +942,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||||
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
|
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
|
||||||
ada-lang.o c-lang.o f-lang.o objc-lang.o \
|
ada-lang.o c-lang.o f-lang.o objc-lang.o \
|
||||||
ui-out.o cli-out.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 \
|
jv-lang.o jv-valprint.o jv-typeprint.o \
|
||||||
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
|
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
|
||||||
scm-exp.o scm-lang.o scm-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) \
|
$(float_format_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \
|
||||||
$(gdbcore_h) $(gdbtypes_h) $(osabi_h) $(regcache_h) $(regset_h) \
|
$(gdbcore_h) $(gdbtypes_h) $(osabi_h) $(regcache_h) $(regset_h) \
|
||||||
$(trad_frame_h) $(value_h) $(gdb_string_h) $(vax_tdep_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) \
|
win32-nat.o: win32-nat.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
|
||||||
$(exceptions_h) $(gdbcore_h) $(command_h) $(completer_h) \
|
$(exceptions_h) $(gdbcore_h) $(command_h) $(completer_h) \
|
||||||
$(regcache_h) $(top_h) $(buildsym_h) $(symfile_h) $(objfiles_h) \
|
$(regcache_h) $(top_h) $(buildsym_h) $(symfile_h) $(objfiles_h) \
|
||||||
|
|
|
@ -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>
|
2006-09-17 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
* gdb.texinfo (GDB/MI Stack Manipulation): Mention that
|
* gdb.texinfo (GDB/MI Stack Manipulation): Mention that
|
||||||
|
|
|
@ -4913,6 +4913,181 @@ Regex conditionals.
|
||||||
@item sparc
|
@item sparc
|
||||||
@end table
|
@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
|
@section include
|
||||||
|
|
||||||
@node Coding
|
@node Coding
|
||||||
|
|
120
gdb/vec.c
Normal file
120
gdb/vec.c
Normal 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
|
Loading…
Add table
Reference in a new issue