/* * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation * * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov * * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: * http://iki.fi/bisqwit/source/adlmidi.html * * 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 * 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 . */ #include "opnmidi_bankmap.h" #include template inline BasicBankMap::BasicBankMap() : m_freeslots(NULL), m_size(0), m_capacity(0) { m_buckets.reset(new Slot *[hash_buckets]()); } template inline size_t BasicBankMap::hash(key_type key) { // disregard the 0 high bit in LSB key = (key & 127) | ((key >> 8) << 7); // take low part as hash value return key & (hash_buckets - 1); } template void BasicBankMap::reserve(size_t capacity) { if(m_capacity >= capacity) return; size_t need = capacity - m_capacity; const size_t minalloc = static_cast(minimum_allocation); need = (need < minalloc) ? minalloc : need; AdlMIDI_SPtrArray slotz; slotz.reset(new Slot[need]); m_allocations.push_back(slotz); m_capacity += need; for(size_t i = need; i-- > 0;) free_slot(&slotz[i]); } template typename BasicBankMap::iterator BasicBankMap::begin() const { iterator it(m_buckets.get(), NULL, 0); while(it.index < hash_buckets && !(it.slot = m_buckets[it.index])) ++it.index; return it; } template typename BasicBankMap::iterator BasicBankMap::end() const { iterator it(m_buckets.get(), NULL, hash_buckets); return it; } template typename BasicBankMap::iterator BasicBankMap::find(key_type key) { size_t index = hash(key); Slot *slot = bucket_find(index, key); if(!slot) return end(); return iterator(m_buckets.get(), slot, index); } template void BasicBankMap::erase(iterator it) { bucket_remove(it.index, it.slot); free_slot(it.slot); --m_size; } template inline BasicBankMap::iterator::iterator() : buckets(NULL), slot(NULL), index(0) { } template inline BasicBankMap::iterator::iterator(Slot **buckets, Slot *slot, size_t index) : buckets(buckets), slot(slot), index(index) { } template typename BasicBankMap::iterator & BasicBankMap::iterator::operator++() { if(slot->next) slot = slot->next; else { Slot *slot = NULL; ++index; while(index < hash_buckets && !(slot = buckets[index])) ++index; this->slot = slot; } return *this; } template bool BasicBankMap::iterator::operator==(const iterator &o) const { return buckets == o.buckets && slot == o.slot && index == o.index; } template inline bool BasicBankMap::iterator::operator!=(const iterator &o) const { return !operator==(o); } template void BasicBankMap::iterator::to_ptrs(void *ptrs[3]) { ptrs[0] = buckets; ptrs[1] = slot; ptrs[2] = (void *)index; } template typename BasicBankMap::iterator BasicBankMap::iterator::from_ptrs(void *const ptrs[3]) { iterator it; it.buckets = (Slot **)ptrs[0]; it.slot = (Slot *)ptrs[1]; it.index = (size_t)ptrs[2]; return it; } template std::pair::iterator, bool> BasicBankMap::insert(const value_type &value) { size_t index = hash(value.first); Slot *slot = bucket_find(index, value.first); if(slot) return std::make_pair(iterator(m_buckets.get(), slot, index), false); slot = allocate_slot(); if(!slot) { reserve(m_capacity + minimum_allocation); slot = ensure_allocate_slot(); } slot->value = value; bucket_add(index, slot); ++m_size; return std::make_pair(iterator(m_buckets.get(), slot, index), true); } template std::pair::iterator, bool> BasicBankMap::insert(const value_type &value, do_not_expand_t) { size_t index = hash(value.first); Slot *slot = bucket_find(index, value.first); if(slot) return std::make_pair(iterator(m_buckets.get(), slot, index), false); slot = allocate_slot(); if(!slot) return std::make_pair(end(), false); slot->value = value; bucket_add(index, slot); ++m_size; return std::make_pair(iterator(m_buckets.get(), slot, index), true); } template void BasicBankMap::clear() { for(size_t i = 0; i < hash_buckets; ++i) { Slot *slot = m_buckets[i]; while (Slot *cur = slot) { slot = slot->next; free_slot(cur); } m_buckets[i] = NULL; } m_size = 0; } template inline T &BasicBankMap::operator[](key_type key) { return insert(value_type(key, T())).first->second; } template typename BasicBankMap::Slot * BasicBankMap::allocate_slot() { Slot *slot = m_freeslots; if(!slot) return NULL; Slot *next = slot->next; if(next) next->prev = NULL; m_freeslots = next; return slot; } template inline typename BasicBankMap::Slot * BasicBankMap::ensure_allocate_slot() { Slot *slot = allocate_slot(); assert(slot); return slot; } template void BasicBankMap::free_slot(Slot *slot) { Slot *next = m_freeslots; if(next) next->prev = slot; slot->prev = NULL; slot->next = next; m_freeslots = slot; m_freeslots->value.second = T(); } template typename BasicBankMap::Slot * BasicBankMap::bucket_find(size_t index, key_type key) { Slot *slot = m_buckets[index]; while(slot && slot->value.first != key) slot = slot->next; return slot; } template void BasicBankMap::bucket_add(size_t index, Slot *slot) { assert(slot); Slot *next = m_buckets[index]; if(next) next->prev = slot; slot->next = next; m_buckets[index] = slot; } template void BasicBankMap::bucket_remove(size_t index, Slot *slot) { assert(slot); Slot *prev = slot->prev; Slot *next = slot->next; if(!prev) m_buckets[index] = next; else prev->next = next; if(next) next->prev = prev; }