#pragma once /************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2023 Melin Software HB 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 of the License, 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, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "intkeymap.hpp" template intkeymap::intkeymap() { siz = 17; allocFactor = 1.5; keys = new keypair[siz]; hash1 = siz / 2 + 3; hash2 = siz / 3 + 2; used = 0; next = 0; level = 0; parent = 0; dummy = 0; noValue = 0; clear(); } template intkeymap::intkeymap(int _size) { allocFactor = 1.3; siz = optsize(_size); keys = new keypair[siz]; hash1 = siz / 2 + 3; hash2 = siz / 3 + 2; used = 0; next = 0; level = 0; parent = 0; dummy = T(); noValue = T(); clear(); } template intkeymap::intkeymap(const intkeymap &co) { allocFactor = co.allocFactor; siz = co.siz; keys = new keypair[siz]; hash1 = co.hash1; hash2 = co.hash2; used = co.used; level = co.level; dummy = co.dummy; noValue = co.noValue; for (unsigned k=0; k(*co.next); next->parent = this; } } template const intkeymap &intkeymap::operator=(const intkeymap &co) { clear(); delete[] keys; allocFactor = co.allocFactor; siz = co.siz; keys = new keypair[siz]; hash1 = co.hash1; hash2 = co.hash2; used = co.used; level = co.level; dummy = co.dummy; noValue = co.noValue; for (unsigned k = 0; k(*co.next); next->parent = this; } return *this; } template intkeymap::~intkeymap() { delete[] keys; if (next) delete next; } template void intkeymap::clear() { for (unsigned k=0;k void intkeymap::insert(KEY key, const T &value) { if (key == NoKey) { noValue = value; return; } keypair *ptr = (keypair *)lookup(key); if (ptr) { ptr->key = key; ptr->value = value; return; } unsigned hk = unsigned(key) % siz; if (keys[hk].key == NoKey) used++; if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; keys[hk].value = value; return; } hk = unsigned(key + hash1) % siz; if (keys[hk].key == NoKey) used++; if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; keys[hk].value = value; return; } hk = unsigned(key + hash2) % siz; if (keys[hk].key == NoKey) used++; if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; keys[hk].value = value; return; } if (next) { next->insert(key, value); return; } else if (level < 3) { next = new intkeymap(siz/2); next->level = level + 1; next->parent = this; next->insert(key, value); return; } rehash(0, key, value); } template T &intkeymap::get(KEY key) { keypair *ptr = (keypair *)lookup(key); if (ptr) return ptr->value; if (key == NoKey) return noValue; unsigned hk = unsigned(key) % siz; if (keys[hk].key == NoKey) { used++; keys[hk].value = T(); } if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; return keys[hk].value; } hk = unsigned(key + hash1) % siz; if (keys[hk].key == NoKey) { used++; keys[hk].value = T(); } if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; return keys[hk].value; } hk = unsigned(key + hash2) % siz; if (keys[hk].key == NoKey) { keys[hk].value = T(); used++; } if (keys[hk].key == NoKey || keys[hk].key == key) { keys[hk].key = key; return keys[hk].value; } if (next) { return next->get(key); } else if (level < 3) { next = new intkeymap(siz/2); next->level = level + 1; next->parent = this; return next->get(key); } return rehash(0, key, T()); } template void intkeymap::remove(KEY key) { unsigned hk = unsigned(key) % siz; if (keys[hk].key == key) { keys[hk].key = NoKey; used--; return; } hk = unsigned(key + hash1) % siz; if (keys[hk].key == key) { keys[hk].key = NoKey; used--; return; } hk = unsigned(key + hash2) % siz; if (keys[hk].key == key) { keys[hk].key = NoKey; used--; return; } if (next) { next->remove(key); return; } } template T &intkeymap::rehash(int _siz, KEY key, const T &value) { if (parent) return parent->rehash(_siz+used, key, value); else { intkeymap nm(int((_siz+used)*allocFactor)); if (key != NoKey) nm.insert(key, value); intkeymap *tmap = this; while (tmap) { int tsize = tmap->siz; keypair *tkeys = tmap->keys; for (int k=0; knext; } // Swap keypair *oldkeys = keys; //Take next delete next; next = nm.next; nm.next = 0; if (next) next->parent = this; //Take keys keys = nm.keys; nm.keys = 0; delete[] oldkeys; // Copy relevant data siz = nm.siz; used = nm.used; hash1 = nm.hash1; hash2 = nm.hash2; if (key!=NoKey) return get(key); return dummy; } } template bool intkeymap::lookup(KEY key, T &value) const { keypair *ptr = (keypair *)lookup(key); if (ptr) { value = ptr->value; return true; } else { value = T(); return false; } } template void *intkeymap::lookup(KEY key) const { if (key == NoKey) { return 0; } unsigned hk = unsigned(key) % siz; if (keys[hk].key == key) { return (void *)&keys[hk]; } hk = unsigned(key + hash1) % siz; if (keys[hk].key == key) { return (void *)&keys[hk]; } hk = unsigned(key + hash2) % siz; if (keys[hk].key == key) { return (void *)&keys[hk]; } if (next) return next->lookup(key); else return 0; } template int intkeymap::optsize(int a) { if (a<5) a = 5; if ((a&1) == 0) a++; while (true) { if (a%3 == 0) a+=2; else if (a%5 == 0) a+=2; else if (a%7 == 0) a+=2; else if (a%11 == 0) a+=2; else if (a%13 == 0) a+=2; else return a; } } template int intkeymap::size() const { if (next) return used + next->size(); else return used; } template bool intkeymap::empty() const { return used==0 && (next==0 || next->empty()); } template void intkeymap::resize(int size) { allocFactor = 1.0; rehash(size, NoKey, 0); allocFactor = 1.3; }