Chris@1742: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1742: Chris@1742: /* Chris@1742: Sonic Visualiser Chris@1742: An audio file viewer and annotation editor. Chris@1742: Centre for Digital Music, Queen Mary, University of London. Chris@1742: Chris@1742: This program is free software; you can redistribute it and/or Chris@1742: modify it under the terms of the GNU General Public License as Chris@1742: published by the Free Software Foundation; either version 2 of the Chris@1742: License, or (at your option) any later version. See the file Chris@1742: COPYING included with this distribution for more information. Chris@1742: */ Chris@1742: Chris@1742: #include "ById.h" Chris@1742: Chris@1742: #include Chris@1742: #include Chris@1742: Chris@1742: int IdAlloc::getNextId() Chris@1742: { Chris@1742: static int nextId = 0; Chris@1742: static QMutex mutex; Chris@1742: QMutexLocker locker(&mutex); Chris@1742: int i = nextId; Chris@1742: if (nextId == INT_MAX) { Chris@1742: nextId = INT_MIN; Chris@1742: } else { Chris@1742: ++nextId; Chris@1742: if (nextId == 0 || nextId == NO_ID) { Chris@1742: throw std::runtime_error("Internal ID limit exceeded!"); Chris@1742: } Chris@1742: } Chris@1742: return i; Chris@1742: } Chris@1742: Chris@1742: class AnyById::Impl Chris@1742: { Chris@1742: public: Chris@1742: ~Impl() { Chris@1742: QMutexLocker locker(&m_mutex); Chris@1742: bool empty = true; Chris@1742: for (const auto &p: m_items) { Chris@1742: if (p.second && p.second.use_count() > 0) { Chris@1742: empty = false; Chris@1742: break; Chris@1742: } Chris@1742: } Chris@1742: if (!empty) { Chris@1742: SVCERR << "WARNING: ById map is not empty at close; some items have not been released" << endl; Chris@1742: SVCERR << " Unreleased items are:" << endl; Chris@1742: for (const auto &p: m_items) { Chris@1742: if (p.second && p.second.use_count() > 0) { Chris@1742: SVCERR << " - id #" << p.first Chris@1742: << ": type " << typeid(*p.second.get()).name() Chris@1742: << ", use count " << p.second.use_count() << endl; Chris@1742: } Chris@1742: } Chris@1742: } Chris@1742: } Chris@1742: Chris@1742: void add(int id, std::shared_ptr item) { Chris@1742: QMutexLocker locker(&m_mutex); Chris@1742: if (m_items.find(id) != m_items.end()) { Chris@1742: SVCERR << "ById::add: item with id " << id Chris@1742: << " is already recorded (existing item type is " Chris@1742: << typeid(*m_items.find(id)->second.get()).name() Chris@1742: << ", proposed is " Chris@1742: << typeid(*item.get()).name() << ")" << endl; Chris@1742: throw std::logic_error("item id is already recorded in add"); Chris@1742: } Chris@1742: m_items[id] = item; Chris@1742: } Chris@1742: Chris@1742: void release(int id) { Chris@1742: QMutexLocker locker(&m_mutex); Chris@1742: if (m_items.find(id) == m_items.end()) { Chris@1742: SVCERR << "ById::release: unknown item id " << id << endl; Chris@1742: throw std::logic_error("unknown item id in release"); Chris@1742: } Chris@1742: m_items.erase(id); Chris@1742: } Chris@1742: Chris@1742: std::shared_ptr get(int id) const { Chris@1742: QMutexLocker locker(&m_mutex); Chris@1742: const auto &itr = m_items.find(id); Chris@1742: if (itr != m_items.end()) { Chris@1742: return itr->second; Chris@1742: } else { Chris@1742: return {}; Chris@1742: } Chris@1742: } Chris@1742: Chris@1742: private: Chris@1742: mutable QMutex m_mutex; Chris@1742: std::unordered_map> m_items; Chris@1742: }; Chris@1742: Chris@1742: void Chris@1742: AnyById::add(int id, std::shared_ptr item) Chris@1742: { Chris@1742: impl().add(id, item); Chris@1742: } Chris@1742: Chris@1742: void Chris@1742: AnyById::release(int id) Chris@1742: { Chris@1742: impl().release(id); Chris@1742: } Chris@1742: Chris@1742: std::shared_ptr Chris@1742: AnyById::get(int id) Chris@1742: { Chris@1742: return impl().get(id); Chris@1742: } Chris@1742: Chris@1742: AnyById::Impl & Chris@1742: AnyById::impl() Chris@1742: { Chris@1742: static Impl impl; Chris@1742: return impl; Chris@1742: }