/* 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 _DBE_DEFAULTMAP_H #define _DBE_DEFAULTMAP_H #include #include #include template class DefaultMap : public Map { public: DefaultMap (); ~DefaultMap (); void clear (); void put (Key_t key, Value_t val); Value_t get (Key_t key); Value_t get (Key_t key, typename Map::Relation rel); Value_t remove (Key_t); Vector *keySet (); Vector *values (); private: struct Entry { Key_t key; Value_t val; }; static const int CHUNK_SIZE; static const int HTABLE_SIZE; int entries; int nchunks; Entry **chunks; Vector *index; Entry **hashTable; }; template const int DefaultMap::CHUNK_SIZE = 16384; template const int DefaultMap::HTABLE_SIZE = 1024; template DefaultMap::DefaultMap () { entries = 0; nchunks = 0; chunks = NULL; index = new Vector; hashTable = new Entry*[HTABLE_SIZE]; for (int i = 0; i < HTABLE_SIZE; i++) hashTable[i] = NULL; } template DefaultMap::~DefaultMap () { for (int i = 0; i < nchunks; i++) delete[] chunks[i]; delete[] chunks; delete index; delete[] hashTable; } template void DefaultMap::clear () { entries = 0; index->reset (); for (int i = 0; i < HTABLE_SIZE; i++) hashTable[i] = NULL; } template inline unsigned hash (Key_t key) { unsigned h = (unsigned) ((unsigned long) key); h ^= (h >> 20) ^ (h >> 12); return (h ^ (h >> 7) ^ (h >> 4)); } template void DefaultMap::put (Key_t key, Value_t val) { unsigned idx = hash (key) % HTABLE_SIZE; Entry *entry = hashTable[idx]; if (entry && entry->key == key) { entry->val = val; return; } int lo = 0; int hi = entries - 1; while (lo <= hi) { int md = (lo + hi) / 2; entry = index->fetch (md); int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0; if (cmp < 0) lo = md + 1; else if (cmp > 0) hi = md - 1; else { entry->val = val; return; } } if (entries >= nchunks * CHUNK_SIZE) { nchunks++; // Reallocate Entry chunk array Entry **new_chunks = new Entry*[nchunks]; for (int i = 0; i < nchunks - 1; i++) new_chunks[i] = chunks[i]; delete[] chunks; chunks = new_chunks; // Allocate new chunk for entries. chunks[nchunks - 1] = new Entry[CHUNK_SIZE]; } entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE]; entry->key = key; entry->val = val; index->insert (lo, entry); hashTable[idx] = entry; entries++; } template Value_t DefaultMap::get (Key_t key) { unsigned idx = hash (key) % HTABLE_SIZE; Entry *entry = hashTable[idx]; if (entry && entry->key == key) return entry->val; int lo = 0; int hi = entries - 1; while (lo <= hi) { int md = (lo + hi) / 2; entry = index->fetch (md); int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0; if (cmp < 0) lo = md + 1; else if (cmp > 0) hi = md - 1; else { hashTable[idx] = entry; return entry->val; } } return (Value_t) 0; } template Value_t DefaultMap::get (Key_t key, typename Map::Relation rel) { if (rel != Map::REL_EQ) return (Value_t) 0; return get (key); } template Value_t DefaultMap::remove (Key_t) { // Not implemented if (1) assert (0); return (Value_t) 0; } template Vector * DefaultMap::values () { Vector *vals = new Vector(entries); for (int i = 0; i < entries; ++i) { Entry *entry = index->fetch (i); vals->append (entry->val); } return vals; } template Vector * DefaultMap::keySet () { Vector *keys = new Vector(entries); for (int i = 0; i < entries; ++i) { Entry *entry = index->fetch (i); keys->append (entry->key); } return keys; } #endif