annotate base/ById.h @ 1738:4abc0f08adf9 by-id

More on alignment models and paths
author Chris Cannam
date Wed, 26 Jun 2019 10:21:15 +0100
parents d9082ed16931
children 565575463752
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@1738 29 #include "XmlExportable.h"
Chris@1738 30
Chris@1731 31 template <typename T>
Chris@1731 32 struct SvId {
Chris@1735 33
Chris@1731 34 int id;
Chris@1729 35
Chris@1735 36 enum {
Chris@1735 37 // The value NO_ID (-1) is never allocated by WithId
Chris@1735 38 NO_ID = -1
Chris@1735 39 };
Chris@1735 40
Chris@1735 41 SvId() : id(NO_ID) {}
Chris@1735 42
Chris@1735 43 SvId(const SvId &) =default;
Chris@1735 44 SvId &operator=(const SvId &) =default;
Chris@1735 45
Chris@1735 46 bool operator==(const SvId &other) const { return id == other.id; }
Chris@1731 47 bool operator<(const SvId &other) const { return id < other.id; }
Chris@1731 48
Chris@1735 49 bool isNone() const { return id == NO_ID; }
Chris@1735 50
Chris@1731 51 QString toString() const {
Chris@1731 52 return QString("%1").arg(id);
Chris@1731 53 }
Chris@1731 54 };
Chris@1731 55
Chris@1731 56 template <typename T>
Chris@1729 57 class WithId
Chris@1729 58 {
Chris@1729 59 public:
Chris@1731 60 typedef SvId<T> Id;
Chris@1731 61
Chris@1729 62 WithId() :
Chris@1729 63 m_id(getNextId()) {
Chris@1729 64 }
Chris@1729 65
Chris@1731 66 /**
Chris@1731 67 * Return an id for this object. The id is a unique identifier for
Chris@1731 68 * this object among all objects that implement WithId within this
Chris@1731 69 * single run of the application.
Chris@1731 70 */
Chris@1729 71 Id getId() const {
Chris@1731 72 Id id;
Chris@1731 73 id.id = m_id;
Chris@1731 74 return id;
Chris@1729 75 }
Chris@1729 76
Chris@1729 77 private:
Chris@1731 78 int m_id;
Chris@1731 79
Chris@1731 80 static int getNextId() {
Chris@1731 81 static int nextId = 0;
Chris@1731 82 static QMutex mutex;
Chris@1731 83 QMutexLocker locker(&mutex);
Chris@1731 84 int i = nextId;
Chris@1731 85 if (nextId == INT_MAX) {
Chris@1731 86 nextId = INT_MIN;
Chris@1735 87 } else {
Chris@1735 88 ++nextId;
Chris@1735 89 if (nextId == 0 || nextId == Id::NO_ID) {
Chris@1735 90 throw std::runtime_error("Internal ID limit exceeded!");
Chris@1735 91 }
Chris@1731 92 }
Chris@1731 93 return i;
Chris@1731 94 }
Chris@1729 95 };
Chris@1729 96
Chris@1731 97 template <typename Item, typename Id>
Chris@1729 98 class ById
Chris@1729 99 {
Chris@1729 100 public:
Chris@1731 101 ~ById() {
Chris@1731 102 QMutexLocker locker(&m_mutex);
Chris@1731 103 for (const auto &p: m_items) {
Chris@1731 104 if (p.second && p.second.use_count() > 0) {
Chris@1734 105 SVCERR << "WARNING: ById map destroyed with use count of "
Chris@1734 106 << p.second.use_count() << " for item with type "
Chris@1734 107 << typeid(*p.second.get()).name()
Chris@1734 108 << " and id " << p.first.id << endl;
Chris@1731 109 }
Chris@1731 110 }
Chris@1731 111 }
Chris@1731 112
Chris@1729 113 void add(std::shared_ptr<Item> item) {
Chris@1729 114 QMutexLocker locker(&m_mutex);
Chris@1734 115 auto id = item->getId();
Chris@1734 116 if (m_items.find(id) != m_items.end()) {
Chris@1734 117 SVCERR << "WARNING: ById::add: item with id " << id
Chris@1734 118 << " is already recorded, replacing it (item type is "
Chris@1734 119 << typeid(*item.get()).name() << ")" << endl;
Chris@1734 120 }
Chris@1734 121 m_items[id] = item;
Chris@1729 122 }
Chris@1729 123
Chris@1729 124 void
Chris@1729 125 release(Id id) {
Chris@1729 126 QMutexLocker locker(&m_mutex);
Chris@1729 127 m_items.erase(id);
Chris@1729 128 }
Chris@1729 129
Chris@1729 130 std::shared_ptr<Item> get(Id id) const {
Chris@1729 131 QMutexLocker locker(&m_mutex);
Chris@1729 132 const auto &itr = m_items.find(id);
Chris@1729 133 if (itr != m_items.end()) {
Chris@1729 134 return itr->second;
Chris@1729 135 } else {
Chris@1729 136 return std::shared_ptr<Item>();
Chris@1729 137 }
Chris@1729 138 }
Chris@1729 139
Chris@1729 140 template <typename Derived>
Chris@1729 141 std::shared_ptr<Derived> getAs(Id id) const {
Chris@1729 142 return std::dynamic_pointer_cast<Derived>(get(id));
Chris@1729 143 }
Chris@1738 144
Chris@1738 145 /**
Chris@1738 146 * If the Item type is an XmlExportable, return the export ID of
Chris@1738 147 * the given item ID. The export ID is a simple int, and is only
Chris@1738 148 * allocated when first requested, so objects that are never
Chris@1738 149 * exported don't get one.
Chris@1738 150 */
Chris@1738 151 int getExportId(Id id) const {
Chris@1738 152 auto exportable = getAs<XmlExportable>(id);
Chris@1738 153 if (exportable) {
Chris@1738 154 return exportable->getExportId();
Chris@1738 155 } else {
Chris@1738 156 return XmlExportable::NO_ID;
Chris@1738 157 }
Chris@1738 158 }
Chris@1729 159
Chris@1729 160 private:
Chris@1729 161 mutable QMutex m_mutex;
Chris@1729 162 std::map<Id, std::shared_ptr<Item>> m_items;
Chris@1729 163 };
Chris@1729 164
Chris@1731 165 template <typename Item, typename Id>
Chris@1731 166 class StaticById
Chris@1729 167 {
Chris@1729 168 public:
Chris@1731 169 static void add(std::shared_ptr<Item> imagined) {
Chris@1731 170 byId().add(imagined);
Chris@1729 171 }
Chris@1729 172
Chris@1729 173 static void release(Id id) {
Chris@1731 174 byId().release(id);
Chris@1729 175 }
Chris@1729 176
Chris@1731 177 static std::shared_ptr<Item> get(Id id) {
Chris@1731 178 return byId().get(id);
Chris@1729 179 }
Chris@1729 180
Chris@1729 181 template <typename Derived>
Chris@1729 182 static
Chris@1729 183 std::shared_ptr<Derived> getAs(Id id) {
Chris@1731 184 return std::dynamic_pointer_cast<Derived>(get(id));
Chris@1729 185 }
Chris@1729 186
Chris@1738 187 static int getExportId(Id id) {
Chris@1738 188 return byId().getExportId(id);
Chris@1738 189 }
Chris@1738 190
Chris@1729 191 private:
Chris@1731 192 static
Chris@1731 193 ById<Item, Id> &byId() {
Chris@1731 194 static ById<Item, Id> b;
Chris@1731 195 return b;
Chris@1731 196 }
Chris@1729 197 };
Chris@1731 198
Chris@1729 199 #endif
Chris@1729 200