| 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@1729 | 18 #include <memory> | 
| Chris@1729 | 19 #include <map> | 
| Chris@1731 | 20 #include <typeinfo> | 
| Chris@1731 | 21 #include <iostream> | 
| Chris@1731 | 22 #include <climits> | 
| Chris@1729 | 23 | 
| Chris@1729 | 24 #include <QMutex> | 
| Chris@1731 | 25 #include <QString> | 
| Chris@1729 | 26 | 
| Chris@1731 | 27 template <typename T> | 
| Chris@1731 | 28 struct SvId { | 
| Chris@1735 | 29 | 
| Chris@1731 | 30     int id; | 
| Chris@1729 | 31 | 
| Chris@1735 | 32     enum { | 
| Chris@1735 | 33         // The value NO_ID (-1) is never allocated by WithId | 
| Chris@1735 | 34         NO_ID = -1 | 
| Chris@1735 | 35     }; | 
| Chris@1735 | 36 | 
| Chris@1735 | 37     SvId() : id(NO_ID) {} | 
| Chris@1735 | 38 | 
| Chris@1735 | 39     SvId(const SvId &) =default; | 
| Chris@1735 | 40     SvId &operator=(const SvId &) =default; | 
| Chris@1735 | 41 | 
| Chris@1735 | 42     bool operator==(const SvId &other) const { return id == other.id; } | 
| Chris@1731 | 43     bool operator<(const SvId &other) const { return id < other.id; } | 
| Chris@1731 | 44 | 
| Chris@1735 | 45     bool isNone() const { return id == NO_ID; } | 
| Chris@1735 | 46 | 
| Chris@1731 | 47     QString toString() const { | 
| Chris@1731 | 48         return QString("%1").arg(id); | 
| Chris@1731 | 49     } | 
| Chris@1731 | 50 }; | 
| Chris@1731 | 51 | 
| Chris@1731 | 52 template <typename T> | 
| Chris@1729 | 53 class WithId | 
| Chris@1729 | 54 { | 
| Chris@1729 | 55 public: | 
| Chris@1731 | 56     typedef SvId<T> Id; | 
| Chris@1731 | 57 | 
| Chris@1729 | 58     WithId() : | 
| Chris@1729 | 59         m_id(getNextId()) { | 
| Chris@1729 | 60     } | 
| Chris@1729 | 61 | 
| Chris@1731 | 62     /** | 
| Chris@1731 | 63      * Return an id for this object. The id is a unique identifier for | 
| Chris@1731 | 64      * this object among all objects that implement WithId within this | 
| Chris@1731 | 65      * single run of the application. | 
| Chris@1731 | 66      */ | 
| Chris@1729 | 67     Id getId() const { | 
| Chris@1731 | 68         Id id; | 
| Chris@1731 | 69         id.id = m_id; | 
| Chris@1731 | 70         return id; | 
| Chris@1729 | 71     } | 
| Chris@1729 | 72 | 
| Chris@1729 | 73 private: | 
| Chris@1731 | 74     int m_id; | 
| Chris@1731 | 75 | 
| Chris@1731 | 76     static int getNextId() { | 
| Chris@1731 | 77         static int nextId = 0; | 
| Chris@1731 | 78         static QMutex mutex; | 
| Chris@1731 | 79         QMutexLocker locker(&mutex); | 
| Chris@1731 | 80         int i = nextId; | 
| Chris@1731 | 81         if (nextId == INT_MAX) { | 
| Chris@1731 | 82             nextId = INT_MIN; | 
| Chris@1735 | 83         } else { | 
| Chris@1735 | 84             ++nextId; | 
| Chris@1735 | 85             if (nextId == 0 || nextId == Id::NO_ID) { | 
| Chris@1735 | 86                 throw std::runtime_error("Internal ID limit exceeded!"); | 
| Chris@1735 | 87             } | 
| Chris@1731 | 88         } | 
| Chris@1731 | 89         return i; | 
| Chris@1731 | 90     } | 
| Chris@1729 | 91 }; | 
| Chris@1729 | 92 | 
| Chris@1731 | 93 template <typename Item, typename Id> | 
| Chris@1729 | 94 class ById | 
| Chris@1729 | 95 { | 
| Chris@1729 | 96 public: | 
| Chris@1731 | 97     ~ById() { | 
| Chris@1731 | 98         QMutexLocker locker(&m_mutex); | 
| Chris@1731 | 99         for (const auto &p: m_items) { | 
| Chris@1731 | 100             if (p.second && p.second.use_count() > 0) { | 
| Chris@1731 | 101                 std::cerr << "WARNING: ById map destroyed with use count of " | 
| Chris@1731 | 102                           << p.second.use_count() << " for item with type " | 
| Chris@1731 | 103                           << typeid(*p.second.get()).name() | 
| Chris@1731 | 104                           << " and id " << p.first.id << std::endl; | 
| Chris@1731 | 105             } | 
| Chris@1731 | 106         } | 
| Chris@1731 | 107     } | 
| Chris@1731 | 108 | 
| Chris@1729 | 109     void add(std::shared_ptr<Item> item) { | 
| Chris@1729 | 110         QMutexLocker locker(&m_mutex); | 
| Chris@1729 | 111         m_items[item->getId()] = item; | 
| Chris@1729 | 112     } | 
| Chris@1729 | 113 | 
| Chris@1729 | 114     void | 
| Chris@1729 | 115     release(Id id) { | 
| Chris@1729 | 116         QMutexLocker locker(&m_mutex); | 
| Chris@1729 | 117         m_items.erase(id); | 
| Chris@1729 | 118     } | 
| Chris@1729 | 119 | 
| Chris@1729 | 120     std::shared_ptr<Item> get(Id id) const { | 
| Chris@1729 | 121         QMutexLocker locker(&m_mutex); | 
| Chris@1729 | 122         const auto &itr = m_items.find(id); | 
| Chris@1729 | 123         if (itr != m_items.end()) { | 
| Chris@1729 | 124             return itr->second; | 
| Chris@1729 | 125         } else { | 
| Chris@1729 | 126             return std::shared_ptr<Item>(); | 
| Chris@1729 | 127         } | 
| Chris@1729 | 128     } | 
| Chris@1729 | 129 | 
| Chris@1729 | 130     template <typename Derived> | 
| Chris@1729 | 131     std::shared_ptr<Derived> getAs(Id id) const { | 
| Chris@1729 | 132         return std::dynamic_pointer_cast<Derived>(get(id)); | 
| Chris@1729 | 133     } | 
| Chris@1729 | 134 | 
| Chris@1729 | 135 private: | 
| Chris@1729 | 136     mutable QMutex m_mutex; | 
| Chris@1729 | 137     std::map<Id, std::shared_ptr<Item>> m_items; | 
| Chris@1729 | 138 }; | 
| Chris@1729 | 139 | 
| Chris@1731 | 140 template <typename Item, typename Id> | 
| Chris@1731 | 141 class StaticById | 
| Chris@1729 | 142 { | 
| Chris@1729 | 143 public: | 
| Chris@1731 | 144     static void add(std::shared_ptr<Item> imagined) { | 
| Chris@1731 | 145         byId().add(imagined); | 
| Chris@1729 | 146     } | 
| Chris@1729 | 147 | 
| Chris@1729 | 148     static void release(Id id) { | 
| Chris@1731 | 149         byId().release(id); | 
| Chris@1729 | 150     } | 
| Chris@1729 | 151 | 
| Chris@1731 | 152     static std::shared_ptr<Item> get(Id id) { | 
| Chris@1731 | 153         return byId().get(id); | 
| Chris@1729 | 154     } | 
| Chris@1729 | 155 | 
| Chris@1729 | 156     template <typename Derived> | 
| Chris@1729 | 157     static | 
| Chris@1729 | 158     std::shared_ptr<Derived> getAs(Id id) { | 
| Chris@1731 | 159         return std::dynamic_pointer_cast<Derived>(get(id)); | 
| Chris@1729 | 160     } | 
| Chris@1729 | 161 | 
| Chris@1729 | 162 private: | 
| Chris@1731 | 163     static | 
| Chris@1731 | 164     ById<Item, Id> &byId() { | 
| Chris@1731 | 165         static ById<Item, Id> b; | 
| Chris@1731 | 166         return b; | 
| Chris@1731 | 167     } | 
| Chris@1729 | 168 }; | 
| Chris@1731 | 169 | 
| Chris@1729 | 170 #endif | 
| Chris@1729 | 171 |