annotate base/ById.h @ 1746:826e0cb77d8e by-id

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