annotate base/ById.h @ 1750:d0ef65d8dd89 by-id

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