File indexing completed on 2024-05-12 15:58:40

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KIS_SAFE_READ_LIST_H_
0008 #define KIS_SAFE_READ_LIST_H_
0009 
0010 
0011 #include <QList>
0012 
0013 /**
0014  * \class KisSafeReadList
0015  *
0016  * This is a special wrapper around QList class
0017  * Q: Why is it needed?
0018  * A: It guarantees thread-safety of all the read requests to the list.
0019  *    There is absolutely *no* guarantees for write requests though.
0020  * Q: Why pure QList cannot guarantee it?
0021  * A: First, Qt does not guarantee thread-safety for QList at all.
0022  *    Second, QList is implicitly shared structure, therefore even
0023  *    with read, but non-const requests (e.g. non-const QList::first()),
0024  *    QList will perform internal write operations. That will lead to
0025  *    a race condition in an environment with 3 and more threads.
0026  */
0027 template<class T> class KisSafeReadList : private QList<T> {
0028 public:
0029     KisSafeReadList() {}
0030 
0031     using typename QList<T>::const_iterator;
0032 
0033     /**
0034      * All the methods of this class are split into two groups:
0035      * treadsafe and non-threadsafe. The methods from the first group
0036      * can be called concurrently with each other. The ones form
0037      * the other group can't be called concurrently (even with the
0038      * friends from the first group) and must have an exclusive
0039      * access to the list.
0040      */
0041 
0042     /**
0043      * The thread-safe group
0044      */
0045 
0046     inline const T& first() const {
0047         return QList<T>::first();
0048     }
0049 
0050     inline const T& last() const {
0051         return QList<T>::last();
0052     }
0053 
0054     inline const T& at(int i) const {
0055         return QList<T>::at(i);
0056     }
0057 
0058     using QList<T>::constBegin;
0059     using QList<T>::constEnd;
0060     using QList<T>::isEmpty;
0061     using QList<T>::size;
0062     using QList<T>::indexOf;
0063     using QList<T>::contains;
0064 
0065     /**
0066      * The non-thread-safe group
0067      */
0068 
0069     using QList<T>::append;
0070     using QList<T>::prepend;
0071     using QList<T>::insert;
0072     using QList<T>::removeAt;
0073     using QList<T>::clear;
0074 
0075 private:
0076     Q_DISABLE_COPY(KisSafeReadList)
0077 };
0078 
0079 
0080 #define FOREACH_SAFE(_iter, _container)         \
0081     for(_iter = _container.constBegin();        \
0082         _iter != _container.constEnd();         \
0083         _iter++)
0084 
0085 
0086 #endif /* KIS_SAFE_READ_LIST_H_ */