1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #ifndef _PERFAN_VEC_H
22 #define _PERFAN_VEC_H
23
24 #include <assert.h>
25 #include <inttypes.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 // This package implements a vector of items.
30
31 #define Destroy(x) if (x) { (x)->destroy(); delete (x); (x) = NULL; }
32 #define VecSize(x) ((x) ? (x)->size() : 0)
33
34 void destroy (void *vec); // Free up the "two-dimension" Vectors
35
36 typedef int (*CompareFunc)(const void*, const void*);
37 typedef int (*ExtCompareFunc)(const void*, const void*, const void*);
38 typedef int (*SearchFunc)(char*, char*);
39
40 extern "C"
41 {
42 typedef int (*StdCompareFunc)(const void*, const void*);
43 }
44
45 enum Search_type
46 {
47 LINEAR,
48 BINARY,
49 HASH
50 };
51
52 enum Direction
53 {
54 FORWARD,
55 REVERSE
56 };
57
58 enum VecType
59 {
60 VEC_VOID = 0,
61 VEC_INTEGER,
62 VEC_CHAR,
63 VEC_BOOL,
64 VEC_DOUBLE,
65 VEC_LLONG,
66 VEC_VOIDARR,
67 VEC_STRING,
68 VEC_INTARR,
69 VEC_BOOLARR,
70 VEC_LLONGARR,
71 VEC_STRINGARR,
72 VEC_DOUBLEARR
73 };
74
75 template <class ITEM> void
76 qsort (ITEM *, size_t, ExtCompareFunc, void *);
77
78 template <typename ITEM> class Vector
79 {
80 public:
81
Vector()82 Vector ()
83 {
84 count = 0;
85 data = NULL;
86 limit = 0;
87 sorted = false;
88 };
89
90 Vector (long sz);
91
92 virtual
~Vector()93 ~Vector ()
94 {
95 free (data);
96 }
97
98 void append (const ITEM item);
99 void addAll (Vector<ITEM> *vec);
100 Vector<ITEM> *copy (); // Return a copy of "this".
101
102 ITEM
fetch(long index)103 fetch (long index)
104 {
105 return data[index];
106 }
107
108 ITEM
get(long index)109 get (long index)
110 {
111 return data[index];
112 }
113
114 // Return the first index in "this" that equals "item".
115 // Return -1 if "item" is not found.
116 long find (const ITEM item);
117 long find_r (const ITEM item);
118
119 // Insert "item" into "index"'th slot of "this",
120 // moving everything over by 1.
121 void insert (long index, const ITEM item);
122
123 // Insert "item" after locating its appropriate index
124 void incorporate (const ITEM item, CompareFunc func);
125
126 // Remove and return the "index"'th item from "this",
127 // moving everything over by 1.
128 ITEM remove (long index);
129
130 // Swap two items in "this",
131 void swap (long index1, long index2);
132
133 long
size()134 size ()
135 {
136 return count;
137 }
138
139 // Store "item" into the "index"'th slot of "this".
140 void store (long index, const ITEM item);
141
142 void
put(long index,const ITEM item)143 put (long index, const ITEM item)
144 {
145 store (index, item);
146 }
147
148 // Sort the vector according to compare
149 void
150 sort (CompareFunc compare, void *arg = NULL)
151 {
152 qsort (data, count, (ExtCompareFunc) compare, arg);
153 sorted = true;
154 }
155
156 // Binary search, vector must be sorted
157 long bisearch (long start, long end, void *key, CompareFunc func);
158 void destroy (); // delete all vector elements (must be pointers!)
159
160 void
reset()161 reset ()
162 {
163 count = 0;
164 sorted = false;
165 }
166
167 bool
is_sorted()168 is_sorted ()
169 {
170 return sorted;
171 }
172
173 virtual VecType
type()174 type ()
175 {
176 return VEC_VOID;
177 }
178
179 virtual void
dump(const char *)180 dump (const char * /* msg */)
181 {
182 return;
183 }
184
185 private:
186
187 void resize (long index);
188
189 ITEM *data; // Pointer to data vector
190 long count; // Number of items
191 long limit; // Vector length (power of 2)
192 bool sorted;
193 };
194
195 template<> VecType Vector<int>::type ();
196 template<> VecType Vector<unsigned>::type ();
197 template<> VecType Vector<char>::type ();
198 template<> VecType Vector<bool>::type ();
199 template<> VecType Vector<double>::type ();
200 template<> VecType Vector<long long>::type ();
201 template<> VecType Vector<uint64_t>::type ();
202 template<> VecType Vector<void*>::type ();
203 template<> VecType Vector<char*>::type ();
204 template<> VecType Vector<Vector<int>*>::type ();
205 template<> VecType Vector<Vector<char*>*>::type ();
206 template<> VecType Vector<Vector<long long>*>::type ();
207 template<> void Vector<char *>::destroy ();
208
209 #define KILOCHUNK 1024
210 #define MEGACHUNK 1024*1024
211 #define GIGACHUNK 1024*1024*1024
212
213 // A standard looping construct:
214 #define Vec_loop(ITEM, vec, index, item) \
215 if (vec != NULL) \
216 for (index = 0, item = ((vec)->size() > 0) ? (vec)->fetch(0) : (ITEM)0; \
217 index < (vec)->size(); \
218 item = (++index < (vec)->size()) ? (vec)->fetch(index) : (ITEM)0)
219
220 template <typename ITEM>
Vector(long sz)221 Vector<ITEM>::Vector (long sz)
222 {
223 count = 0;
224 limit = sz > 0 ? sz : KILOCHUNK; // was 0;
225 data = limit ? (ITEM *) malloc (sizeof (ITEM) * limit) : NULL;
226 sorted = false;
227 }
228
229 template <typename ITEM> void
230 Vector<ITEM>
resize(long index)231 ::resize (long index)
232 {
233 if (index < limit)
234 return;
235 if (limit < 16)
236 limit = 16;
237 while (index >= limit)
238 {
239 if (limit > GIGACHUNK)
240 limit += GIGACHUNK; // Deoptimization for large experiments
241 else
242 limit = limit * 2;
243 }
244 data = (ITEM *) realloc (data, limit * sizeof (ITEM));
245 }
246
247 template <typename ITEM> void
append(const ITEM item)248 Vector<ITEM>::append (const ITEM item)
249 {
250 // This routine will append "item" to the end of "this".
251 if (count >= limit)
252 resize (count);
253 data[count++] = item;
254 }
255
256 template <typename ITEM> void
addAll(Vector<ITEM> * vec)257 Vector<ITEM>::addAll (Vector<ITEM> *vec)
258 {
259 if (vec)
260 for (int i = 0, sz = vec->size (); i < sz; i++)
261 append (vec->fetch (i));
262 }
263
264 template <typename ITEM> Vector<ITEM> *
copy()265 Vector<ITEM>::copy ()
266 {
267 // This routine will return a copy of "this".
268 Vector<ITEM> *vector;
269 vector = new Vector<ITEM>;
270 vector->count = count;
271 vector->limit = limit;
272 vector->data = (ITEM *) malloc (sizeof (ITEM) * limit);
273 (void) memcpy ((char *) vector->data, (char *) data, sizeof (ITEM) * count);
274 return vector;
275 }
276
277 template <typename ITEM> long
find(const ITEM match_item)278 Vector<ITEM>::find (const ITEM match_item)
279 {
280 for (long i = 0; i < size (); i++)
281 if (match_item == get (i))
282 return i;
283 return -1;
284 }
285
286 template <typename ITEM> long
find_r(const ITEM match_item)287 Vector<ITEM>::find_r (const ITEM match_item)
288 {
289 for (long i = size () - 1; i >= 0; i--)
290 if (match_item == get (i))
291 return i;
292 return -1;
293 }
294
295 template <typename ITEM> void
insert(long index,const ITEM item)296 Vector<ITEM>::insert (long index, const ITEM item)
297 {
298 // This routine will insert "item" into the "index"'th slot of "this".
299 // An error occurs if "index" > size().
300 // "index" is allowed to be equal to "count" in the case that
301 // you are inserting past the last element of the vector.
302 // In that case, the bcopy below becomes a no-op.
303 assert (index >= 0);
304 assert (index <= count);
305 append (item);
306 (void) memmove (((char *) (&data[index + 1])), (char *) (&data[index]),
307 (count - index - 1) * sizeof (ITEM));
308 data[index] = item;
309 }
310
311 template <typename ITEM> ITEM
remove(long index)312 Vector<ITEM>::remove (long index)
313 {
314 // This routine will remove the "index"'th item from "this" and
315 // return it. An error occurs if "index" >= size();.
316 assert (index >= 0);
317 assert (index < count);
318 ITEM item = data[index];
319 for (long i = index + 1; i < count; i++)
320 data[i - 1] = data[i];
321 count--;
322 // Bad code that works good when ITEM is a pointer type
323 data[count] = item;
324 return data[count];
325 }
326
327 template <typename ITEM> void
swap(long index1,long index2)328 Vector<ITEM>::swap (long index1, long index2)
329 {
330 ITEM item;
331 item = data[index1];
332 data[index1] = data[index2];
333 data[index2] = item;
334 }
335
336 template <typename ITEM> void
store(long index,const ITEM item)337 Vector<ITEM>::store (long index, const ITEM item)
338 {
339 if (index >= count)
340 {
341 resize (index);
342 memset (&data[count], 0, (index - count) * sizeof (ITEM));
343 count = index + 1;
344 }
345 data[index] = item;
346 }
347
348 // This routine performs a binary search across
349 // the entire vector, with "start" being the low boundary.
350 // It is assumed that the vector is SORTED in
351 // ASCENDING ORDER by the same criteria as the
352 // compare function.
353 // If no match is found, -1 is returned.
354 template <typename ITEM> long
bisearch(long start,long end,void * key,CompareFunc compare)355 Vector<ITEM>::bisearch (long start, long end, void *key, CompareFunc compare)
356 {
357 ITEM *itemp;
358 if (end == -1)
359 end = count;
360 if (start >= end)
361 return -1; // start exceeds limit
362 itemp = (ITEM *) bsearch ((char *) key, (char *) &data[start],
363 end - start, sizeof (ITEM), (StdCompareFunc) compare);
364 if (itemp == (ITEM *) 0)
365 return -1; // not found
366 return (long) (itemp - data);
367 }
368
369 template <typename ITEM> void
incorporate(const ITEM item,CompareFunc compare)370 Vector<ITEM>::incorporate (const ITEM item, CompareFunc compare)
371 {
372 long lt = 0;
373 long rt = count - 1;
374 while (lt <= rt)
375 {
376 long md = (lt + rt) / 2;
377 if (compare (data[md], item) < 0)
378 lt = md + 1;
379 else
380 rt = md - 1;
381 }
382 if (lt == count)
383 append (item);
384 else
385 insert (lt, item);
386 }
387
388 #define QSTHRESH 6
389
390 template <typename ITEM> void
qsort(ITEM * base,size_t nelem,ExtCompareFunc qcmp,void * arg)391 qsort (ITEM *base, size_t nelem, ExtCompareFunc qcmp, void *arg)
392 {
393 for (;;)
394 {
395 // For small arrays use insertion sort
396 if (nelem < QSTHRESH)
397 {
398 for (size_t i = 1; i < nelem; i++)
399 {
400 ITEM *p = base + i;
401 ITEM *q = p - 1;
402 if (qcmp (q, p, arg) > 0)
403 {
404 ITEM t = *p;
405 *p = *q;
406 while (q > base && qcmp (q - 1, &t, arg) > 0)
407 {
408 *q = *(q - 1);
409 --q;
410 }
411 *q = t;
412 }
413 }
414 return;
415 }
416
417 ITEM *last = base + nelem - 1;
418 ITEM *mid = base + nelem / 2;
419 // Sort the first, middle, and last elements
420 ITEM *a1 = base, *a2, *a3;
421 if (qcmp (base, mid, arg) > 0)
422 {
423 if (qcmp (mid, last, arg) > 0)
424 { // l-m-b
425 a2 = last;
426 a3 = last;
427 }
428 else if (qcmp (base, last, arg) > 0)
429 { // l-b-m
430 a2 = mid;
431 a3 = last;
432 }
433 else
434 { // m-b-l
435 a2 = mid;
436 a3 = mid;
437 }
438 }
439 else if (qcmp (mid, last, arg) > 0)
440 {
441 a1 = mid;
442 a3 = last;
443 if (qcmp (base, last, arg) > 0) // m-l-b
444 a2 = base;
445 else // b-l-m
446 a2 = a3;
447 }
448 else // b-m-l
449 a3 = a2 = a1;
450 if (a1 != a2)
451 {
452 ITEM t = *a1;
453 *a1 = *a2;
454 if (a2 != a3)
455 *a2 = *a3;
456 *a3 = t;
457 }
458
459 // Partition
460 ITEM *i = base + 1;
461 ITEM *j = last - 1;
462 for (;;)
463 {
464 while (i < mid && qcmp (i, mid, arg) <= 0)
465 i++;
466 while (j > mid && qcmp (mid, j, arg) <= 0)
467 j--;
468 if (i == j)
469 break;
470 ITEM t = *i;
471 *i = *j;
472 *j = t;
473 if (i == mid)
474 {
475 mid = j;
476 i++;
477 }
478 else if (j == mid)
479 {
480 mid = i;
481 j--;
482 }
483 else
484 {
485 i++;
486 j--;
487 }
488 }
489
490 // Compare two partitions. Do the smaller one by recursion
491 // and loop over the larger one.
492 size_t nleft = mid - base;
493 size_t nright = nelem - nleft - 1;
494 if (nleft <= nright)
495 {
496 qsort (base, nleft, qcmp, arg);
497 base = mid + 1;
498 nelem = nright;
499 }
500 else
501 {
502 qsort (mid + 1, nright, qcmp, arg);
503 nelem = nleft;
504 }
505 }
506 }
507
508 template<> inline void
destroy()509 Vector<char*>::destroy ()
510 {
511 for (long i = 0; i < count; i++)
512 free (data[i]);
513 count = 0;
514 }
515
516 template <typename ITEM> inline void
destroy()517 Vector<ITEM>::destroy ()
518 {
519 for (long i = 0; i < count; i++)
520 delete data[i];
521 count = 0;
522 }
523
524 #endif /* _VEC_H */
525