annotate base/ById.h @ 1734:bffccc8de3c1 by-id

Warn for already-existing id
author Chris Cannam
date Mon, 24 Jun 2019 18:42:28 +0100
parents 601851995f4b
children d9082ed16931
rev   line source
Chris@1729 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1729 2
Chris@1729 3 /*
Chris@1729 4 Sonic Visualiser
Chris@1729 5 An audio file viewer and annotation editor.
Chris@1729 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1729 7
Chris@1729 8 This program is free software; you can redistribute it and/or
Chris@1729 9 modify it under the terms of the GNU General Public License as
Chris@1729 10 published by the Free Software Foundation; either version 2 of the
Chris@1729 11 License, or (at your option) any later version. See the file
Chris@1729 12 COPYING included with this distribution for more information.
Chris@1729 13 */
Chris@1729 14
Chris@1729 15 #ifndef SV_BY_ID_H
Chris@1729 16 #define SV_BY_ID_H
Chris@1729 17
Chris@1734 18 #include "Debug.h"
Chris@1734 19
Chris@1729 20 #include <memory>
Chris@1729 21 #include <map>
Chris@1731 22 #include <typeinfo>
Chris@1731 23 #include <iostream>
Chris@1731 24 #include <climits>
Chris@1729 25
Chris@1729 26 #include <QMutex>
Chris@1731 27 #include <QString>
Chris@1729 28
Chris@1731 29 template <typename T>
Chris@1731 30 struct SvId {
Chris@1731 31 int id;
Chris@1729 32
Chris@1731 33 bool operator<(const SvId &other) const { return id < other.id; }
Chris@1731 34
Chris@1731 35 QString toString() const {
Chris@1731 36 return QString("%1").arg(id);
Chris@1731 37 }
Chris@1731 38 };
Chris@1731 39
Chris@1731 40 template <typename T>
Chris@1729 41 class WithId
Chris@1729 42 {
Chris@1729 43 public:
Chris@1731 44 typedef SvId<T> Id;
Chris@1731 45
Chris@1729 46 WithId() :
Chris@1729 47 m_id(getNextId()) {
Chris@1729 48 }
Chris@1729 49
Chris@1731 50 /**
Chris@1731 51 * Return an id for this object. The id is a unique identifier for
Chris@1731 52 * this object among all objects that implement WithId within this
Chris@1731 53 * single run of the application.
Chris@1731 54 */
Chris@1729 55 Id getId() const {
Chris@1731 56 Id id;
Chris@1731 57 id.id = m_id;
Chris@1731 58 return id;
Chris@1729 59 }
Chris@1729 60
Chris@1729 61 private:
Chris@1731 62 int m_id;
Chris@1731 63
Chris@1731 64 static int getNextId() {
Chris@1731 65 static int nextId = 0;
Chris@1731 66 static QMutex mutex;
Chris@1731 67 QMutexLocker locker(&mutex);
Chris@1731 68 int i = nextId;
Chris@1731 69 if (nextId == INT_MAX) {
Chris@1731 70 nextId = INT_MIN;
Chris@1731 71 }
Chris@1731 72 ++nextId;
Chris@1731 73 return i;
Chris@1731 74 }
Chris@1729 75 };
Chris@1729 76
Chris@1731 77 template <typename Item, typename Id>
Chris@1729 78 class ById
Chris@1729 79 {
Chris@1729 80 public:
Chris@1731 81 ~ById() {
Chris@1731 82 QMutexLocker locker(&m_mutex);
Chris@1731 83 for (const auto &p: m_items) {
Chris@1731 84 if (p.second && p.second.use_count() > 0) {
Chris@1734 85 SVCERR << "WARNING: ById map destroyed with use count of "
Chris@1734 86 << p.second.use_count() << " for item with type "
Chris@1734 87 << typeid(*p.second.get()).name()
Chris@1734 88 << " and id " << p.first.id << endl;
Chris@1731 89 }
Chris@1731 90 }
Chris@1731 91 }
Chris@1731 92
Chris@1729 93 void add(std::shared_ptr<Item> item) {
Chris@1729 94 QMutexLocker locker(&m_mutex);
Chris@1734 95 auto id = item->getId();
Chris@1734 96 if (m_items.find(id) != m_items.end()) {
Chris@1734 97 SVCERR << "WARNING: ById::add: item with id " << id
Chris@1734 98 << " is already recorded, replacing it (item type is "
Chris@1734 99 << typeid(*item.get()).name() << ")" << endl;
Chris@1734 100 }
Chris@1734 101 m_items[id] = item;
Chris@1729 102 }
Chris@1729 103
Chris@1729 104 void
Chris@1729 105 release(Id id) {
Chris@1729 106 QMutexLocker locker(&m_mutex);
Chris@1729 107 m_items.erase(id);
Chris@1729 108 }
Chris@1729 109
Chris@1729 110 std::shared_ptr<Item> get(Id id) const {
Chris@1729 111 QMutexLocker locker(&m_mutex);
Chris@1729 112 const auto &itr = m_items.find(id);
Chris@1729 113 if (itr != m_items.end()) {
Chris@1729 114 return itr->second;
Chris@1729 115 } else {
Chris@1729 116 return std::shared_ptr<Item>();
Chris@1729 117 }
Chris@1729 118 }
Chris@1729 119
Chris@1729 120 template <typename Derived>
Chris@1729 121 std::shared_ptr<Derived> getAs(Id id) const {
Chris@1729 122 return std::dynamic_pointer_cast<Derived>(get(id));
Chris@1729 123 }
Chris@1729 124
Chris@1729 125 private:
Chris@1729 126 mutable QMutex m_mutex;
Chris@1729 127 std::map<Id, std::shared_ptr<Item>> m_items;
Chris@1729 128 };
Chris@1729 129
Chris@1731 130 template <typename Item, typename Id>
Chris@1731 131 class StaticById
Chris@1729 132 {
Chris@1729 133 public:
Chris@1731 134 static void add(std::shared_ptr<Item> imagined) {
Chris@1731 135 byId().add(imagined);
Chris@1729 136 }
Chris@1729 137
Chris@1729 138 static void release(Id id) {
Chris@1731 139 byId().release(id);
Chris@1729 140 }
Chris@1729 141
Chris@1731 142 static std::shared_ptr<Item> get(Id id) {
Chris@1731 143 return byId().get(id);
Chris@1729 144 }
Chris@1729 145
Chris@1729 146 template <typename Derived>
Chris@1729 147 static
Chris@1729 148 std::shared_ptr<Derived> getAs(Id id) {
Chris@1731 149 return std::dynamic_pointer_cast<Derived>(get(id));
Chris@1729 150 }
Chris@1729 151
Chris@1729 152 private:
Chris@1731 153 static
Chris@1731 154 ById<Item, Id> &byId() {
Chris@1731 155 static ById<Item, Id> b;
Chris@1731 156 return b;
Chris@1731 157 }
Chris@1729 158 };
Chris@1731 159
Chris@1729 160 #endif
Chris@1729 161