changeset 1731:601851995f4b by-id

Introduce Model to ById
author Chris Cannam
date Fri, 21 Jun 2019 13:37:00 +0100
parents abd8b9673028
children 87b4c596c0ef
files base/ById.cpp base/ById.h data/model/Model.cpp data/model/Model.h data/model/WritableWaveFileModel.cpp files.pri
diffstat 6 files changed, 74 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/base/ById.cpp	Thu Jun 20 14:57:39 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#include "ById.h"
-
-#include <QMutex>
-
-#include <climits>
-
-int
-WithId::getNextId()
-{
-    static int nextId = 0;
-    static QMutex mutex;
-    QMutexLocker locker(&mutex);
-    int i = nextId;
-    if (nextId == INT_MAX) {
-        nextId = INT_MIN;
-    }
-    ++nextId;
-    return i;
-}
--- a/base/ById.h	Thu Jun 20 14:57:39 2019 +0100
+++ b/base/ById.h	Fri Jun 21 13:37:00 2019 +0100
@@ -17,31 +17,77 @@
 
 #include <memory>
 #include <map>
+#include <typeinfo>
+#include <iostream>
+#include <climits>
 
 #include <QMutex>
+#include <QString>
 
-typedef int Id;
+template <typename T>
+struct SvId {
+    int id;
 
+    bool operator<(const SvId &other) const { return id < other.id; }
+
+    QString toString() const {
+        return QString("%1").arg(id);
+    }
+};
+
+template <typename T>
 class WithId
 {
 public:
+    typedef SvId<T> Id;
+    
     WithId() :
         m_id(getNextId()) {
     }
 
+    /**
+     * Return an id for this object. The id is a unique identifier for
+     * this object among all objects that implement WithId within this
+     * single run of the application.
+     */
     Id getId() const {
-        return m_id;
+        Id id;
+        id.id = m_id;
+        return id;
     }
 
 private:
-    Id m_id;
-    static int getNextId();
+    int m_id;
+
+    static int getNextId() {
+        static int nextId = 0;
+        static QMutex mutex;
+        QMutexLocker locker(&mutex);
+        int i = nextId;
+        if (nextId == INT_MAX) {
+            nextId = INT_MIN;
+        }
+        ++nextId;
+        return i;
+    }
 };
 
-template <typename Item>
+template <typename Item, typename Id>
 class ById
 {
 public:
+    ~ById() {
+        QMutexLocker locker(&m_mutex);
+        for (const auto &p: m_items) {
+            if (p.second && p.second.use_count() > 0) {
+                std::cerr << "WARNING: ById map destroyed with use count of "
+                          << p.second.use_count() << " for item with type "
+                          << typeid(*p.second.get()).name()
+                          << " and id " << p.first.id << std::endl;
+            }
+        }
+    }
+    
     void add(std::shared_ptr<Item> item) {
         QMutexLocker locker(&m_mutex);
         m_items[item->getId()] = item;
@@ -72,34 +118,36 @@
     mutable QMutex m_mutex;
     std::map<Id, std::shared_ptr<Item>> m_items;
 };
-/*
-class Imagined : public WithId {
-};
 
-class ImaginedById
+template <typename Item, typename Id>
+class StaticById
 {
 public:
-    static void add(std::shared_ptr<Imagined> imagined) {
-        m_byId.add(imagined);
+    static void add(std::shared_ptr<Item> imagined) {
+        byId().add(imagined);
     }
 
     static void release(Id id) {
-        m_byId.release(id);
+        byId().release(id);
     }
 
-    static std::shared_ptr<Imagined> get(Id id) {
-        return m_byId.get(id);
+    static std::shared_ptr<Item> get(Id id) {
+        return byId().get(id);
     }
 
     template <typename Derived>
     static
     std::shared_ptr<Derived> getAs(Id id) {
-        return m_byId.getAs<Derived>(id);
+        return std::dynamic_pointer_cast<Derived>(get(id));
     }
 
 private:
-    static ById<Imagined> m_byId;
+    static
+    ById<Item, Id> &byId() {
+        static ById<Item, Id> b;
+        return b;
+    }
 };
-*/
+
 #endif
 
--- a/data/model/Model.cpp	Thu Jun 20 14:57:39 2019 +0100
+++ b/data/model/Model.cpp	Fri Jun 21 13:37:00 2019 +0100
@@ -40,20 +40,6 @@
     }
 }
 
