• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*--------------------------------------------------------------------*/
3 /*--- An expandable array implementation.               m_xarray.h ---*/
4 /*--------------------------------------------------------------------*/
5 
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9 
10    Copyright (C) 2007-2013 OpenWorks LLP
11       info@open-works.co.uk
12 
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.
17 
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.
22 
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
26    02111-1307, USA.
27 
28    The GNU General Public License is contained in the file COPYING.
29 */
30 
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 */
36 
37 
38 /* See pub_tool_xarray.h for details of what this is all about. */
39 
40 struct _XArray {
41    void* (*alloc) ( const HChar*, SizeT ); /* alloc fn (nofail) */
42    const HChar* cc;                 /* cost centre for alloc */
43    void  (*free) ( void* );         /* 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? */
50 };
51 
52 
VG_(newXA)53 XArray* VG_(newXA) ( void*(*alloc_fn)(const HChar*,SizeT),
54                      const HChar* cc,
55                      void(*free_fn)(void*),
56                      Word elemSzB )
57 {
58    struct _XArray* xa;
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 .. */
65    vg_assert(alloc_fn);
66    vg_assert(free_fn);
67    vg_assert(elemSzB > 0);
68    xa = alloc_fn( cc, sizeof(struct _XArray) );
69    vg_assert(xa);
70    xa->alloc     = alloc_fn;
71    xa->cc        = cc;
72    xa->free      = free_fn;
73    xa->cmpFn     = NULL;
74    xa->elemSzB   = elemSzB;
75    xa->usedsizeE = 0;
76    xa->totsizeE  = 0;
77    xa->sorted    = False;
78    xa->arr       = NULL;
79    return xa;
80 }
81 
VG_(cloneXA)82 XArray* VG_(cloneXA)( const HChar* cc, XArray* xao )
83 {
84    struct _XArray* xa = (struct _XArray*)xao;
85    struct _XArray* nyu;
86    const HChar* nyu_cc;
87    vg_assert(xa);
88    vg_assert(xa->alloc);
89    vg_assert(xa->free);
90    vg_assert(xa->elemSzB >= 1);
91    nyu_cc = cc ? cc : xa->cc;
92    nyu = xa->alloc( nyu_cc, sizeof(struct _XArray) );
93    if (!nyu)
94       return NULL;
95    /* Copy everything verbatim ... */
96    *nyu = *xa;
97    nyu->cc = nyu_cc;
98    /* ... except we have to clone the contents-array */
99    if (nyu->arr) {
100       /* Restrict the total size of the new array to its current
101          actual size.  That means we don't waste space copying the
102          unused tail of the original.  The tradeoff is that it
103          guarantees we will have to resize the child if even one more
104          element is later added to it, unfortunately. */
105       nyu->totsizeE = nyu->usedsizeE;
106       /* and allocate .. */
107       nyu->arr = nyu->alloc( nyu->cc, nyu->totsizeE * nyu->elemSzB );
108       if (!nyu->arr) {
109          nyu->free(nyu);
110          return NULL;
111       }
112       VG_(memcpy)( nyu->arr, xa->arr, nyu->totsizeE * nyu->elemSzB );
113    }
114    /* We're done! */
115    return nyu;
116 }
117 
VG_(deleteXA)118 void VG_(deleteXA) ( XArray* xao )
119 {
120    struct _XArray* xa = (struct _XArray*)xao;
121    vg_assert(xa);
122    vg_assert(xa->free);
123    if (xa->arr)
124       xa->free(xa->arr);
125    xa->free(xa);
126 }
127 
VG_(setCmpFnXA)128 void VG_(setCmpFnXA) ( XArray* xao, XACmpFn_t compar )
129 {
130    struct _XArray* xa = (struct _XArray*)xao;
131    vg_assert(xa);
132    vg_assert(compar);
133    xa->cmpFn  = compar;
134    xa->sorted = False;
135 }
136 
VG_(indexXA)137 inline void* VG_(indexXA) ( XArray* xao, Word n )
138 {
139    struct _XArray* xa = (struct _XArray*)xao;
140    vg_assert(xa);
141    vg_assert(n >= 0);
142    vg_assert(n < xa->usedsizeE);
143    return ((char*)xa->arr) + n * xa->elemSzB;
144 }
145 
ensureSpaceXA(struct _XArray * xa)146 static inline void ensureSpaceXA ( struct _XArray* xa )
147 {
148    if (xa->usedsizeE == xa->totsizeE) {
149       void* tmp;
150       Word  newsz;
151       if (xa->totsizeE == 0)
152          vg_assert(!xa->arr);
153       if (xa->totsizeE > 0)
154          vg_assert(xa->arr);
155       if (xa->totsizeE == 0) {
156          /* No point in having tiny (eg) 2-byte allocations for the
157             element array, since all allocs are rounded up to 8 anyway.
158             Hence increase the initial array size for tiny elements in
159             an attempt to avoid reallocations of size 2, 4, 8 if the
160             array does start to fill up. */
161          if (xa->elemSzB == 1) newsz = 8;
162          else if (xa->elemSzB == 2) newsz = 4;
163          else newsz = 2;
164       } else {
165          newsz = 2 + (3 * xa->totsizeE) / 2;  /* 2 * xa->totsizeE; */
166       }
167       if (0 && xa->totsizeE >= 10000)
168          VG_(printf)("addToXA: increasing from %ld to %ld\n",
169                      xa->totsizeE, newsz);
170       tmp = xa->alloc(xa->cc, newsz * xa->elemSzB);
171       vg_assert(tmp);
172       if (xa->usedsizeE > 0)
173          VG_(memcpy)(tmp, xa->arr, xa->usedsizeE * xa->elemSzB);
174       if (xa->arr)
175          xa->free(xa->arr);
176       xa->arr = tmp;
177       xa->totsizeE = newsz;
178    }
179 }
180 
VG_(addToXA)181 Word VG_(addToXA) ( XArray* xao, const void* elem )
182 {
183    struct _XArray* xa = (struct _XArray*)xao;
184    vg_assert(xa);
185    vg_assert(elem);
186    vg_assert(xa->totsizeE >= 0);
187    vg_assert(xa->usedsizeE >= 0 && xa->usedsizeE <= xa->totsizeE);
188    ensureSpaceXA( xa );
189    vg_assert(xa->usedsizeE < xa->totsizeE);
190    vg_assert(xa->arr);
191    VG_(memcpy)( ((UChar*)xa->arr) + xa->usedsizeE * xa->elemSzB,
192                 elem, xa->elemSzB );
193    xa->usedsizeE++;
194    xa->sorted = False;
195    return xa->usedsizeE-1;
196 }
197 
VG_(addBytesToXA)198 Word VG_(addBytesToXA) ( XArray* xao, const void* bytesV, Word nbytes )
199 {
200    Word r, i;
201    struct _XArray* xa = (struct _XArray*)xao;
202    vg_assert(xa);
203    vg_assert(xa->elemSzB == 1);
204    vg_assert(nbytes >= 0);
205    vg_assert(xa->totsizeE >= 0);
206    vg_assert(xa->usedsizeE >= 0 && xa->usedsizeE <= xa->totsizeE);
207    r = xa->usedsizeE;
208    for (i = 0; i < nbytes; i++) {
209       ensureSpaceXA( xa );
210       vg_assert(xa->usedsizeE < xa->totsizeE);
211       vg_assert(xa->arr);
212       * (((UChar*)xa->arr) + xa->usedsizeE) = ((const UChar*)bytesV)[i];
213       xa->usedsizeE++;
214    }
215    xa->sorted = False;
216    return r;
217 }
218 
VG_(sortXA)219 void VG_(sortXA) ( XArray* xao )
220 {
221    struct _XArray* xa = (struct _XArray*)xao;
222    vg_assert(xa);
223    vg_assert(xa->cmpFn);
224    VG_(ssort)( xa->arr, xa->usedsizeE, xa->elemSzB, xa->cmpFn );
225    xa->sorted = True;
226 }
227 
VG_(lookupXA_UNSAFE)228 Bool VG_(lookupXA_UNSAFE) ( XArray* xao, const void* key,
229                             /*OUT*/Word* first, /*OUT*/Word* last,
230                             Int(*cmpFn)(const void*, const void*) )
231 {
232    Word  lo, mid, hi, cres;
233    void* midv;
234    struct _XArray* xa = (struct _XArray*)xao;
235    vg_assert(xa);
236    lo = 0;
237    hi = xa->usedsizeE-1;
238    while (True) {
239       /* current unsearched space is from lo to hi, inclusive. */
240       if (lo > hi) return False; /* not found */
241       mid  = (lo + hi) / 2;
242       midv = VG_(indexXA)( xa, mid );
243       cres = cmpFn( key, midv );
244       if (cres < 0)  { hi = mid-1; continue; }
245       if (cres > 0)  { lo = mid+1; continue; }
246       /* Found it, at mid.  See how far we can expand this. */
247       vg_assert(cmpFn( key, VG_(indexXA)(xa, lo) ) >= 0);
248       vg_assert(cmpFn( key, VG_(indexXA)(xa, hi) ) <= 0);
249       if (first) {
250          *first = mid;
251          while (*first > 0
252                 && 0 == cmpFn( key, VG_(indexXA)(xa, (*first)-1))) {
253             (*first)--;
254          }
255       }
256       if (last) {
257          *last = mid;
258          while (*last < xa->usedsizeE-1
259                 && 0 == cmpFn( key, VG_(indexXA)(xa, (*last)+1))) {
260             (*last)++;
261          }
262       }
263       return True;
264    }
265 }
266 
VG_(lookupXA)267 Bool VG_(lookupXA) ( XArray* xao, const void* key,
268                      /*OUT*/Word* first, /*OUT*/Word* last )
269 {
270    struct _XArray* xa = (struct _XArray*)xao;
271    vg_assert(xa);
272    vg_assert(xa->cmpFn);
273    vg_assert(xa->sorted);
274    return VG_(lookupXA_UNSAFE)(xao, key, first, last, xa->cmpFn);
275 }
276 
VG_(sizeXA)277 Word VG_(sizeXA) ( XArray* xao )
278 {
279    struct _XArray* xa = (struct _XArray*)xao;
280    vg_assert(xa);
281    return xa->usedsizeE;
282 }
283 
VG_(dropTailXA)284 void VG_(dropTailXA) ( XArray* xao, Word n )
285 {
286    struct _XArray* xa = (struct _XArray*)xao;
287    vg_assert(xa);
288    vg_assert(n >= 0);
289    vg_assert(n <= xa->usedsizeE);
290    xa->usedsizeE -= n;
291 }
292 
VG_(dropHeadXA)293 void VG_(dropHeadXA) ( XArray* xao, Word n )
294 {
295    struct _XArray* xa = (struct _XArray*)xao;
296    vg_assert(xa);
297    vg_assert(n >= 0);
298    vg_assert(n <= xa->usedsizeE);
299    if (n == 0) {
300       return;
301    }
302    if (n == xa->usedsizeE) {
303       xa->usedsizeE = 0;
304       return;
305    }
306    vg_assert(n > 0);
307    vg_assert(xa->usedsizeE - n > 0);
308    VG_(memcpy)( (char*)xa->arr,
309                 ((char*)xa->arr) + n * xa->elemSzB,
310                 (xa->usedsizeE - n) * xa->elemSzB );
311    xa->usedsizeE -= n;
312 }
313 
VG_(removeIndexXA)314 void VG_(removeIndexXA)( XArray* xao, Word n )
315 {
316    struct _XArray* xa = (struct _XArray*)xao;
317    vg_assert(xa);
318    vg_assert(n >= 0);
319    vg_assert(n < xa->usedsizeE);
320    if (n+1 < xa->usedsizeE) {
321       VG_(memmove)( ((char*)xa->arr) + (n+0) * xa->elemSzB,
322                     ((char*)xa->arr) + (n+1) * xa->elemSzB,
323                     (xa->usedsizeE - n - 1) * xa->elemSzB );
324    }
325    xa->usedsizeE--;
326 }
327 
VG_(insertIndexXA)328 void VG_(insertIndexXA)( XArray* xao, Word n, const void* elem )
329 {
330    struct _XArray* xa = (struct _XArray*)xao;
331    vg_assert(xa);
332    vg_assert(n >= 0);
333    vg_assert(n <= xa->usedsizeE);
334    vg_assert(xa->usedsizeE >= 0 && xa->usedsizeE <= xa->totsizeE);
335    ensureSpaceXA( xa );
336    vg_assert(xa->usedsizeE < xa->totsizeE);
337    vg_assert(xa->arr);
338    if (n < xa->usedsizeE) {
339       VG_(memmove) ( ((char*)xa->arr) + (n+1) * xa->elemSzB,
340                      ((char*)xa->arr) + (n+0) * xa->elemSzB,
341                      (xa->usedsizeE - n) * xa->elemSzB );
342    }
343    VG_(memcpy)( ((UChar*)xa->arr) + n * xa->elemSzB,
344                 elem, xa->elemSzB );
345    xa->usedsizeE++;
346    xa->sorted = False;
347 }
348 
VG_(getContentsXA_UNSAFE)349 void VG_(getContentsXA_UNSAFE)( XArray* xao,
350                                 /*OUT*/void** ctsP,
351                                 /*OUT*/Word* usedP )
352 {
353    struct _XArray* xa = (struct _XArray*)xao;
354    vg_assert(xa);
355    *ctsP  = (void*)xa->arr;
356    *usedP = xa->usedsizeE;
357 }
358 
359 /* --------- Printeffery --------- */
360 
add_char_to_XA(HChar c,void * opaque)361 static void add_char_to_XA ( HChar c, void* opaque )
362 {
363    XArray* dst = (XArray*)opaque;
364    (void) VG_(addBytesToXA)( dst, &c, 1 );
365 }
366 
VG_(xaprintf)367 void VG_(xaprintf)( XArray* dst, const HChar* format, ... )
368 {
369    va_list vargs;
370    va_start(vargs, format);
371    VG_(vcbprintf)( add_char_to_XA, (void*)dst, format, vargs );
372    va_end(vargs);
373 }
374 
375 
376 /*--------------------------------------------------------------------*/
377 /*--- end                                               m_xarray.c ---*/
378 /*--------------------------------------------------------------------*/
379