Mercurial > hg > svcore
diff base/ById.cpp @ 1742:52705a328b34 by-id
Rejig ById so as to put everything in a single pool, so that at the core you can go from numeric id (untyped) to anything the object can be dynamic_cast to. Useful for building other abstractions like PlayParameter-type registrations that don't know about e.g. Models. Probably some more tweaking needed. Also add tests
author | Chris Cannam |
---|---|
date | Fri, 28 Jun 2019 17:36:30 +0100 |
parents | |
children | b92bdcd4954b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ById.cpp Fri Jun 28 17:36:30 2019 +0100 @@ -0,0 +1,122 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + + 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 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "ById.h" + +#include <unordered_map> +#include <typeinfo> + +int IdAlloc::getNextId() +{ + static int nextId = 0; + static QMutex mutex; + QMutexLocker locker(&mutex); + int i = nextId; + if (nextId == INT_MAX) { + nextId = INT_MIN; + } else { + ++nextId; + if (nextId == 0 || nextId == NO_ID) { + throw std::runtime_error("Internal ID limit exceeded!"); + } + } + return i; +} + +class AnyById::Impl +{ +public: + ~Impl() { + QMutexLocker locker(&m_mutex); + bool empty = true; + for (const auto &p: m_items) { + if (p.second && p.second.use_count() > 0) { + empty = false; + break; + } + } + if (!empty) { + SVCERR << "WARNING: ById map is not empty at close; some items have not been released" << endl; + SVCERR << " Unreleased items are:" << endl; + for (const auto &p: m_items) { + if (p.second && p.second.use_count() > 0) { + SVCERR << " - id #" << p.first + << ": type " << typeid(*p.second.get()).name() + << ", use count " << p.second.use_count() << endl; + } + } + } + } + + void add(int id, std::shared_ptr<WithId> item) { + QMutexLocker locker(&m_mutex); + if (m_items.find(id) != m_items.end()) { + SVCERR << "ById::add: item with id " << id + << " is already recorded (existing item type is " + << typeid(*m_items.find(id)->second.get()).name() + << ", proposed is " + << typeid(*item.get()).name() << ")" << endl; + throw std::logic_error("item id is already recorded in add"); + } + m_items[id] = item; + } + + void release(int id) { + QMutexLocker locker(&m_mutex); + if (m_items.find(id) == m_items.end()) { + SVCERR << "ById::release: unknown item id " << id << endl; + throw std::logic_error("unknown item id in release"); + } + m_items.erase(id); + } + + std::shared_ptr<WithId> get(int id) const { + QMutexLocker locker(&m_mutex); + const auto &itr = m_items.find(id); + if (itr != m_items.end()) { + return itr->second; + } else { + return {}; + } + } + +private: + mutable QMutex m_mutex; + std::unordered_map<int, std::shared_ptr<WithId>> m_items; +}; + +void +AnyById::add(int id, std::shared_ptr<WithId> item) +{ + impl().add(id, item); +} + +void +AnyById::release(int id) +{ + impl().release(id); +} + +std::shared_ptr<WithId> +AnyById::get(int id) +{ + return impl().get(id); +} + +AnyById::Impl & +AnyById::impl() +{ + static Impl impl; + return impl; +}