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
+ Because of the different behavior of objects and of pointers to
+ objects, there are two flavors. 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
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.
+ The 'lower_bound' function will determine where to place an item in the
+ array using insert that will maintain sorted order.
+ Both garbage collected and explicitly managed vector types are
+ creatable. The allocation mechanism is specified when the type is
+ defined, and is therefore part of the type.
+
If you need to directly manipulate a vector, then the 'address'
accessor will return the address of the start of the vector. Also
the '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 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
+ Vector types are defined using a DEF_VEC_{GC,MALLOC}_{O,P}(TYPEDEF)
+ macro, and variables of vector type are declared using a
+ VEC(TYPEDEF) macro. The tags GC and MALLOC specify the allocation
+ method -- garbage collected or explicit malloc/free calls. The
+ characters O and P indicate 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
+ DEF_VEC_GC_P(tree); // define a gc'd vector of tree pointers. This must
// appear at file scope.
struct my_struct {
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,t); ix++)
- { do something with t }
+ for (ix = 0; VEC_iterate(tree,s->v,ix,elt); ix++)
+ { do something with elt }
*/
(by taking its address), this is noted in the descriptions. */
/* Length of vector
- size_t VEC_T_length(const VEC(T) *v);
+ unsigned 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_last(TDEF,V) (VEC_OP(TDEF,last)(V VEC_CHECK_INFO))
/* 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
+ T VEC_T_index(VEC(T) *v, unsigned ix); // Pointer
+ T *VEC_T_index(VEC(T) *v, unsigned 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 VEC_CHECK_INFO))
/* Iterate over vector
- int VEC_T_index(VEC(T) *v, size_t ix, T &ptr); // Pointer
- int VEC_T_index(VEC(T) *v, size_t ix, T *&ptr); // Object
+ int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Pointer
+ int VEC_T_iterate(VEC(T) *v, unsigned ix, T *&ptr); // Object
Return iteration condition and update PTR to point to the IX'th
element. At the end of iteration, sets PTR to NULL. Use this to
#define VEC_alloc(TDEF,A) (VEC_OP(TDEF,alloc)(A MEM_STAT_INFO))
+/* Free a vector.
+ void VEC_T_alloc(VEC(T) *&);
+
+ Free a vector and set it to NULL. */
+
+#define VEC_free(TDEF,V) (VEC_OP(TDEF,free)(&V))
+
/* Use these to determine the required size and initialization of a
vector embedded within another structure (as the final member).
int VEC_T_space (VEC(T) *v,int reserve)
- If V has space for RESERVE additional entries, return non-zero. If
+ If V has space for RESERVE additional entries, return nonzero. If
RESERVE is < 0, ensure there is at least one space slot. You
usually only need to use this if you are doing your own vector
reallocation, for instance on an embedded vector. This returns
- non-zero in exactly the same circumstances that VEC_T_reserve
+ nonzero in exactly the same circumstances that VEC_T_reserve
will. */
#define VEC_space(TDEF,V,R) (VEC_OP(TDEF,space)(V,R))
Ensure that V has at least RESERVE slots available, if RESERVE is
>= 0. If RESERVE < 0, ensure that there is at least one spare
- slot. These differ in their reallocation behaviour, the first will
+ slot. These differ in their reallocation behavior, the first will
not create additional headroom, but the second mechanism will
perform the usual exponential headroom increase. Note this can
- cause V to be reallocated. Returns non-zero iff reallocation
+ cause V to be reallocated. Returns nonzero iff reallocation
actually occurred. */
#define VEC_reserve(TDEF,V,R) (VEC_OP(TDEF,reserve)(&(V),R MEM_STAT_INFO))
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. */
+ insufficient space in the vector. */
#define VEC_quick_push(TDEF,V,O) \
(VEC_OP(TDEF,quick_push)(V,O VEC_CHECK_INFO))
#define VEC_pop(TDEF,V) (VEC_OP(TDEF,pop)(V VEC_CHECK_INFO))
/* Truncate to specific length
- void VEC_T_truncate (VEC(T) *v, size_t len);
+ void VEC_T_truncate (VEC(T) *v, unsigned len);
Set the length as specified. This is an O(1) operation. */
(VEC_OP(TDEF,truncate)(V,I VEC_CHECK_INFO))
/* 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
+ T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Pointer
+ T *VEC_T_replace (VEC(T) *v, unsigned 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
(VEC_OP(TDEF,replace)(V,I,O VEC_CHECK_INFO))
/* 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
+ T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Pointer
+ T *VEC_T_quick_insert (VEC(T) *v, unsigned 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
(VEC_OP(TDEF,quick_insert)(V,I,O VEC_CHECK_INFO))
/* 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
+ T *VEC_T_safe_insert (VEC(T) *&v, unsigned ix, T val); // Pointer
+ T *VEC_T_safe_insert (VEC(T) *&v, unsigned 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
(VEC_OP(TDEF,safe_insert)(&(V),I,O VEC_CHECK_INFO MEM_STAT_INFO))
/* 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
+ T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Pointer
+ void VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Object
Remove an element from the IXth position of V. Ordering of
- remaining elements is preserverd. For pointer vectors returns the
+ remaining elements is preserved. 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 VEC_CHECK_INFO))
/* 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
+ T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Pointer
+ void VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Object
Remove an element from the IXth position of V. Ordering of
remaining elements is destroyed. For pointer vectors returns the
#define VEC_address(TDEF,V) (VEC_OP(TDEF,address)(V))
+/* Find the first index in the vector not less than the object.
+ unsigned VEC_T_lower_bound (VEC(T) *v, const T val,
+ bool (*lessthan) (const T, const T)); // Pointer
+ unsigned VEC_T_lower_bound (VEC(T) *v, const T *val,
+ bool (*lessthan) (const T*, const T*)); // Object
+
+ Find the first position in which VAL could be inserted without
+ changing the ordering of V. LESSTHAN is a function that returns
+ true if the first argument is strictly less than the second. */
+
+#define VEC_lower_bound(TDEF,V,O,LT) \
+ (VEC_OP(TDEF,lower_bound)(V,O,LT VEC_CHECK_INFO))
+
#if !IN_GENGTYPE
/* Reallocate an array of elements with prefix. */
-extern void *vec_p_reserve (void *, int MEM_STAT_DECL);
-extern void *vec_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
+extern void *vec_gc_p_reserve (void *, int MEM_STAT_DECL);
+extern void *vec_gc_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
+extern void vec_gc_free (void *);
+extern void *vec_heap_p_reserve (void *, int MEM_STAT_DECL);
+extern void *vec_heap_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
+extern void vec_heap_free (void *);
#if ENABLE_CHECKING
#define VEC_CHECK_INFO ,__FILE__,__LINE__,__FUNCTION__
#define VEC_TDEF(TDEF) \
typedef struct VEC (TDEF) GTY(()) \
{ \
- size_t num; \
- size_t alloc; \
+ unsigned num; \
+ unsigned 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},
+{"DEF_VEC_GC_P", VEC_STRINGIFY (VEC_TDEF (#)) ";", NULL},
+{"DEF_VEC_MALLOC_P", "", NULL},
#else
+#define DEF_VEC_GC_P(TDEF) DEF_VEC_P(TDEF,gc)
+#define DEF_VEC_MALLOC_P(TDEF) DEF_VEC_P(TDEF,heap)
-#define DEF_VEC_P(TDEF) \
+#define DEF_VEC_P(TDEF,a) \
VEC_TDEF (TDEF); \
\
-static inline size_t VEC_OP (TDEF,length) \
+static inline unsigned VEC_OP (TDEF,length) \
(const VEC (TDEF) *vec_) \
{ \
return vec_ ? vec_->num : 0; \
} \
\
static inline TDEF VEC_OP (TDEF,index) \
- (const VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (const VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
VEC_ASSERT (vec_ && ix_ < vec_->num, "index", TDEF); \
\
} \
\
static inline int VEC_OP (TDEF,iterate) \
- (const VEC (TDEF) *vec_, size_t ix_, TDEF *ptr) \
+ (const VEC (TDEF) *vec_, unsigned ix_, TDEF *ptr) \
{ \
if (vec_ && ix_ < vec_->num) \
{ \
static inline VEC (TDEF) *VEC_OP (TDEF,alloc) \
(int alloc_ MEM_STAT_DECL) \
{ \
- return vec_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT); \
+ return (VEC (TDEF) *) vec_##a##_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT);\
+} \
+ \
+static inline void VEC_OP (TDEF,free) \
+ (VEC (TDEF) **vec_) \
+{ \
+ vec_##a##_free (*vec_); \
+ *vec_ = NULL; \
} \
\
static inline size_t VEC_OP (TDEF,embedded_size) \
(VEC (TDEF) *vec_, int alloc_) \
{ \
return vec_ ? ((vec_)->alloc - (vec_)->num \
- < (size_t)(alloc_ < 0 ? 1 : alloc_)) : alloc_ != 0; \
+ >= (unsigned)(alloc_ < 0 ? 1 : alloc_)) : !alloc_; \
} \
\
static inline int VEC_OP (TDEF,reserve) \
(VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL) \
{ \
- int extend = VEC_OP (TDEF,space) (*vec_, alloc_); \
+ int extend = !VEC_OP (TDEF,space) (*vec_, alloc_); \
\
if (extend) \
- *vec_ = vec_p_reserve (*vec_, alloc_ PASS_MEM_STAT); \
+ *vec_ = (VEC (TDEF) *) vec_##a##_p_reserve (*vec_, alloc_ PASS_MEM_STAT); \
\
return extend; \
} \
} \
\
static inline void VEC_OP (TDEF,truncate) \
- (VEC (TDEF) *vec_, size_t size_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned size_ VEC_CHECK_DECL) \
{ \
VEC_ASSERT (vec_ ? vec_->num >= size_ : !size_, "truncate", TDEF); \
if (vec_) \
} \
\
static inline TDEF VEC_OP (TDEF,replace) \
- (VEC (TDEF) *vec_, size_t ix_, TDEF obj_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_, TDEF obj_ VEC_CHECK_DECL) \
{ \
TDEF old_obj_; \
\
return old_obj_; \
} \
\
-static inline TDEF *VEC_OP (TDEF,quick_insert) \
- (VEC (TDEF) *vec_, size_t ix_, TDEF obj_ VEC_CHECK_DECL) \
+static inline unsigned VEC_OP (TDEF,lower_bound) \
+ (VEC (TDEF) *vec_, const TDEF obj_, bool (*lessthan_)(const TDEF, const TDEF) VEC_CHECK_DECL) \
+{ \
+ unsigned int len_ = VEC_OP (TDEF, length) (vec_); \
+ unsigned int half_, middle_; \
+ unsigned int first_ = 0; \
+ while (len_ > 0) \
+ { \
+ TDEF middle_elem_; \
+ half_ = len_ >> 1; \
+ middle_ = first_; \
+ middle_ += half_; \
+ middle_elem_ = VEC_OP (TDEF, index) (vec_, middle_ VEC_CHECK_PASS); \
+ if (lessthan_ (middle_elem_, obj_)) \
+ { \
+ first_ = middle_; \
+ ++first_; \
+ len_ = len_ - half_ - 1; \
+ } \
+ else \
+ len_ = half_; \
+ } \
+ return first_; \
+} \
+ \
+static inline TDEF *VEC_OP (TDEF,quick_insert) \
+ (VEC (TDEF) *vec_, unsigned ix_, TDEF obj_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
\
} \
\
static inline TDEF *VEC_OP (TDEF,safe_insert) \
- (VEC (TDEF) **vec_, size_t ix_, TDEF obj_ VEC_CHECK_DECL MEM_STAT_DECL) \
+ (VEC (TDEF) **vec_, unsigned ix_, TDEF obj_ \
+ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT); \
\
} \
\
static inline TDEF VEC_OP (TDEF,ordered_remove) \
- (VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
TDEF obj_; \
} \
\
static inline TDEF VEC_OP (TDEF,unordered_remove) \
- (VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
TDEF obj_; \
/* Vector of object. */
#if IN_GENGTYPE
-{"DEF_VEC_O", VEC_STRINGIFY (VEC_TDEF (#)) ";", NULL},
+{"DEF_VEC_GC_O", VEC_STRINGIFY (VEC_TDEF (#)) ";", NULL},
+{"DEF_VEC_MALLOC_O", "", NULL},
#else
-#define DEF_VEC_O(TDEF) \
+#define DEF_VEC_GC_O(TDEF) DEF_VEC_O(TDEF,gc)
+#define DEF_VEC_MALLOC_O(TDEF) DEF_VEC_O(TDEF,heap)
+
+#define DEF_VEC_O(TDEF,a) \
VEC_TDEF (TDEF); \
\
-static inline size_t VEC_OP (TDEF,length) \
+static inline unsigned VEC_OP (TDEF,length) \
(const VEC (TDEF) *vec_) \
{ \
return vec_ ? vec_->num : 0; \
} \
\
static inline TDEF *VEC_OP (TDEF,index) \
- (VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
VEC_ASSERT (vec_ && ix_ < vec_->num, "index", TDEF); \
\
} \
\
static inline int VEC_OP (TDEF,iterate) \
- (VEC (TDEF) *vec_, size_t ix_, TDEF **ptr) \
+ (VEC (TDEF) *vec_, unsigned ix_, TDEF **ptr) \
{ \
if (vec_ && ix_ < vec_->num) \
{ \
static inline VEC (TDEF) *VEC_OP (TDEF,alloc) \
(int alloc_ MEM_STAT_DECL) \
{ \
- return vec_o_reserve (NULL, alloc_ - !alloc_, \
- offsetof (VEC(TDEF),vec), sizeof (TDEF) \
- PASS_MEM_STAT); \
+ return (VEC (TDEF) *) vec_##a##_o_reserve (NULL, alloc_ - !alloc_, \
+ offsetof (VEC(TDEF),vec), sizeof (TDEF)\
+ PASS_MEM_STAT); \
+} \
+ \
+static inline void VEC_OP (TDEF,free) \
+ (VEC (TDEF) **vec_) \
+{ \
+ vec_##a##_free (*vec_); \
+ *vec_ = NULL; \
} \
\
static inline size_t VEC_OP (TDEF,embedded_size) \
(VEC (TDEF) *vec_, int alloc_) \
{ \
return vec_ ? ((vec_)->alloc - (vec_)->num \
- < (size_t)(alloc_ < 0 ? 1 : alloc_)) : alloc_ != 0; \
+ >= (unsigned)(alloc_ < 0 ? 1 : alloc_)) : !alloc_; \
} \
\
static inline int VEC_OP (TDEF,reserve) \
(VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL) \
{ \
- int extend = VEC_OP (TDEF,space) (*vec_, alloc_); \
+ int extend = !VEC_OP (TDEF,space) (*vec_, alloc_); \
\
if (extend) \
- *vec_ = vec_o_reserve (*vec_, alloc_, \
+ *vec_ = (VEC (TDEF) *) vec_##a##_o_reserve (*vec_, alloc_, \
offsetof (VEC(TDEF),vec), sizeof (TDEF) \
PASS_MEM_STAT); \
\
} \
\
static inline void VEC_OP (TDEF,truncate) \
- (VEC (TDEF) *vec_, size_t size_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned size_ VEC_CHECK_DECL) \
{ \
VEC_ASSERT (vec_ ? vec_->num >= size_ : !size_, "truncate", TDEF); \
if (vec_) \
} \
\
static inline TDEF *VEC_OP (TDEF,replace) \
- (VEC (TDEF) *vec_, size_t ix_, const TDEF *obj_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_, const TDEF *obj_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
\
return slot_; \
} \
\
-static inline TDEF *VEC_OP (TDEF,quick_insert) \
- (VEC (TDEF) *vec_, size_t ix_, const TDEF *obj_ VEC_CHECK_DECL) \
+static inline unsigned VEC_OP (TDEF,lower_bound) \
+ (VEC (TDEF) *vec_, const TDEF *obj_, bool (*lessthan_)(const TDEF *, const TDEF *) VEC_CHECK_DECL) \
+{ \
+ unsigned int len_ = VEC_OP (TDEF, length) (vec_); \
+ unsigned int half_, middle_; \
+ unsigned int first_ = 0; \
+ while (len_ > 0) \
+ { \
+ TDEF *middle_elem_; \
+ half_ = len_ >> 1; \
+ middle_ = first_; \
+ middle_ += half_; \
+ middle_elem_ = VEC_OP (TDEF, index) (vec_, middle_ VEC_CHECK_PASS); \
+ if (lessthan_ (middle_elem_, obj_)) \
+ { \
+ first_ = middle_; \
+ ++first_; \
+ len_ = len_ - half_ - 1; \
+ } \
+ else \
+ len_ = half_; \
+ } \
+ return first_; \
+} \
+ \
+static inline TDEF *VEC_OP (TDEF,quick_insert) \
+ (VEC (TDEF) *vec_, unsigned ix_, const TDEF *obj_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
\
} \
\
static inline TDEF *VEC_OP (TDEF,safe_insert) \
- (VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_ VEC_CHECK_DECL MEM_STAT_DECL) \
+ (VEC (TDEF) **vec_, unsigned ix_, const TDEF *obj_ \
+ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT); \
\
} \
\
static inline void VEC_OP (TDEF,ordered_remove) \
- (VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
TDEF *slot_; \
\
} \
\
static inline void VEC_OP (TDEF,unordered_remove) \
- (VEC (TDEF) *vec_, size_t ix_ VEC_CHECK_DECL) \
+ (VEC (TDEF) *vec_, unsigned ix_ VEC_CHECK_DECL) \
{ \
VEC_ASSERT (ix_ < vec_->num, "remove", TDEF); \
vec_->vec[ix_] = vec_->vec[--vec_->num]; \