2 /*--------------------------------------------------------------------*/
3 /*--- An expandable array implementation. m_xarray.h ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2007-2017 OpenWorks LLP
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 The GNU General Public License is contained in the file COPYING.
31 #include "pub_core_basics.h"
32 #include "pub_core_libcbase.h"
33 #include "pub_core_libcassert.h"
34 #include "pub_core_libcprint.h"
35 #include "pub_core_xarray.h" /* self */
38 /* See pub_tool_xarray.h for details of what this is all about. */
41 Alloc_Fn_t alloc_fn
; /* alloc fn (nofail) */
42 const HChar
* cc
; /* cost centre for alloc */
43 Free_Fn_t free_fn
; /* free fn */
44 Int (*cmpFn
) ( const void*, const void* ); /* cmp fn (may be NULL) */
45 Word elemSzB
; /* element size in bytes */
46 void* arr
; /* pointer to elements */
47 Word usedsizeE
; /* # used elements in arr */
48 Word totsizeE
; /* max size of arr, in elements */
49 Bool sorted
; /* is it sorted? */
53 XArray
* VG_(newXA
) ( Alloc_Fn_t alloc_fn
,
59 /* Implementation relies on Word being signed and (possibly)
60 on SizeT being unsigned. */
61 vg_assert( sizeof(Word
) == sizeof(void*) );
62 vg_assert( ((Word
)(-1)) < ((Word
)(0)) );
63 vg_assert( ((SizeT
)(-1)) > ((SizeT
)(0)) );
64 /* check user-supplied info .. */
67 vg_assert(elemSzB
> 0);
68 xa
= alloc_fn( cc
, sizeof(struct _XArray
) );
69 xa
->alloc_fn
= alloc_fn
;
71 xa
->free_fn
= free_fn
;
73 xa
->elemSzB
= elemSzB
;
81 XArray
* VG_(cloneXA
)( const HChar
* cc
, const XArray
* xa
)
86 vg_assert(xa
->alloc_fn
);
87 vg_assert(xa
->free_fn
);
88 vg_assert(xa
->elemSzB
>= 1);
89 nyu_cc
= cc
? cc
: xa
->cc
;
90 nyu
= xa
->alloc_fn( nyu_cc
, sizeof(struct _XArray
) );
92 /* Copy everything verbatim ... */
95 /* ... except we have to clone the contents-array */
97 /* Restrict the total size of the new array to its current
98 actual size. That means we don't waste space copying the
99 unused tail of the original. The tradeoff is that it
100 guarantees we will have to resize the child if even one more
101 element is later added to it, unfortunately. */
102 nyu
->totsizeE
= nyu
->usedsizeE
;
103 /* and allocate .. */
104 nyu
->arr
= nyu
->alloc_fn( nyu
->cc
, nyu
->totsizeE
* nyu
->elemSzB
);
105 VG_(memcpy
)( nyu
->arr
, xa
->arr
, nyu
->totsizeE
* nyu
->elemSzB
);
111 void VG_(deleteXA
) ( XArray
* xa
)
114 vg_assert(xa
->free_fn
);
116 xa
->free_fn(xa
->arr
);
120 void VG_(setCmpFnXA
) ( XArray
* xa
, XACmpFn_t compar
)
128 inline void* VG_(indexXA
) ( const XArray
* xa
, Word n
)
131 /* vg_assert(n >= 0); If n negative, the UWord conversion will make
132 it bigger than usedsizeE, which is verified to be non negative when
134 vg_assert((UWord
)n
< (UWord
)xa
->usedsizeE
);
135 return ((char*)xa
->arr
) + n
* xa
->elemSzB
;
138 void VG_(hintSizeXA
) ( XArray
* xa
, Word n
)
140 /* Currently, we support giving a size hint only just after the
141 call to VG_(newXA). So, we could instead have done
142 a function VG_(newXA_with_SizeHint). The separate VG_(hintSizeXA)
143 function is however chosen as we might one day accept to
144 give a size hint after having added elements. That could be useful
145 for reducing the size of an xarray to just the size currently needed
146 or to give a size hint when it is known that a lot more elements
147 are needed or when the final nr of elements is known. */
149 vg_assert(xa
->usedsizeE
== 0);
150 vg_assert(xa
->totsizeE
== 0);
153 xa
->arr
= xa
->alloc_fn(xa
->cc
, n
* xa
->elemSzB
);
158 static inline void ensureSpaceXA ( XArray
* xa
)
160 if (xa
->usedsizeE
== xa
->totsizeE
) {
163 if (xa
->totsizeE
== 0)
165 if (xa
->totsizeE
> 0)
167 if (xa
->totsizeE
== 0) {
168 /* No point in having tiny (eg) 2-byte allocations for the
169 element array, since all allocs are rounded up to 8 anyway.
170 Hence increase the initial array size for tiny elements in
171 an attempt to avoid reallocations of size 2, 4, 8 if the
172 array does start to fill up. */
173 if (xa
->elemSzB
== 1) newsz
= 8;
174 else if (xa
->elemSzB
== 2) newsz
= 4;
177 newsz
= 2 + (3 * xa
->totsizeE
) / 2; /* 2 * xa->totsizeE; */
179 if (0 && xa
->totsizeE
>= 10000)
180 VG_(printf
)("addToXA: increasing from %ld to %ld\n",
181 xa
->totsizeE
, newsz
);
182 tmp
= xa
->alloc_fn(xa
->cc
, newsz
* xa
->elemSzB
);
183 if (xa
->usedsizeE
> 0)
184 VG_(memcpy
)(tmp
, xa
->arr
, xa
->usedsizeE
* xa
->elemSzB
);
186 xa
->free_fn(xa
->arr
);
188 xa
->totsizeE
= newsz
;
192 Word
VG_(addToXA
) ( XArray
* xa
, const void* elem
)
196 vg_assert(xa
->totsizeE
>= 0);
197 vg_assert(xa
->usedsizeE
>= 0 && xa
->usedsizeE
<= xa
->totsizeE
);
199 vg_assert(xa
->usedsizeE
< xa
->totsizeE
);
201 VG_(memcpy
)( ((UChar
*)xa
->arr
) + xa
->usedsizeE
* xa
->elemSzB
,
205 return xa
->usedsizeE
-1;
208 Word
VG_(addBytesToXA
) ( XArray
* xa
, const void* bytesV
, Word nbytes
)
212 vg_assert(xa
->elemSzB
== 1);
213 vg_assert(nbytes
>= 0);
214 vg_assert(xa
->totsizeE
>= 0);
215 vg_assert(xa
->usedsizeE
>= 0 && xa
->usedsizeE
<= xa
->totsizeE
);
217 for (i
= 0; i
< nbytes
; i
++) {
219 vg_assert(xa
->usedsizeE
< xa
->totsizeE
);
221 * (((UChar
*)xa
->arr
) + xa
->usedsizeE
) = ((const UChar
*)bytesV
)[i
];
228 void VG_(sortXA
) ( XArray
* xa
)
231 vg_assert(xa
->cmpFn
);
232 VG_(ssort
)( xa
->arr
, xa
->usedsizeE
, xa
->elemSzB
, xa
->cmpFn
);
236 Bool
VG_(lookupXA_UNSAFE
) ( const XArray
* xa
, const void* key
,
237 /*OUT*/Word
* first
, /*OUT*/Word
* last
,
238 Int(*cmpFn
)(const void*, const void*) )
240 Word lo
, mid
, hi
, cres
;
244 hi
= xa
->usedsizeE
-1;
246 /* current unsearched space is from lo to hi, inclusive. */
247 if (lo
> hi
) return False
; /* not found */
249 midv
= VG_(indexXA
)( xa
, mid
);
250 cres
= cmpFn( key
, midv
);
251 if (cres
< 0) { hi
= mid
-1; continue; }
252 if (cres
> 0) { lo
= mid
+1; continue; }
253 /* Found it, at mid. See how far we can expand this. */
254 vg_assert(cmpFn( key
, VG_(indexXA
)(xa
, lo
) ) >= 0);
255 vg_assert(cmpFn( key
, VG_(indexXA
)(xa
, hi
) ) <= 0);
259 && 0 == cmpFn( key
, VG_(indexXA
)(xa
, (*first
)-1))) {
265 while (*last
< xa
->usedsizeE
-1
266 && 0 == cmpFn( key
, VG_(indexXA
)(xa
, (*last
)+1))) {
274 Bool
VG_(lookupXA
) ( const XArray
* xa
, const void* key
,
275 /*OUT*/Word
* first
, /*OUT*/Word
* last
)
278 vg_assert(xa
->cmpFn
);
279 vg_assert(xa
->sorted
);
280 return VG_(lookupXA_UNSAFE
)(xa
, key
, first
, last
, xa
->cmpFn
);
283 /* FIXME: This function should return an unsigned value because the number
284 of elements cannot be negative. Unfortunately, making the change causes
286 Word
VG_(sizeXA
) ( const XArray
* xa
)
289 return xa
->usedsizeE
;
292 void VG_(dropTailXA
) ( XArray
* xa
, Word n
)
296 vg_assert(n
<= xa
->usedsizeE
);
300 void VG_(dropHeadXA
) ( XArray
* xa
, Word n
)
304 vg_assert(n
<= xa
->usedsizeE
);
308 if (n
== xa
->usedsizeE
) {
313 vg_assert(xa
->usedsizeE
- n
> 0);
314 VG_(memcpy
)( (char*)xa
->arr
,
315 ((char*)xa
->arr
) + n
* xa
->elemSzB
,
316 (xa
->usedsizeE
- n
) * xa
->elemSzB
);
320 void VG_(removeIndexXA
)( XArray
* xa
, Word n
)
324 vg_assert(n
< xa
->usedsizeE
);
325 if (n
+1 < xa
->usedsizeE
) {
326 VG_(memmove
)( ((char*)xa
->arr
) + (n
+0) * xa
->elemSzB
,
327 ((char*)xa
->arr
) + (n
+1) * xa
->elemSzB
,
328 (xa
->usedsizeE
- n
- 1) * xa
->elemSzB
);
333 void VG_(insertIndexXA
)( XArray
* xa
, Word n
, const void* elem
)
337 vg_assert(n
<= xa
->usedsizeE
);
338 vg_assert(xa
->usedsizeE
>= 0 && xa
->usedsizeE
<= xa
->totsizeE
);
340 vg_assert(xa
->usedsizeE
< xa
->totsizeE
);
342 if (n
< xa
->usedsizeE
) {
343 VG_(memmove
) ( ((char*)xa
->arr
) + (n
+1) * xa
->elemSzB
,
344 ((char*)xa
->arr
) + (n
+0) * xa
->elemSzB
,
345 (xa
->usedsizeE
- n
) * xa
->elemSzB
);
347 VG_(memcpy
)( ((UChar
*)xa
->arr
) + n
* xa
->elemSzB
,
353 void VG_(getContentsXA_UNSAFE
)( XArray
* xa
,
358 *ctsP
= (void*)xa
->arr
;
359 *usedP
= xa
->usedsizeE
;
362 /* --------- Printeffery --------- */
364 static void add_char_to_XA ( HChar c
, void* opaque
)
366 XArray
* dst
= (XArray
*)opaque
;
367 (void) VG_(addBytesToXA
)( dst
, &c
, 1 );
370 void VG_(xaprintf
)( XArray
* dst
, const HChar
* format
, ... )
373 va_start(vargs
, format
);
374 VG_(vcbprintf
)( add_char_to_XA
, (void*)dst
, format
, vargs
);
378 Bool
VG_(strIsMemberXA
)(const XArray
* xa
, const HChar
* str
)
381 HChar
** members
= (HChar
**)xa
->arr
;
383 for (i
= 0; i
< xa
->usedsizeE
; i
++)
384 if (VG_(strcmp
)(str
, members
[i
]) == 0)
389 /*--------------------------------------------------------------------*/
390 /*--- end m_xarray.c ---*/
391 /*--------------------------------------------------------------------*/