ById.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 #include "ById.h"
16 
17 #include <unordered_map>
18 #include <typeinfo>
19 
20 //#define DEBUG_BY_ID 1
21 
23 {
24  static int nextId = 0;
25  static QMutex mutex;
26  QMutexLocker locker(&mutex);
27  int i = nextId;
28  if (nextId == INT_MAX) {
29  nextId = INT_MIN;
30  } else {
31  ++nextId;
32  if (nextId == 0 || nextId == NO_ID) {
33  throw std::runtime_error("Internal ID limit exceeded!");
34  }
35  }
36  return i;
37 }
38 
39 // "warning: expression with side effects will be evaluated despite
40 // being used as an operand to 'typeid'"
41 #ifdef __clang__
42 #pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
43 #endif
44 
46 {
47 public:
48  ~Impl() {
49  QMutexLocker locker(&m_mutex);
50  bool empty = true;
51  for (const auto &p: m_items) {
52  if (p.second && p.second.use_count() > 0) {
53  empty = false;
54  break;
55  }
56  }
57  if (!empty) {
58  SVCERR << "WARNING: ById map is not empty at close; some items have not been released" << endl;
59  SVCERR << " Unreleased items are:" << endl;
60  for (const auto &p: m_items) {
61  auto ptr = p.second;
62  if (ptr && ptr.use_count() > 0) {
63  QString message = QString("id #%1: type %2")
64  .arg(p.first).arg(typeid(*ptr.get()).name());
65  if (auto qobj = std::dynamic_pointer_cast<QObject>(ptr)) {
66  message += QString(", object name \"%1\"")
67  .arg(qobj->objectName());
68  }
69  message += QString(", use count %1").arg(ptr.use_count());
70  SVCERR << " - " << message << endl;
71  }
72  }
73  }
74  }
75 
76  int add(std::shared_ptr<WithId> item) {
77  int id = item->getUntypedId();
78  if (id == IdAlloc::NO_ID) {
79  throw std::logic_error("item id should never be NO_ID");
80  }
81 #ifdef DEBUG_BY_ID
82  SVCERR << "ById::add(#" << id << ") of type "
83  << typeid(*item.get()).name() << endl;
84 #endif
85  QMutexLocker locker(&m_mutex);
86  if (m_items.find(id) != m_items.end()) {
87  SVCERR << "ById::add: item with id " << id
88  << " is already recorded (existing item type is "
89  << typeid(*m_items.find(id)->second.get()).name()
90  << ", proposed is "
91  << typeid(*item.get()).name() << ")" << endl;
92  throw std::logic_error("item id is already recorded in add");
93  }
94  m_items[id] = item;
95  return id;
96  }
97 
98  void release(int id) {
99  if (id == IdAlloc::NO_ID) {
100  return;
101  }
102 #ifdef DEBUG_BY_ID
103  SVCERR << "ById::release(#" << id << ")" << endl;
104 #endif
105  QMutexLocker locker(&m_mutex);
106  if (m_items.find(id) == m_items.end()) {
107  SVCERR << "ById::release: unknown item id " << id << endl;
108  throw std::logic_error("unknown item id in release");
109  }
110  m_items.erase(id);
111  }
112 
113  std::shared_ptr<WithId> get(int id) const {
114  if (id == IdAlloc::NO_ID) {
115  return {}; // this id cannot be added: avoid locking
116  }
117  QMutexLocker locker(&m_mutex);
118  const auto &itr = m_items.find(id);
119  if (itr != m_items.end()) {
120  return itr->second;
121  } else {
122  return {};
123  }
124  }
125 
126 private:
127  mutable QMutex m_mutex;
128  std::unordered_map<int, std::shared_ptr<WithId>> m_items;
129 };
130 
131 int
132 AnyById::add(std::shared_ptr<WithId> item)
133 {
134  return impl().add(item);
135 }
136 
137 void
139 {
140  impl().release(id);
141 }
142 
143 std::shared_ptr<WithId>
145 {
146  return impl().get(id);
147 }
148 
151 {
152  static Impl impl;
153  return impl;
154 }
int add(std::shared_ptr< WithId > item)
Definition: ById.cpp:76
static const int NO_ID
Definition: ById.h:109
static QMutex mutex
Definition: Debug.cpp:30
static std::shared_ptr< WithId > get(int)
Definition: ById.cpp:144
static void release(int)
Definition: ById.cpp:138
static Impl & impl()
Definition: ById.cpp:150
static int add(std::shared_ptr< WithId >)
Definition: ById.cpp:132
QMutex m_mutex
Definition: ById.cpp:127
void release(int id)
Definition: ById.cpp:98
#define SVCERR
Definition: Debug.h:109
std::unordered_map< int, std::shared_ptr< WithId > > m_items
Definition: ById.cpp:128
static int getNextId()
Definition: ById.cpp:22