/* Copyright (C) 2021-2023 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 #include #include #include // 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 void qsort (ITEM *, size_t, ExtCompareFunc, void *); template 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 *vec); Vector *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::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector::type (); template<> VecType Vector*>::type (); template<> VecType Vector*>::type (); template<> VecType Vector*>::type (); template<> void Vector::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 Vector::Vector (long sz) { count = 0; limit = sz > 0 ? sz : KILOCHUNK; // was 0; data = limit ? (ITEM *) malloc (sizeof (ITEM) * limit) : NULL; sorted = false; } template void Vector ::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 void Vector::append (const ITEM item) { // This routine will append "item" to the end of "this". if (count >= limit) resize (count); data[count++] = item; } template void Vector::addAll (Vector *vec) { if (vec) for (int i = 0, sz = vec->size (); i < sz; i++) append (vec->fetch (i)); } template Vector * Vector::copy () { // This routine will return a copy of "this". Vector *vector; vector = new Vector; 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 long Vector::find (const ITEM match_item) { for (long i = 0; i < size (); i++) if (match_item == get (i)) return i; return -1; } template long Vector::find_r (const ITEM match_item) { for (long i = size () - 1; i >= 0; i--) if (match_item == get (i)) return i; return -1; } template void Vector::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 ITEM Vector::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 void Vector::swap (long index1, long index2) { ITEM item; item = data[index1]; data[index1] = data[index2]; data[index2] = item; } template void Vector::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 long Vector::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 void Vector::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 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::destroy () { for (long i = 0; i < count; i++) free (data[i]); count = 0; } template inline void Vector::destroy () { for (long i = 0; i < count; i++) delete data[i]; count = 0; } #endif /* _VEC_H */