|  | /* Copyright (C) 2021 Free Software Foundation, Inc. | 
|  | Contributed by Oracle. | 
|  |  | 
|  | This file is part of GNU Binutils. | 
|  |  | 
|  | 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #ifndef _PERFAN_VEC_H | 
|  | #define _PERFAN_VEC_H | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <inttypes.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | // This package implements a vector of items. | 
|  |  | 
|  | #define Destroy(x)      if (x) { (x)->destroy(); delete (x); (x) = NULL; } | 
|  | #define VecSize(x)      ((x) ? (x)->size() : 0) | 
|  |  | 
|  | void destroy (void *vec); // Free up the "two-dimension" Vectors | 
|  |  | 
|  | typedef int (*CompareFunc)(const void*, const void*); | 
|  | typedef int (*ExtCompareFunc)(const void*, const void*, const void*); | 
|  | typedef int (*SearchFunc)(char*, char*); | 
|  |  | 
|  | extern "C" | 
|  | { | 
|  | typedef int (*StdCompareFunc)(const void*, const void*); | 
|  | } | 
|  |  | 
|  | enum Search_type | 
|  | { | 
|  | LINEAR, | 
|  | BINARY, | 
|  | HASH | 
|  | }; | 
|  |  | 
|  | enum Direction | 
|  | { | 
|  | FORWARD, | 
|  | REVERSE | 
|  | }; | 
|  |  | 
|  | enum VecType | 
|  | { | 
|  | VEC_VOID = 0, | 
|  | VEC_INTEGER, | 
|  | VEC_CHAR, | 
|  | VEC_BOOL, | 
|  | VEC_DOUBLE, | 
|  | VEC_LLONG, | 
|  | VEC_VOIDARR, | 
|  | VEC_STRING, | 
|  | VEC_INTARR, | 
|  | VEC_BOOLARR, | 
|  | VEC_LLONGARR, | 
|  | VEC_STRINGARR, | 
|  | VEC_DOUBLEARR | 
|  | }; | 
|  |  | 
|  | template <class ITEM> void | 
|  | qsort (ITEM *, size_t, ExtCompareFunc, void *); | 
|  |  | 
|  | template <typename ITEM> class Vector | 
|  | { | 
|  | public: | 
|  |  | 
|  | Vector () | 
|  | { | 
|  | count = 0; | 
|  | data = NULL; | 
|  | limit = 0; | 
|  | sorted = false; | 
|  | }; | 
|  |  | 
|  | Vector (long sz); | 
|  |  | 
|  | virtual | 
|  | ~Vector () | 
|  | { | 
|  | free (data); | 
|  | } | 
|  |  | 
|  | void append (const ITEM item); | 
|  | void addAll (Vector<ITEM> *vec); | 
|  | Vector<ITEM> *copy ();        // Return a copy of "this". | 
|  |  | 
|  | ITEM | 
|  | fetch (long index) | 
|  | { | 
|  | return data[index]; | 
|  | } | 
|  |  | 
|  | ITEM | 
|  | get (long index) | 
|  | { | 
|  | return data[index]; | 
|  | } | 
|  |  | 
|  | // Return the first index in "this" that equals "item". | 
|  | // Return -1 if "item" is not found. | 
|  | long find (const ITEM item); | 
|  | long find_r (const ITEM item); | 
|  |  | 
|  | // Insert "item" into "index"'th slot of "this", | 
|  | // moving everything over by 1. | 
|  | void insert (long index, const ITEM item); | 
|  |  | 
|  | // Insert "item" after locating its appropriate index | 
|  | void incorporate (const ITEM item, CompareFunc func); | 
|  |  | 
|  | // Remove and return the "index"'th item from "this", | 
|  | // moving everything over by 1. | 
|  | ITEM remove (long index); | 
|  |  | 
|  | // Swap two items in "this", | 
|  | void swap (long index1, long index2); | 
|  |  | 
|  | long | 
|  | size () | 
|  | { | 
|  | return count; | 
|  | } | 
|  |  | 
|  | // Store "item" into the "index"'th slot of "this". | 
|  | void store (long index, const ITEM item); | 
|  |  | 
|  | void | 
|  | put (long index, const ITEM item) | 
|  | { | 
|  | store (index, item); | 
|  | } | 
|  |  | 
|  | // Sort the vector according to compare | 
|  | void | 
|  | sort (CompareFunc compare, void *arg = NULL) | 
|  | { | 
|  | qsort (data, count, (ExtCompareFunc) compare, arg); | 
|  | sorted = true; | 
|  | } | 
|  |  | 
|  | // Binary search, vector must be sorted | 
|  | long bisearch (long start, long end, void *key, CompareFunc func); | 
|  | void destroy ();      // delete all vector elements (must be pointers!) | 
|  |  | 
|  | void | 
|  | reset () | 
|  | { | 
|  | count = 0; | 
|  | sorted = false; | 
|  | } | 
|  |  | 
|  | bool | 
|  | is_sorted () | 
|  | { | 
|  | return sorted; | 
|  | } | 
|  |  | 
|  | virtual VecType | 
|  | type () | 
|  | { | 
|  | return VEC_VOID; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | dump (const char * /* msg */) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | void resize (long index); | 
|  |  | 
|  | ITEM *data;   // Pointer to data vector | 
|  | long count;   // Number of items | 
|  | long limit;   // Vector length (power of 2) | 
|  | bool sorted; | 
|  | }; | 
|  |  | 
|  | template<> VecType Vector<int>::type (); | 
|  | template<> VecType Vector<unsigned>::type (); | 
|  | template<> VecType Vector<char>::type (); | 
|  | template<> VecType Vector<bool>::type (); | 
|  | template<> VecType Vector<double>::type (); | 
|  | template<> VecType Vector<long long>::type (); | 
|  | template<> VecType Vector<uint64_t>::type (); | 
|  | template<> VecType Vector<void*>::type (); | 
|  | template<> VecType Vector<char*>::type (); | 
|  | template<> VecType Vector<Vector<int>*>::type (); | 
|  | template<> VecType Vector<Vector<char*>*>::type (); | 
|  | template<> VecType Vector<Vector<long long>*>::type (); | 
|  | template<> void Vector<char *>::destroy (); | 
|  |  | 
|  | #define KILOCHUNK   1024 | 
|  | #define MEGACHUNK   1024*1024 | 
|  | #define GIGACHUNK   1024*1024*1024 | 
|  |  | 
|  | // A standard looping construct: | 
|  | #define Vec_loop(ITEM, vec, index, item) \ | 
|  | if (vec != NULL) \ | 
|  | for (index = 0, item = ((vec)->size() > 0) ? (vec)->fetch(0) : (ITEM)0; \ | 
|  | index < (vec)->size(); \ | 
|  | item = (++index < (vec)->size()) ? (vec)->fetch(index) : (ITEM)0) | 
|  |  | 
|  | template <typename ITEM> | 
|  | Vector<ITEM>::Vector (long sz) | 
|  | { | 
|  | count = 0; | 
|  | limit = sz > 0 ? sz : KILOCHUNK; // was 0; | 
|  | data = limit ? (ITEM *) malloc (sizeof (ITEM) * limit) : NULL; | 
|  | sorted = false; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM> | 
|  | ::resize (long index) | 
|  | { | 
|  | if (index < limit) | 
|  | return; | 
|  | if (limit < 16) | 
|  | limit = 16; | 
|  | while (index >= limit) | 
|  | { | 
|  | if (limit > GIGACHUNK) | 
|  | limit += GIGACHUNK; // Deoptimization for large experiments | 
|  | else | 
|  | limit = limit * 2; | 
|  | } | 
|  | data = (ITEM *) realloc (data, limit * sizeof (ITEM)); | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::append (const ITEM item) | 
|  | { | 
|  | // This routine will append "item" to the end of "this". | 
|  | if (count >= limit) | 
|  | resize (count); | 
|  | data[count++] = item; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::addAll (Vector<ITEM> *vec) | 
|  | { | 
|  | if (vec) | 
|  | for (int i = 0, sz = vec->size (); i < sz; i++) | 
|  | append (vec->fetch (i)); | 
|  | } | 
|  |  | 
|  | template <typename ITEM> Vector<ITEM> * | 
|  | Vector<ITEM>::copy () | 
|  | { | 
|  | // This routine will return a copy of "this". | 
|  | Vector<ITEM> *vector; | 
|  | vector = new Vector<ITEM>; | 
|  | vector->count = count; | 
|  | vector->limit = limit; | 
|  | vector->data = (ITEM *) malloc (sizeof (ITEM) * limit); | 
|  | (void) memcpy ((char *) vector->data, (char *) data, sizeof (ITEM) * count); | 
|  | return vector; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> long | 
|  | Vector<ITEM>::find (const ITEM match_item) | 
|  | { | 
|  | for (long i = 0; i < size (); i++) | 
|  | if (match_item == get (i)) | 
|  | return i; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> long | 
|  | Vector<ITEM>::find_r (const ITEM match_item) | 
|  | { | 
|  | for (long i = size () - 1; i >= 0; i--) | 
|  | if (match_item == get (i)) | 
|  | return i; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::insert (long index, const ITEM item) | 
|  | { | 
|  | // This routine will insert "item" into the "index"'th slot of "this". | 
|  | // An error occurs if "index" > size(). | 
|  | // "index" is allowed to be equal to "count" in the case that | 
|  | // you are inserting past the last element of the vector. | 
|  | // In that case, the bcopy below becomes a no-op. | 
|  | assert (index >= 0); | 
|  | assert (index <= count); | 
|  | append (item); | 
|  | (void) memmove (((char *) (&data[index + 1])), (char *) (&data[index]), | 
|  | (count - index - 1) * sizeof (ITEM)); | 
|  | data[index] = item; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> ITEM | 
|  | Vector<ITEM>::remove (long index) | 
|  | { | 
|  | // This routine will remove the "index"'th item from "this" and | 
|  | // return it.  An error occurs if "index" >= size();. | 
|  | assert (index >= 0); | 
|  | assert (index < count); | 
|  | ITEM item = data[index]; | 
|  | for (long i = index + 1; i < count; i++) | 
|  | data[i - 1] = data[i]; | 
|  | count--; | 
|  | // Bad code that works good when ITEM is a pointer type | 
|  | data[count] = item; | 
|  | return data[count]; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::swap (long index1, long index2) | 
|  | { | 
|  | ITEM item; | 
|  | item = data[index1]; | 
|  | data[index1] = data[index2]; | 
|  | data[index2] = item; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::store (long index, const ITEM item) | 
|  | { | 
|  | if (index >= count) | 
|  | { | 
|  | resize (index); | 
|  | memset (&data[count], 0, (index - count) * sizeof (ITEM)); | 
|  | count = index + 1; | 
|  | } | 
|  | data[index] = item; | 
|  | } | 
|  |  | 
|  | // This routine performs a binary search across | 
|  | // the entire vector, with "start" being the low boundary. | 
|  | // It is assumed that the vector is SORTED in | 
|  | // ASCENDING ORDER by the same criteria as the | 
|  | // compare function. | 
|  | // If no match is found, -1 is returned. | 
|  | template <typename ITEM> long | 
|  | Vector<ITEM>::bisearch (long start, long end, void *key, CompareFunc compare) | 
|  | { | 
|  | ITEM *itemp; | 
|  | if (end == -1) | 
|  | end = count; | 
|  | if (start >= end) | 
|  | return -1; // start exceeds limit | 
|  | itemp = (ITEM *) bsearch ((char *) key, (char *) &data[start], | 
|  | end - start, sizeof (ITEM), (StdCompareFunc) compare); | 
|  | if (itemp == (ITEM *) 0) | 
|  | return -1; // not found | 
|  | return (long) (itemp - data); | 
|  | } | 
|  |  | 
|  | template <typename ITEM> void | 
|  | Vector<ITEM>::incorporate (const ITEM item, CompareFunc compare) | 
|  | { | 
|  | long lt = 0; | 
|  | long rt = count - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | long md = (lt + rt) / 2; | 
|  | if (compare (data[md], item) < 0) | 
|  | lt = md + 1; | 
|  | else | 
|  | rt = md - 1; | 
|  | } | 
|  | if (lt == count) | 
|  | append (item); | 
|  | else | 
|  | insert (lt, item); | 
|  | } | 
|  |  | 
|  | #define QSTHRESH 6 | 
|  |  | 
|  | template <typename ITEM> void | 
|  | qsort (ITEM *base, size_t nelem, ExtCompareFunc qcmp, void *arg) | 
|  | { | 
|  | for (;;) | 
|  | { | 
|  | // For small arrays use insertion sort | 
|  | if (nelem < QSTHRESH) | 
|  | { | 
|  | for (size_t i = 1; i < nelem; i++) | 
|  | { | 
|  | ITEM *p = base + i; | 
|  | ITEM *q = p - 1; | 
|  | if (qcmp (q, p, arg) > 0) | 
|  | { | 
|  | ITEM t = *p; | 
|  | *p = *q; | 
|  | while (q > base && qcmp (q - 1, &t, arg) > 0) | 
|  | { | 
|  | *q = *(q - 1); | 
|  | --q; | 
|  | } | 
|  | *q = t; | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | ITEM *last = base + nelem - 1; | 
|  | ITEM *mid = base + nelem / 2; | 
|  | // Sort the first, middle, and last elements | 
|  | ITEM *a1 = base, *a2, *a3; | 
|  | if (qcmp (base, mid, arg) > 0) | 
|  | { | 
|  | if (qcmp (mid, last, arg) > 0) | 
|  | { // l-m-b | 
|  | a2 = last; | 
|  | a3 = last; | 
|  | } | 
|  | else if (qcmp (base, last, arg) > 0) | 
|  | { // l-b-m | 
|  | a2 = mid; | 
|  | a3 = last; | 
|  | } | 
|  | else | 
|  | { // m-b-l | 
|  | a2 = mid; | 
|  | a3 = mid; | 
|  | } | 
|  | } | 
|  | else if (qcmp (mid, last, arg) > 0) | 
|  | { | 
|  | a1 = mid; | 
|  | a3 = last; | 
|  | if (qcmp (base, last, arg) > 0)  // m-l-b | 
|  | a2 = base; | 
|  | else  // b-l-m | 
|  | a2 = a3; | 
|  | } | 
|  | else // b-m-l | 
|  | a3 = a2 = a1; | 
|  | if (a1 != a2) | 
|  | { | 
|  | ITEM t = *a1; | 
|  | *a1 = *a2; | 
|  | if (a2 != a3) | 
|  | *a2 = *a3; | 
|  | *a3 = t; | 
|  | } | 
|  |  | 
|  | // Partition | 
|  | ITEM *i = base + 1; | 
|  | ITEM *j = last - 1; | 
|  | for (;;) | 
|  | { | 
|  | while (i < mid && qcmp (i, mid, arg) <= 0) | 
|  | i++; | 
|  | while (j > mid && qcmp (mid, j, arg) <= 0) | 
|  | j--; | 
|  | if (i == j) | 
|  | break; | 
|  | ITEM t = *i; | 
|  | *i = *j; | 
|  | *j = t; | 
|  | if (i == mid) | 
|  | { | 
|  | mid = j; | 
|  | i++; | 
|  | } | 
|  | else if (j == mid) | 
|  | { | 
|  | mid = i; | 
|  | j--; | 
|  | } | 
|  | else | 
|  | { | 
|  | i++; | 
|  | j--; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Compare two partitions. Do the smaller one by recursion | 
|  | // and loop over the larger one. | 
|  | size_t nleft = mid - base; | 
|  | size_t nright = nelem - nleft - 1; | 
|  | if (nleft <= nright) | 
|  | { | 
|  | qsort (base, nleft, qcmp, arg); | 
|  | base = mid + 1; | 
|  | nelem = nright; | 
|  | } | 
|  | else | 
|  | { | 
|  | qsort (mid + 1, nright, qcmp, arg); | 
|  | nelem = nleft; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | template<> inline void | 
|  | Vector<char*>::destroy () | 
|  | { | 
|  | for (long i = 0; i < count; i++) | 
|  | free (data[i]); | 
|  | count = 0; | 
|  | } | 
|  |  | 
|  | template <typename ITEM> inline void | 
|  | Vector<ITEM>::destroy () | 
|  | { | 
|  | for (long i = 0; i < count; i++) | 
|  | delete data[i]; | 
|  | count = 0; | 
|  | } | 
|  |  | 
|  | #endif /* _VEC_H */ |