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@1731
|
21 #include <iostream>
|
Chris@1731
|
22 #include <climits>
|
Chris@1742
|
23 #include <stdexcept>
|
Chris@1729
|
24
|
Chris@1729
|
25 #include <QMutex>
|
Chris@1731
|
26 #include <QString>
|
Chris@1729
|
27
|
Chris@1738
|
28 #include "XmlExportable.h"
|
Chris@1738
|
29
|
Chris@1742
|
30 struct IdAlloc {
|
Chris@1742
|
31
|
Chris@1742
|
32 // The value NO_ID (-1) is never allocated
|
Chris@1742
|
33 static const int NO_ID = -1;
|
Chris@1742
|
34
|
Chris@1742
|
35 static int getNextId();
|
Chris@1742
|
36 };
|
Chris@1742
|
37
|
Chris@1731
|
38 template <typename T>
|
Chris@1742
|
39 struct TypedId {
|
Chris@1735
|
40
|
Chris@1742
|
41 int untyped;
|
Chris@1742
|
42
|
Chris@1742
|
43 TypedId() : untyped(IdAlloc::NO_ID) {}
|
Chris@1729
|
44
|
Chris@1742
|
45 TypedId(const TypedId &) =default;
|
Chris@1742
|
46 TypedId &operator=(const TypedId &) =default;
|
Chris@1735
|
47
|
Chris@1742
|
48 bool operator==(const TypedId &other) const {
|
Chris@1742
|
49 return untyped == other.untyped;
|
Chris@1742
|
50 }
|
Chris@1742
|
51 bool operator!=(const TypedId &other) const {
|
Chris@1742
|
52 return untyped != other.untyped;
|
Chris@1742
|
53 }
|
Chris@1742
|
54 bool operator<(const TypedId &other) const {
|
Chris@1742
|
55 return untyped < other.untyped;
|
Chris@1742
|
56 }
|
Chris@1742
|
57 bool isNone() const {
|
Chris@1742
|
58 return untyped == IdAlloc::NO_ID;
|
Chris@1731
|
59 }
|
Chris@1731
|
60 };
|
Chris@1731
|
61
|
Chris@1731
|
62 template <typename T>
|
Chris@1739
|
63 std::ostream &
|
Chris@1742
|
64 operator<<(std::ostream &ostr, const TypedId<T> &id)
|
Chris@1739
|
65 {
|
Chris@1739
|
66 // For diagnostic purposes only. Do not use these IDs for
|
Chris@1739
|
67 // serialisation - see XmlExportable instead.
|
Chris@1739
|
68 if (id.isNone()) {
|
Chris@1739
|
69 return (ostr << "<none>");
|
Chris@1739
|
70 } else {
|
Chris@1742
|
71 return (ostr << "#" << id.untyped);
|
Chris@1739
|
72 }
|
Chris@1739
|
73 }
|
Chris@1739
|
74
|
Chris@1729
|
75 class WithId
|
Chris@1729
|
76 {
|
Chris@1729
|
77 public:
|
Chris@1729
|
78 WithId() :
|
Chris@1742
|
79 m_id(IdAlloc::getNextId()) {
|
Chris@1742
|
80 }
|
Chris@1742
|
81 virtual ~WithId() {
|
Chris@1729
|
82 }
|
Chris@1729
|
83
|
Chris@1731
|
84 /**
|
Chris@1742
|
85 * Return an id for this object. The id is a unique number for
|
Chris@1731
|
86 * this object among all objects that implement WithId within this
|
Chris@1731
|
87 * single run of the application.
|
Chris@1731
|
88 */
|
Chris@1742
|
89 int getUntypedId() const {
|
Chris@1742
|
90 return m_id;
|
Chris@1742
|
91 }
|
Chris@1742
|
92
|
Chris@1742
|
93 private:
|
Chris@1742
|
94 int m_id;
|
Chris@1742
|
95 };
|
Chris@1742
|
96
|
Chris@1742
|
97 template <typename T>
|
Chris@1742
|
98 class WithTypedId : virtual public WithId
|
Chris@1742
|
99 {
|
Chris@1742
|
100 public:
|
Chris@1742
|
101 typedef TypedId<T> Id;
|
Chris@1742
|
102
|
Chris@1742
|
103 WithTypedId() : WithId() { }
|
Chris@1742
|
104
|
Chris@1742
|
105 /**
|
Chris@1742
|
106 * Return an id for this object. The id is a unique value for this
|
Chris@1742
|
107 * object among all objects that implement WithTypedId within this
|
Chris@1742
|
108 * single run of the application.
|
Chris@1742
|
109 */
|
Chris@1729
|
110 Id getId() const {
|
Chris@1731
|
111 Id id;
|
Chris@1742
|
112 id.untyped = getUntypedId();
|
Chris@1731
|
113 return id;
|
Chris@1729
|
114 }
|
Chris@1742
|
115 };
|
Chris@1742
|
116
|
Chris@1742
|
117 class AnyById
|
Chris@1742
|
118 {
|
Chris@1742
|
119 public:
|
Chris@1742
|
120 static void add(int, std::shared_ptr<WithId>);
|
Chris@1742
|
121 static void release(int);
|
Chris@1742
|
122 static std::shared_ptr<WithId> get(int);
|
Chris@1742
|
123
|
Chris@1742
|
124 template <typename Derived>
|
Chris@1742
|
125 static std::shared_ptr<Derived> getAs(int id) {
|
Chris@1742
|
126 std::shared_ptr<WithId> p = get(id);
|
Chris@1742
|
127 return std::dynamic_pointer_cast<Derived>(p);
|
Chris@1742
|
128 }
|
Chris@1729
|
129
|
Chris@1729
|
130 private:
|
Chris@1742
|
131 class Impl;
|
Chris@1742
|
132 static Impl &impl();
|
Chris@1729
|
133 };
|
Chris@1729
|
134
|
Chris@1731
|
135 template <typename Item, typename Id>
|
Chris@1742
|
136 class TypedById
|
Chris@1729
|
137 {
|
Chris@1729
|
138 public:
|
Chris@1742
|
139 static void add(std::shared_ptr<Item> item) {
|
Chris@1734
|
140 auto id = item->getId();
|
Chris@1739
|
141 if (id.isNone()) {
|
Chris@1739
|
142 throw std::logic_error("item id should never be None");
|
Chris@1739
|
143 }
|
Chris@1742
|
144 AnyById::add(id.untyped, item);
|
Chris@1729
|
145 }
|
Chris@1729
|
146
|
Chris@1742
|
147 static void release(Id id) {
|
Chris@1742
|
148 AnyById::release(id.untyped);
|
Chris@1729
|
149 }
|
Chris@1742
|
150 static void release(std::shared_ptr<Item> item) {
|
Chris@1742
|
151 release(item->getId());
|
Chris@1729
|
152 }
|
Chris@1729
|
153
|
Chris@1729
|
154 template <typename Derived>
|
Chris@1742
|
155 static std::shared_ptr<Derived> getAs(Id id) {
|
Chris@1742
|
156 if (id.isNone()) return {}; // this id is never issued: avoid locking
|
Chris@1742
|
157 return AnyById::getAs<Derived>(id.untyped);
|
Chris@1742
|
158 }
|
Chris@1742
|
159
|
Chris@1742
|
160 static std::shared_ptr<Item> get(Id id) {
|
Chris@1742
|
161 return getAs<Item>(id);
|
Chris@1729
|
162 }
|
Chris@1738
|
163
|
Chris@1738
|
164 /**
|
Chris@1738
|
165 * If the Item type is an XmlExportable, return the export ID of
|
Chris@1739
|
166 * the given item ID. A call to this function will fail to compile
|
Chris@1739
|
167 * if the Item is not an XmlExportable.
|
Chris@1739
|
168 *
|
Chris@1739
|
169 * The export ID is a simple int, and is only allocated when first
|
Chris@1739
|
170 * requested, so objects that are never exported don't get one.
|
Chris@1738
|
171 */
|
Chris@1742
|
172 static int getExportId(Id id) {
|
Chris@1738
|
173 auto exportable = getAs<XmlExportable>(id);
|
Chris@1738
|
174 if (exportable) {
|
Chris@1738
|
175 return exportable->getExportId();
|
Chris@1738
|
176 } else {
|
Chris@1738
|
177 return XmlExportable::NO_ID;
|
Chris@1738
|
178 }
|
Chris@1738
|
179 }
|
Chris@1729
|
180 };
|
Chris@1731
|
181
|
Chris@1729
|
182 #endif
|
Chris@1729
|
183
|