-int
-Model::getNextId()
-{
-    static int nextId = 0;
-    static QMutex mutex;
-    QMutexLocker locker(&mutex);
-    int i = nextId;
-    if (nextId == INT_MAX) {
-        nextId = INT_MIN;
-    }
-    ++nextId;
-    return i;
-}
-
 void
 Model::setSourceModel(Model *model)
 {
--- a/data/model/Model.h	Thu Jun 20 14:57:39 2019 +0100
+++ b/data/model/Model.h	Fri Jun 21 13:37:00 2019 +0100
@@ -19,6 +19,7 @@
 #include <vector>
 #include <QObject>
 
+#include "base/ById.h"
 #include "base/XmlExportable.h"
 #include "base/Playable.h"
 #include "base/BaseTypes.h"
@@ -27,14 +28,12 @@
 class ZoomConstraint;
 class AlignmentModel;
 
-typedef int ModelId;
-
 /** 
  * Model is the base class for all data models that represent any sort
  * of data on a time scale based on an audio frame rate.
  */
-
 class Model : public QObject,
+              public WithId<Model>,
               public XmlExportable,
               public Playable
 {
@@ -132,13 +131,6 @@
     virtual bool isSparse() const { return false; }
 
     /**
-     * Return an id for this model. The id is guaranteed to be a
-     * unique identifier for this model among all models that may ever
-     * exist within this single run of the application.
-     */
-    ModelId getId() const { return m_id; }
-    
-    /**
      * Mark the model as abandoning. This means that the application
      * no longer needs it, so it can stop doing any background
      * calculations it may be involved in. Note that as far as the
@@ -339,7 +331,6 @@
 
 protected:
     Model() :
-        m_id(getNextId()),
         m_sourceModel(0), 
         m_alignment(0), 
         m_abandoning(false), 
@@ -350,15 +341,15 @@
     Model(const Model &);
     Model &operator=(const Model &); 
 
-    const ModelId m_id;
     Model *m_sourceModel;
     AlignmentModel *m_alignment;
     QString m_typeUri;
     bool m_abandoning;
     bool m_aboutToDelete;
     sv_frame_t m_extendTo;
-    
-    int getNextId();
 };
 
+typedef Model::Id ModelId;
+typedef StaticById<Model, ModelId> ModelById;
+
 #endif
--- a/data/model/WritableWaveFileModel.cpp	Thu Jun 20 14:57:39 2019 +0100
+++ b/data/model/WritableWaveFileModel.cpp	Fri Jun 21 13:37:00 2019 +0100
@@ -96,7 +96,8 @@
             // so the filename only needs to be unique within that -
             // model ID should be ok
             QDir dir(TempDirectory::getInstance()->getPath());
-            path = dir.filePath(QString("written_%1.wav").arg(getId()));
+            path = dir.filePath(QString("written_%1.wav")
+                                .arg(getId().toString()));
         } catch (const DirectoryCreationFailed &f) {
             SVCERR << "WritableWaveFileModel: Failed to create temporary directory" << endl;
             return;
@@ -126,7 +127,8 @@
         // Temp dir is exclusive to this run of the application, so
         // the filename only needs to be unique within that
         QDir dir(TempDirectory::getInstance()->getPath());
-        m_temporaryPath = dir.filePath(QString("prenorm_%1.wav").arg(getId()));
+        m_temporaryPath = dir.filePath(QString("prenorm_%1.wav")
+                                       .arg(getId().toString()));
 
         m_temporaryWriter = new WavFileWriter
             (m_temporaryPath, m_sampleRate, m_channels,
--- a/files.pri	Thu Jun 20 14:57:39 2019 +0100
+++ b/files.pri	Fri Jun 21 13:37:00 2019 +0100
@@ -150,7 +150,6 @@
 	   
 SVCORE_SOURCES = \
            base/AudioLevel.cpp \
-           base/ById.cpp \
            base/Clipboard.cpp \
            base/ColumnOp.cpp \
            base/Command.cpp \