LibrePCB Developers Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
serializableobjectlist.h
Go to the documentation of this file.
1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LIBREPCB_SERIALIZABLEOBJECTLIST_H
21 #define LIBREPCB_SERIALIZABLEOBJECTLIST_H
22 
23 /*******************************************************************************
24  * Includes
25  ******************************************************************************/
26 #include "../uuid.h"
27 #include "serializableobject.h"
28 
29 #include <QtCore>
30 
31 #include <memory>
32 
33 /*******************************************************************************
34  * Namespace / Forward Declarations
35  ******************************************************************************/
36 namespace librepcb {
37 
38 /*******************************************************************************
39  * Class SerializableObjectList
40  ******************************************************************************/
41 
91 template <typename T, typename P>
93  Q_DECLARE_TR_FUNCTIONS(SerializableObjectList)
94 
95 public:
96  // Observer Type
97  class IF_Observer {
98  public:
99  virtual void listObjectAdded(const SerializableObjectList<T, P>& list,
100  int newIndex,
101  const std::shared_ptr<T>& ptr) noexcept = 0;
102  virtual void listObjectRemoved(const SerializableObjectList<T, P>& list,
103  int oldIndex,
104  const std::shared_ptr<T>& ptr) noexcept = 0;
105  };
106 
107  // Iterator Types
108  template <typename I, typename O>
109  class Iterator {
110  I it;
111 
112  public:
113  Iterator() = delete;
114  Iterator(const Iterator& other) noexcept : it(other.it) {}
115  Iterator(const I& it) noexcept : it(it) {}
116  bool operator!=(const Iterator& rhs) const noexcept { return it != rhs.it; }
118  ++it;
119  return *this;
120  }
121  O& operator*() { return **it; }
122  std::shared_ptr<O> ptr() noexcept {
123  return std::const_pointer_cast<O>(*it);
124  }
126  };
127  using iterator = Iterator<typename QVector<std::shared_ptr<T>>::iterator, T>;
128  using const_iterator =
129  Iterator<typename QVector<std::shared_ptr<T>>::const_iterator, const T>;
130 
131  // Constructors / Destructor
132  explicit SerializableObjectList(IF_Observer* observer = nullptr) noexcept {
133  if (observer) registerObserver(observer);
134  }
136  IF_Observer* observer = nullptr) noexcept {
137  *this = other; // copy all elements
138  if (observer) registerObserver(observer);
139  }
141  IF_Observer* observer = nullptr) noexcept {
142  mObjects = other.mObjects; // copy all pointers (NOT the objects!)
143  other.clear(); // remove all other's elements with notifying its observers
144  if (observer) registerObserver(observer);
145  }
146  SerializableObjectList(std::initializer_list<std::shared_ptr<T>> elements,
147  IF_Observer* observer = nullptr) noexcept {
148  mObjects = elements;
149  if (observer) registerObserver(observer);
150  }
151  SerializableObjectList(std::initializer_list<T> elements,
152  IF_Observer* observer = nullptr) noexcept {
153  mObjects.reserve(elements.size());
154  for (const T& obj : elements) {
155  append(std::make_shared<T>(obj));
156  } // copy element
157  if (observer) registerObserver(observer);
158  }
159  explicit SerializableObjectList(const SExpression& node,
160  IF_Observer* observer = nullptr) {
161  loadFromDomElement(node); // can throw
162  if (observer) registerObserver(observer);
163  }
164  virtual ~SerializableObjectList() noexcept {}
165 
166  // Getters
167  bool isEmpty() const noexcept { return mObjects.empty(); }
168  int count() const noexcept { return mObjects.count(); }
169  std::vector<Uuid> getUuids() const noexcept {
170  std::vector<Uuid> uuids;
171  uuids.reserve(mObjects.count());
172  foreach (const std::shared_ptr<T>& obj, mObjects) {
173  uuids.push_back(obj->getUuid());
174  }
175  return uuids;
176  }
177  QSet<Uuid> getUuidSet() const noexcept {
178  QSet<Uuid> uuids;
179  uuids.reserve(mObjects.count());
180  foreach (const std::shared_ptr<T>& obj, mObjects) {
181  uuids.insert(obj->getUuid());
182  }
183  return uuids;
184  }
185 
186  // Element Query
187  int indexOf(const T* obj) const noexcept {
188  for (int i = 0; i < count(); ++i) {
189  if (mObjects[i].get() == obj) {
190  return i;
191  }
192  }
193  return -1;
194  }
195  int indexOf(const Uuid& key) const noexcept {
196  for (int i = 0; i < count(); ++i) {
197  if (mObjects[i]->getUuid() == key) {
198  return i;
199  }
200  }
201  return -1;
202  }
203  int indexOf(const QString& name) const noexcept {
204  for (int i = 0; i < count(); ++i) {
205  if (mObjects[i]->getName() == name) {
206  return i;
207  }
208  }
209  return -1;
210  }
211  bool contains(int index) const noexcept {
212  return index >= 0 && index < mObjects.count();
213  }
214  bool contains(const T* obj) const noexcept { return indexOf(obj) >= 0; }
215  bool contains(const Uuid& key) const noexcept { return indexOf(key) >= 0; }
216  bool contains(const QString& name) const noexcept {
217  return indexOf(name) >= 0;
218  }
219 
220  // "Soft" Element Access (null if not found)
221  std::shared_ptr<T> value(int index) noexcept { return mObjects.value(index); }
222  std::shared_ptr<const T> value(int index) const noexcept {
223  return std::const_pointer_cast<const T>(mObjects.value(index));
224  }
225  std::shared_ptr<T> find(const T* obj) noexcept { return value(indexOf(obj)); }
226  std::shared_ptr<T> find(const Uuid& key) noexcept {
227  return value(indexOf(key));
228  }
229  std::shared_ptr<const T> find(const Uuid& key) const noexcept {
230  return value(indexOf(key));
231  }
232  std::shared_ptr<T> find(const QString& name) noexcept {
233  return value(indexOf(name));
234  }
235  std::shared_ptr<const T> find(const QString& name) const noexcept {
236  return value(indexOf(name));
237  }
238 
239  // "Hard" Element Access (assertion or exception if not found!)
240  std::shared_ptr<const T> at(int index) const noexcept {
241  return std::const_pointer_cast<const T>(mObjects.at(index));
242  } // always read-only!
243  std::shared_ptr<T>& first() noexcept { return mObjects.first(); }
244  std::shared_ptr<const T> first() const noexcept { return mObjects.first(); }
245  std::shared_ptr<T>& last() noexcept { return mObjects.last(); }
246  std::shared_ptr<const T> last() const noexcept { return mObjects.last(); }
247  std::shared_ptr<T> get(const T* obj) {
248  std::shared_ptr<T> ptr = find(obj);
249  if (!ptr) throw LogicError(__FILE__, __LINE__);
250  return ptr;
251  }
252  std::shared_ptr<T> get(const Uuid& key) {
253  std::shared_ptr<T> ptr = find(key);
254  if (!ptr) throwKeyNotFoundException(key);
255  return ptr;
256  }
257  std::shared_ptr<const T> get(const Uuid& key) const {
258  std::shared_ptr<const T> ptr = find(key);
259  if (!ptr) throwKeyNotFoundException(key);
260  return ptr;
261  }
262  std::shared_ptr<T> get(const QString& name) {
263  std::shared_ptr<T> ptr = find(name);
264  if (!ptr) throwNameNotFoundException(name);
265  return ptr;
266  }
267  std::shared_ptr<const T> get(const QString& name) const {
268  std::shared_ptr<const T> ptr = find(name);
269  if (!ptr) throwNameNotFoundException(name);
270  return ptr;
271  }
272 
273  // Iterator Access
274  const_iterator begin() const noexcept { return mObjects.begin(); }
275  const_iterator end() const noexcept { return mObjects.end(); }
276  const_iterator cbegin() noexcept { return mObjects.cbegin(); }
277  const_iterator cend() noexcept { return mObjects.cend(); }
278  iterator begin() noexcept { return mObjects.begin(); }
279  iterator end() noexcept { return mObjects.end(); }
280 
281  // General Methods
282  int loadFromDomElement(const SExpression& node) {
283  clear();
284  foreach (const SExpression& node, node.getChildren(P::tagname)) {
285  append(std::make_shared<T>(node)); // can throw
286  }
287  return count();
288  }
289  void swap(int i, int j) noexcept {
290  // do not call mObjects.swap() because it would not notify the observers
291  qBound(0, i, count() - 1);
292  qBound(0, j, count() - 1);
293  if (i == j) return;
294  if (i > j) qSwap(i, j);
295  std::shared_ptr<T> oj = take(j);
296  std::shared_ptr<T> oi = take(i);
297  insert(i, oj);
298  insert(j, oi);
299  }
300  int insert(int index, const std::shared_ptr<T>& obj) noexcept {
301  Q_ASSERT(obj);
302  qBound(0, index, count());
303  mObjects.insert(index, obj);
304  notifyObjectAdded(index, obj);
305  return index;
306  }
307  int append(const std::shared_ptr<T>& obj) noexcept {
308  return insert(count(), obj);
309  }
310  std::shared_ptr<T> take(int index) noexcept {
311  Q_ASSERT(contains(index));
312  std::shared_ptr<T> obj = mObjects.takeAt(index);
313  notifyObjectRemoved(index, obj);
314  return std::move(obj);
315  }
316  std::shared_ptr<T> take(const T* obj) noexcept { return take(indexOf(obj)); }
317  std::shared_ptr<T> take(const Uuid& uuid) noexcept {
318  return take(indexOf(uuid));
319  }
320  std::shared_ptr<T> take(const QString& name) noexcept {
321  return take(indexOf(name));
322  }
323  void remove(int index) noexcept { take(index); }
324  void remove(const T* obj) noexcept { take(obj); }
325  void remove(const Uuid& uuid) noexcept { take(uuid); }
326  void remove(const QString& name) noexcept { take(name); }
327  void clear() noexcept {
328  // do not call mObjects.clear() because it would not notify the observers
329  for (int i = count() - 1; i >= 0; --i) {
330  remove(i);
331  }
332  }
334  void serialize(SExpression& root) const override {
335  serializePointerContainer(root, mObjects, P::tagname); // can throw
336  }
337 
338  // Convenience Methods
340  SerializableObjectList<T, P> copiedList;
341  copiedList.mObjects = mObjects; // copy only the pointers, not the objects!
342  qSort(copiedList.mObjects.begin(), copiedList.mObjects.end(),
343  [](const std::shared_ptr<T>& ptr1, const std::shared_ptr<T>& ptr2) {
344  return ptr1->getUuid() < ptr2->getUuid();
345  });
346  return copiedList;
347  }
349  SerializableObjectList<T, P> copiedList;
350  copiedList.mObjects = mObjects; // copy only the pointers, not the objects!
351  qSort(copiedList.mObjects.begin(), copiedList.mObjects.end(),
352  [](const std::shared_ptr<T>& ptr1, const std::shared_ptr<T>& ptr2) {
353  return ptr1->getName() < ptr2->getName();
354  });
355  return copiedList;
356  }
357 
358  // Observer Methods
359  void registerObserver(IF_Observer* o) noexcept {
360  Q_ASSERT(o);
361  mObservers.append(o);
362  }
363  void unregisterObserver(IF_Observer* o) noexcept {
364  Q_ASSERT(o);
365  mObservers.removeOne(o);
366  }
367 
368  // Operator Overloadings
369  std::shared_ptr<T> operator[](int i) noexcept {
370  Q_ASSERT(contains(i));
371  return mObjects[i];
372  }
373  std::shared_ptr<const T> operator[](int i) const noexcept {
374  Q_ASSERT(contains(i));
375  return mObjects[i];
376  }
377  bool operator==(const SerializableObjectList<T, P>& rhs) const noexcept {
378  if (rhs.mObjects.count() != mObjects.count()) return false;
379  for (int i = 0; i < mObjects.count(); ++i) {
380  if (*rhs.mObjects[i] != *mObjects[i]) return false;
381  }
382  return true;
383  }
384  bool operator!=(const SerializableObjectList<T, P>& rhs) const noexcept {
385  return !(*this == rhs);
386  }
388  const SerializableObjectList<T, P>& rhs) noexcept {
389  clear();
390  mObjects.reserve(rhs.count());
391  foreach (const std::shared_ptr<T>& ptr, rhs.mObjects) {
392  append(std::make_shared<T>(*ptr)); // call copy constructor of object
393  }
394  return *this;
395  }
397  SerializableObjectList<T, P>&& rhs) noexcept {
398  clear();
399  mObjects.reserve(rhs.count());
400  foreach (const std::shared_ptr<T>& ptr, rhs.mObjects) {
401  append(ptr); // copy only the pointer, NOT the object
402  }
403  rhs.clear();
404  return *this;
405  }
406 
407 protected: // Methods
408  void notifyObjectAdded(int index, const std::shared_ptr<T>& obj) noexcept {
409  foreach (IF_Observer* observer, mObservers) {
410  observer->listObjectAdded(*this, index, obj);
411  }
412  }
413  void notifyObjectRemoved(int index, const std::shared_ptr<T>& obj) noexcept {
414  foreach (IF_Observer* observer, mObservers) {
415  observer->listObjectRemoved(*this, index, obj);
416  }
417  }
418  void throwKeyNotFoundException(const Uuid& key) const {
419  throw RuntimeError(
420  __FILE__, __LINE__,
421  QString(
422  tr("There is "
423  "no element of type \"%1\" with the UUID \"%2\" in the list."))
424  .arg(P::tagname)
425  .arg(key.toStr()));
426  }
427  void throwNameNotFoundException(const QString& name) const {
428  throw RuntimeError(
429  __FILE__, __LINE__,
430  QString(
431  tr("There is "
432  "no element of type \"%1\" with the name \"%2\" in the list."))
433  .arg(P::tagname)
434  .arg(name));
435  }
436 
437 protected: // Data
438  QVector<std::shared_ptr<T>> mObjects;
439  QList<IF_Observer*> mObservers;
440 };
441 
442 } // namespace librepcb
443 
444 /*******************************************************************************
445  * Prevent from using SerializableObjectList in a foreach loop because it always
446  *would create a deep copy of the list! You should use C++11 range based for
447  *loops instead.
448  ******************************************************************************/
449 
450 #if (QT_VERSION > QT_VERSION_CHECK(5, 9, 0))
451 namespace QtPrivate {
452 #endif
453 
454 template <typename T, typename P>
455 class QForeachContainer<librepcb::SerializableObjectList<T, P>> {
456 public:
457  ~QForeachContainer() = delete;
458 };
459 template <typename T, typename P>
460 class QForeachContainer<const librepcb::SerializableObjectList<T, P>> {
461 public:
462  ~QForeachContainer() = delete;
463 };
464 
465 #if (QT_VERSION > QT_VERSION_CHECK(5, 9, 0))
466 } // namespace QtPrivate
467 #endif
468 
469 /*******************************************************************************
470  * End of File
471  ******************************************************************************/
472 
473 #endif // LIBREPCB_SERIALIZABLEOBJECTLIST_H
I it
Definition: serializableobjectlist.h:110
const_iterator cend() noexcept
Definition: serializableobjectlist.h:277
The LogicError class.
Definition: exceptions.h:182
bool operator!=(const Iterator &rhs) const noexcept
Definition: serializableobjectlist.h:116
const QList< SExpression > & getChildren() const
Definition: sexpression.h:87
std::shared_ptr< T > & last() noexcept
Definition: serializableobjectlist.h:245
virtual void listObjectRemoved(const SerializableObjectList< T, P > &list, int oldIndex, const std::shared_ptr< T > &ptr) noexcept=0
static void serializePointerContainer(SExpression &root, const T &container, const QString &itemName)
Definition: serializableobject.h:99
SerializableObjectList< T, P > & operator=(SerializableObjectList< T, P > &&rhs) noexcept
Definition: serializableobjectlist.h:396
std::shared_ptr< T > value(int index) noexcept
Definition: serializableobjectlist.h:221
void clear() noexcept
Definition: serializableobjectlist.h:327
bool operator==(const SerializableObjectList< T, P > &rhs) const noexcept
Definition: serializableobjectlist.h:377
std::vector< Uuid > getUuids() const noexcept
Definition: serializableobjectlist.h:169
std::shared_ptr< T > operator[](int i) noexcept
Definition: serializableobjectlist.h:369
iterator end() noexcept
Definition: serializableobjectlist.h:279
Iterator(const I &it) noexcept
Definition: serializableobjectlist.h:115
The SerializableObjectList class implements a list of librepcb::SerializableObject.
Definition: serializableobjectlist.h:92
int indexOf(const QString &name) const noexcept
Definition: serializableobjectlist.h:203
Iterator< typename QVector< std::shared_ptr< Circle >>::const_iterator, const Circle > const_iterator
Definition: serializableobjectlist.h:129
O & operator*()
Definition: serializableobjectlist.h:121
std::shared_ptr< O > ptr() noexcept
Definition: serializableobjectlist.h:122
QList< IF_Observer * > mObservers
Definition: serializableobjectlist.h:439
int count() const noexcept
Definition: serializableobjectlist.h:168
bool contains(int index) const noexcept
Definition: serializableobjectlist.h:211
virtual void listObjectAdded(const SerializableObjectList< T, P > &list, int newIndex, const std::shared_ptr< T > &ptr) noexcept=0
QSet< Uuid > getUuidSet() const noexcept
Definition: serializableobjectlist.h:177
bool contains(const T *obj) const noexcept
Definition: serializableobjectlist.h:214
SerializableObjectList< T, P > & operator=(const SerializableObjectList< T, P > &rhs) noexcept
Definition: serializableobjectlist.h:387
~Iterator()
Definition: serializableobjectlist.h:125
std::shared_ptr< T > & first() noexcept
Definition: serializableobjectlist.h:243
bool isEmpty() const noexcept
Definition: serializableobjectlist.h:167
The SerializableObject class is the base class for all classes which need to be serializable/deserial...
Definition: serializableobject.h:46
void serialize(SExpression &root) const override
Serialize the object into an existing S-Expression node.
Definition: serializableobjectlist.h:334
iterator begin() noexcept
Definition: serializableobjectlist.h:278
void registerObserver(IF_Observer *o) noexcept
Definition: serializableobjectlist.h:359
void notifyObjectAdded(int index, const std::shared_ptr< T > &obj) noexcept
Definition: serializableobjectlist.h:408
SerializableObjectList< T, P > sortedByUuid() const noexcept
Definition: serializableobjectlist.h:339
std::shared_ptr< const T > at(int index) const noexcept
Definition: serializableobjectlist.h:240
std::shared_ptr< const T > find(const Uuid &key) const noexcept
Definition: serializableobjectlist.h:229
int append(const std::shared_ptr< T > &obj) noexcept
Definition: serializableobjectlist.h:307
std::shared_ptr< const T > operator[](int i) const noexcept
Definition: serializableobjectlist.h:373
bool contains(const QString &name) const noexcept
Definition: serializableobjectlist.h:216
std::shared_ptr< T > take(int index) noexcept
Definition: serializableobjectlist.h:310
std::shared_ptr< const T > value(int index) const noexcept
Definition: serializableobjectlist.h:222
The RuntimeError class.
Definition: exceptions.h:219
void throwKeyNotFoundException(const Uuid &key) const
Definition: serializableobjectlist.h:418
std::shared_ptr< const T > find(const QString &name) const noexcept
Definition: serializableobjectlist.h:235
void swap(int i, int j) noexcept
Definition: serializableobjectlist.h:289
SerializableObjectList(std::initializer_list< std::shared_ptr< T >> elements, IF_Observer *observer=nullptr) noexcept
Definition: serializableobjectlist.h:146
int indexOf(const T *obj) const noexcept
Definition: serializableobjectlist.h:187
int insert(int index, const std::shared_ptr< T > &obj) noexcept
Definition: serializableobjectlist.h:300
std::shared_ptr< T > find(const Uuid &key) noexcept
Definition: serializableobjectlist.h:226
bool operator!=(const SerializableObjectList< T, P > &rhs) const noexcept
Definition: serializableobjectlist.h:384
Definition: serializableobjectlist.h:109
std::shared_ptr< T > find(const QString &name) noexcept
Definition: serializableobjectlist.h:232
SerializableObjectList(const SExpression &node, IF_Observer *observer=nullptr)
Definition: serializableobjectlist.h:159
std::shared_ptr< T > take(const QString &name) noexcept
Definition: serializableobjectlist.h:320
Iterator(const Iterator &other) noexcept
Definition: serializableobjectlist.h:114
const_iterator cbegin() noexcept
Definition: serializableobjectlist.h:276
Definition: serializableobjectlist.h:97
void unregisterObserver(IF_Observer *o) noexcept
Definition: serializableobjectlist.h:363
SerializableObjectList(IF_Observer *observer=nullptr) noexcept
Definition: serializableobjectlist.h:132
SerializableObjectList(std::initializer_list< T > elements, IF_Observer *observer=nullptr) noexcept
Definition: serializableobjectlist.h:151
SerializableObjectList(SerializableObjectList< T, P > &&other, IF_Observer *observer=nullptr) noexcept
Definition: serializableobjectlist.h:140
virtual ~SerializableObjectList() noexcept
Definition: serializableobjectlist.h:164
std::shared_ptr< T > take(const Uuid &uuid) noexcept
Definition: serializableobjectlist.h:317
std::shared_ptr< T > take(const T *obj) noexcept
Definition: serializableobjectlist.h:316
SerializableObjectList< T, P > sortedByName() const noexcept
Definition: serializableobjectlist.h:348
int indexOf(const Uuid &key) const noexcept
Definition: serializableobjectlist.h:195
SerializableObjectList(const SerializableObjectList< T, P > &other, IF_Observer *observer=nullptr) noexcept
Definition: serializableobjectlist.h:135
std::shared_ptr< T > find(const T *obj) noexcept
Definition: serializableobjectlist.h:225
The Uuid class is a replacement for QUuid to get UUID strings without {} braces.
Definition: uuid.h:58
const_iterator end() const noexcept
Definition: serializableobjectlist.h:275
QVector< std::shared_ptr< T > > mObjects
Definition: serializableobjectlist.h:438
bool contains(const Uuid &key) const noexcept
Definition: serializableobjectlist.h:215
Iterator & operator++()
Definition: serializableobjectlist.h:117
void notifyObjectRemoved(int index, const std::shared_ptr< T > &obj) noexcept
Definition: serializableobjectlist.h:413
void throwNameNotFoundException(const QString &name) const
Definition: serializableobjectlist.h:427
The SExpression class.
Definition: sexpression.h:60
QString toStr() const noexcept
Get the UUID as a string (without braces)
Definition: uuid.h:88
int loadFromDomElement(const SExpression &node)
Definition: serializableobjectlist.h:282
std::shared_ptr< const T > last() const noexcept
Definition: serializableobjectlist.h:246
std::shared_ptr< const T > first() const noexcept
Definition: serializableobjectlist.h:244
const_iterator begin() const noexcept
Definition: serializableobjectlist.h:274
Iterator< typename QVector< std::shared_ptr< Circle >>::iterator, Circle > iterator
Definition: serializableobjectlist.h:127