annotate base/ById.h @ 1753:d954dfccd922 by-id

Comments
author Chris Cannam
date Fri, 05 Jul 2019 16:55:20 +0100
parents 6d09d68165a4
children 0678bf772f82
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@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@1744 30 //!!! todo: docs
Chris@1744 31
Chris@1750 32 //!!! further possibilities:
Chris@1750 33 //
Chris@1750 34 // - get() returns a pointer wrapper that cannot be shared/copied
Chris@1750 35 // again by the caller (except by the usual C++ trickery)
Chris@1750 36 //
Chris@1750 37 // also to do: review how often we are calling getAs<...> when we
Chris@1750 38 // could just be using get
Chris@1750 39
Chris@1753 40 //!!! NB we still haven't solved the problem of what to do for a
Chris@1753 41 //!!! user-initiated cancel of a transform
Chris@1753 42
Chris@1742 43 struct IdAlloc {
Chris@1742 44
Chris@1742 45 // The value NO_ID (-1) is never allocated
Chris@1742 46 static const int NO_ID = -1;
Chris@1742 47
Chris@1742 48 static int getNextId();
Chris@1742 49 };
Chris@1742 50
Chris@1731 51 template <typename T>
Chris@1742 52 struct TypedId {
Chris@1735 53
Chris@1742 54 int untyped;
Chris@1742 55
Chris@1742 56 TypedId() : untyped(IdAlloc::NO_ID) {}
Chris@1729 57
Chris@1742 58 TypedId(const TypedId &) =default;
Chris@1742 59 TypedId &operator=(const TypedId &) =default;
Chris@1735 60
Chris@1742 61 bool operator==(const TypedId &other) const {
Chris@1742 62 return untyped == other.untyped;
Chris@1742 63 }
Chris@1742 64 bool operator!=(const TypedId &other) const {
Chris@1742 65 return untyped != other.untyped;
Chris@1742 66 }
Chris@1742 67 bool operator<(const TypedId &other) const {
Chris@1742 68 return untyped < other.untyped;
Chris@1742 69 }
Chris@1742 70 bool isNone() const {
Chris@1742 71 return untyped == IdAlloc::NO_ID;
Chris@1731 72 }
Chris@1731 73 };
Chris@1731 74
Chris@1731 75 template <typename T>
Chris@1739 76 std::ostream &
Chris@1742 77 operator<<(std::ostream &ostr, const TypedId<T> &id)
Chris@1739 78 {
Chris@1739 79 // For diagnostic purposes only. Do not use these IDs for
Chris@1739 80 // serialisation - see XmlExportable instead.
Chris@1739 81 if (id.isNone()) {
Chris@1739 82 return (ostr << "<none>");
Chris@1739 83 } else {
Chris@1742 84 return (ostr << "#" << id.untyped);
Chris@1739 85 }
Chris@1739 86 }
Chris@1739 87
Chris@1729 88 class WithId
Chris@1729 89 {
Chris@1729 90 public:
Chris@1729 91 WithId() :
Chris@1742 92 m_id(IdAlloc::getNextId()) {
Chris@1742 93 }
Chris@1742 94 virtual ~WithId() {
Chris@1729 95 }
Chris@1729 96
Chris@1752 97 protected:
Chris@1752 98 friend class AnyById;
Chris@1752 99
Chris@1731 100 /**
Chris@1742 101 * Return an id for this object. The id is a unique number for
Chris@1731 102 * this object among all objects that implement WithId within this
Chris@1731 103 * single run of the application.
Chris@1731 104 */
Chris@1742 105 int getUntypedId() const {
Chris@1742 106 return m_id;
Chris@1742 107 }
Chris@1742 108
Chris@1742 109 private:
Chris@1742 110 int m_id;
Chris@1742 111 };
Chris@1742 112
Chris@1742 113 template <typename T>
Chris@1742 114 class WithTypedId : virtual public WithId
Chris@1742 115 {
Chris@1742 116 public:
Chris@1742 117 typedef TypedId<T> Id;
Chris@1742 118
Chris@1742 119 WithTypedId() : WithId() { }
Chris@1742 120
Chris@1752 121 protected:
Chris@1752 122 template <typename Item, typename Id>
Chris@1752 123 friend class TypedById;
Chris@1752 124
Chris@1742 125 /**
Chris@1742 126 * Return an id for this object. The id is a unique value for this
Chris@1742 127 * object among all objects that implement WithTypedId within this
Chris@1742 128 * single run of the application.
Chris@1742 129 */
Chris@1729 130 Id getId() const {
Chris@1731 131 Id id;
Chris@1742 132 id.untyped = getUntypedId();
Chris@1731 133 return id;
Chris@1729 134 }
Chris@1742 135 };
Chris@1742 136
Chris@1742 137 class AnyById
Chris@1742 138 {
Chris@1742 139 public:
Chris@1752 140 static int add(std::shared_ptr<WithId>);
Chris@1742 141 static void release(int);
Chris@1746 142 static std::shared_ptr<WithId> get(int);
Chris@1742 143
Chris@1742 144 template <typename Derived>
Chris@1746 145 static bool isa(int id) {
Chris@1746 146 std::shared_ptr<WithId> p = get(id);
Chris@1746 147 return bool(std::dynamic_pointer_cast<Derived>(p));
Chris@1746 148 }
Chris@1746 149
Chris@1746 150 template <typename Derived>
Chris@1742 151 static std::shared_ptr<Derived> getAs(int id) {
Chris@1742 152 std::shared_ptr<WithId> p = get(id);
Chris@1742 153 return std::dynamic_pointer_cast<Derived>(p);
Chris@1742 154 }
Chris@1729 155
Chris@1729 156 private:
Chris@1742 157 class Impl;
Chris@1742 158 static Impl &impl();
Chris@1729 159 };
Chris@1729 160
Chris@1731 161 template <typename Item, typename Id>
Chris@1742 162 class TypedById
Chris@1729 163 {
Chris@1729 164 public:
Chris@1750 165 static Id add(std::shared_ptr<Item> item) {
Chris@1752 166 Id id;
Chris@1752 167 id.untyped = AnyById::add(item);
Chris@1750 168 return id;
Chris@1729 169 }
Chris@1729 170
Chris@1742 171 static void release(Id id) {
Chris@1742 172 AnyById::release(id.untyped);
Chris@1729 173 }
Chris@1742 174 static void release(std::shared_ptr<Item> item) {
Chris@1742 175 release(item->getId());
Chris@1729 176 }
Chris@1729 177
Chris@1729 178 template <typename Derived>
Chris@1746 179 static bool isa(Id id) {
Chris@1746 180 return AnyById::isa<Derived>(id.untyped);
Chris@1746 181 }
Chris@1746 182
Chris@1746 183 template <typename Derived>
Chris@1742 184 static std::shared_ptr<Derived> getAs(Id id) {
Chris@1742 185 return AnyById::getAs<Derived>(id.untyped);
Chris@1742 186 }
Chris@1742 187
Chris@1742 188 static std::shared_ptr<Item> get(Id id) {
Chris@1742 189 return getAs<Item>(id);
Chris@1729 190 }
Chris@1752 191
Chris@1738 192 /**
Chris@1738 193 * If the Item type is an XmlExportable, return the export ID of
Chris@1739 194 * the given item ID. A call to this function will fail to compile
Chris@1739 195 * if the Item is not an XmlExportable.
Chris@1739 196 *
Chris@1739 197 * The export ID is a simple int, and is only allocated when first
Chris@1739 198 * requested, so objects that are never exported don't get one.
Chris@1738 199 */
Chris@1742 200 static int getExportId(Id id) {
Chris@1738 201 auto exportable = getAs<XmlExportable>(id);
Chris@1738 202 if (exportable) {
Chris@1738 203 return exportable->getExportId();
Chris@1738 204 } else {
Chris@1738 205 return XmlExportable::NO_ID;
Chris@1738 206 }
Chris@1738 207 }
Chris@1729 208 };
Chris@1731 209
Chris@1729 210 #endif
Chris@1729 211