| /* 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. */ | |
| // java.util.HashMap | |
| #ifndef _DBE_HASHMAP_H | |
| #define _DBE_HASHMAP_H | |
| #include "vec.h" | |
| #include "util.h" | |
| #include "StringBuilder.h" | |
| #include "Histable.h" | |
| #include "MemObject.h" | |
| template <typename Key_t> inline int get_hash_code (Key_t a); | |
| template <typename Key_t> inline bool is_equals (Key_t a, Key_t b); | |
| template <typename Key_t> inline Key_t copy_key (Key_t a); | |
| template <typename Key_t> inline void delete_key (Key_t a); | |
| // Specialization for char* | |
| template<> inline int | |
| get_hash_code (char *a) | |
| { | |
| return (int) (crc64 (a, strlen (a)) & 0x7fffffff); | |
| } | |
| template<> inline bool | |
| is_equals (char *a, char *b) | |
| { | |
| return dbe_strcmp (a, b) == 0; | |
| } | |
| template<> inline char * | |
| copy_key (char *a) | |
| { | |
| return dbe_strdup (a); | |
| } | |
| template<> inline void | |
| delete_key (char *a) | |
| { | |
| return free (a); | |
| } | |
| template<> inline int | |
| get_hash_code (uint64_t a) | |
| { | |
| return (int) (a & 0x7fffffff); | |
| } | |
| template<> inline bool | |
| is_equals (uint64_t a, uint64_t b) | |
| { | |
| return a == b; | |
| } | |
| template<> inline uint64_t | |
| copy_key (uint64_t a) | |
| { | |
| return a; | |
| } | |
| template<> inline void | |
| delete_key (uint64_t a) | |
| { | |
| a = a; | |
| } | |
| template<> inline int | |
| get_hash_code (Histable* a) | |
| { | |
| return (int) (a->id & 0x7fffffff); | |
| } | |
| template<> inline bool | |
| is_equals (Histable* a, Histable* b) | |
| { | |
| return a == b; | |
| } | |
| template<> inline Histable* | |
| copy_key (Histable* a) | |
| { | |
| return a; | |
| } | |
| template<> inline void | |
| delete_key (Histable* a) | |
| { | |
| a->id = a->id; | |
| } | |
| template<> inline int | |
| get_hash_code (MemObj* a) | |
| { | |
| return (int) (a->id & 0x7fffffff); | |
| } | |
| template<> inline bool | |
| is_equals (MemObj* a, MemObj* b) | |
| { | |
| return a == b; | |
| } | |
| template<> inline MemObj* | |
| copy_key (MemObj* a) | |
| { | |
| return a; | |
| } | |
| template<> inline void | |
| delete_key (MemObj* a) | |
| { | |
| a->id = a->id; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| class HashMap | |
| { | |
| public: | |
| HashMap (int initialCapacity = 0); | |
| ~HashMap () | |
| { | |
| clear (); | |
| delete vals; | |
| delete[] hashTable; | |
| } | |
| Value_t put (Key_t key, Value_t val); | |
| Value_t get (Key_t key); | |
| Value_t get (Key_t key, Value_t val); // Create a new map if key is not here | |
| void clear (); | |
| Value_t remove (Key_t); | |
| Vector<Value_t> *values (Key_t key); // Return a list of values for 'key' | |
| bool | |
| containsKey (Key_t key) | |
| { | |
| Value_t p = get (key); | |
| return p != NULL; | |
| }; | |
| Vector<Value_t> * | |
| values () | |
| { | |
| return vals; | |
| } | |
| void | |
| reset () | |
| { | |
| clear (); | |
| } | |
| int | |
| get_phaseIdx () | |
| { | |
| return phaseIdx; | |
| } | |
| void | |
| set_phaseIdx (int phase) | |
| { | |
| if (phase == 0) clear (); | |
| phaseIdx = phase; | |
| } | |
| char *dump (); | |
| private: | |
| enum | |
| { | |
| HASH_SIZE = 511, | |
| MAX_HASH_SIZE = 1048575 | |
| }; | |
| typedef struct Hash | |
| { | |
| Key_t key; | |
| Value_t val; | |
| struct Hash *next; | |
| } Hash_t; | |
| void resize (); | |
| int | |
| hashCode (Key_t key) | |
| { | |
| return get_hash_code (key) % hash_sz; | |
| } | |
| bool | |
| equals (Key_t a, Key_t b) | |
| { | |
| return is_equals (a, b); | |
| } | |
| Key_t | |
| copy (Key_t key) | |
| { | |
| return copy_key (key); | |
| } | |
| Hash_t **hashTable; | |
| Vector<Value_t> *vals; | |
| int phaseIdx; | |
| int hash_sz; | |
| int nelem; | |
| }; | |
| template <typename Key_t, typename Value_t> | |
| HashMap<Key_t, Value_t> | |
| ::HashMap (int initialCapacity) | |
| { | |
| if (initialCapacity > 0) | |
| vals = new Vector<Value_t>(initialCapacity); | |
| else | |
| vals = new Vector<Value_t>(); | |
| phaseIdx = 0; | |
| nelem = 0; | |
| hash_sz = HASH_SIZE; | |
| hashTable = new Hash_t*[hash_sz]; | |
| for (int i = 0; i < hash_sz; i++) | |
| hashTable[i] = NULL; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| void | |
| HashMap<Key_t, Value_t>::clear () | |
| { | |
| vals->reset (); | |
| phaseIdx = 0; | |
| nelem = 0; | |
| for (int i = 0; i < hash_sz; i++) | |
| { | |
| Hash_t *next; | |
| for (Hash_t *p = hashTable[i]; p; p = next) | |
| { | |
| next = p->next; | |
| delete_key (p->key); | |
| delete p; | |
| } | |
| hashTable[i] = NULL; | |
| } | |
| } | |
| template <typename Key_t, typename Value_t> | |
| void | |
| HashMap<Key_t, Value_t>::resize () | |
| { | |
| int old_hash_sz = hash_sz; | |
| hash_sz = old_hash_sz * 2 + 1; | |
| Hash_t **old_hash_table = hashTable; | |
| hashTable = new Hash_t*[hash_sz]; | |
| for (int i = 0; i < hash_sz; i++) | |
| hashTable[i] = NULL; | |
| nelem = 0; | |
| for (int i = 0; i < old_hash_sz; i++) | |
| { | |
| if (old_hash_table[i] != NULL) | |
| { | |
| Hash_t *old_p; | |
| Hash_t *p = old_hash_table[i]; | |
| while (p != NULL) | |
| { | |
| put (p->key, p->val); | |
| old_p = p; | |
| p = p->next; | |
| delete old_p; | |
| } | |
| } | |
| } | |
| delete[] old_hash_table; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| HashMap<Key_t, Value_t>::get (Key_t key) | |
| { | |
| int hash_code = hashCode (key); | |
| for (Hash_t *p = hashTable[hash_code]; p; p = p->next) | |
| if (equals (key, p->key)) | |
| return p->val; | |
| return NULL; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Vector<Value_t> * | |
| HashMap<Key_t, Value_t>::values (Key_t key) | |
| { | |
| Vector<Value_t> *list = new Vector<Value_t>(); | |
| int hash_code = hashCode (key); | |
| for (Hash_t *p = hashTable[hash_code]; p; p = p->next) | |
| { | |
| if (equals (key, p->key)) | |
| list->append (p->val); | |
| } | |
| return list; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| HashMap<Key_t, Value_t>::get (const Key_t key, Value_t val) | |
| { | |
| int hash_code = hashCode (key); | |
| Hash_t *p, *first = NULL; | |
| for (p = hashTable[hash_code]; p; p = p->next) | |
| { | |
| if (equals (key, p->key)) | |
| { | |
| if (first == NULL) | |
| first = p; | |
| if (val == p->val) | |
| return first->val; // Always return the first value | |
| } | |
| } | |
| vals->append (val); | |
| p = new Hash_t (); | |
| p->val = val; | |
| p->key = copy (key); | |
| if (first) | |
| { | |
| p->next = first->next; | |
| first->next = p; | |
| return first->val; // Always return the first value | |
| } | |
| else | |
| { | |
| p->next = hashTable[hash_code]; | |
| hashTable[hash_code] = p; | |
| return val; | |
| } | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| HashMap<Key_t, Value_t>::remove (Key_t key) | |
| { | |
| int hash_code = hashCode (key); | |
| Value_t val = NULL; | |
| for (Hash_t *prev = NULL, *p = hashTable[hash_code]; p != NULL;) | |
| { | |
| if (equals (key, p->key)) | |
| { | |
| if (prev == NULL) | |
| hashTable[hash_code] = p->next; | |
| else | |
| prev->next = p->next; | |
| if (val == NULL) | |
| val = p->val; | |
| delete_key (p->key); | |
| delete p; | |
| } | |
| else | |
| { | |
| prev = p; | |
| p = p->next; | |
| } | |
| } | |
| return val; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| HashMap<Key_t, Value_t>::put (Key_t key, Value_t val) | |
| { | |
| int hash_code = hashCode (key); | |
| vals->append (val); | |
| for (Hash_t *p = hashTable[hash_code]; p != NULL; p = p->next) | |
| { | |
| if (equals (key, p->key)) | |
| { | |
| Value_t v = p->val; | |
| p->val = val; | |
| return v; | |
| } | |
| } | |
| Hash_t *p = new Hash_t (); | |
| p->val = val; | |
| p->key = copy (key); | |
| p->next = hashTable[hash_code]; | |
| hashTable[hash_code] = p; | |
| nelem++; | |
| if (nelem == hash_sz) | |
| resize (); | |
| return val; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| char * | |
| HashMap<Key_t, Value_t>::dump () | |
| { | |
| StringBuilder sb; | |
| char buf[128]; | |
| snprintf (buf, sizeof (buf), "HashMap: size=%d ##########\n", vals->size ()); | |
| sb.append (buf); | |
| for (int i = 0; i < hash_sz; i++) | |
| { | |
| if (hashTable[i] == NULL) | |
| continue; | |
| snprintf (buf, sizeof (buf), "%3d:", i); | |
| sb.append (buf); | |
| char *s = NTXT (" "); | |
| for (Hash_t *p = hashTable[i]; p; p = p->next) | |
| { | |
| sb.append (s); | |
| s = NTXT (" "); | |
| sb.append (p->key); | |
| snprintf (buf, sizeof (buf), " --> 0x%p '%s'\n", | |
| p->val, p->val->get_name ()); | |
| sb.append (buf); | |
| } | |
| } | |
| return sb.toString (); | |
| } | |
| #endif // _DBE_HASHMAP_H |