| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt3D module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #ifndef QT3DCORE_QCIRCULARBUFFER_H | 
| 41 | #define QT3DCORE_QCIRCULARBUFFER_H | 
| 42 |  | 
| 43 | // | 
| 44 | //  W A R N I N G | 
| 45 | //  ------------- | 
| 46 | // | 
| 47 | // This file is not part of the Qt API.  It exists for the convenience | 
| 48 | // of other Qt classes.  This header file may change from version to | 
| 49 | // version without notice, or even be removed. | 
| 50 | // | 
| 51 | // We mean it. | 
| 52 | // | 
| 53 |  | 
| 54 | #include <Qt3DCore/qt3dcore_global.h> | 
| 55 | #include <QtCore/QtGlobal> | 
| 56 | #include <QtCore/qlist.h> | 
| 57 | #include <QtCore/qpair.h> | 
| 58 | #include <QtCore/qshareddata.h> | 
| 59 | #include <QtCore/qvector.h> | 
| 60 |  | 
| 61 | #include <algorithm> | 
| 62 | #include <iterator> | 
| 63 | #include <limits> | 
| 64 | #include <memory> | 
| 65 | #include <new> | 
| 66 |  | 
| 67 |  | 
| 68 | #ifdef Q_COMPILER_INITIALIZER_LISTS | 
| 69 | # include <initializer_list> | 
| 70 | #endif | 
| 71 |  | 
| 72 | QT_BEGIN_NAMESPACE | 
| 73 |  | 
| 74 | namespace Qt3DCore { | 
| 75 |  | 
| 76 | class CircularBufferData : public QSharedData | 
| 77 | { | 
| 78 | protected: | 
| 79 |     CircularBufferData() | 
| 80 |         : data(nullptr), | 
| 81 |           capacity(0), | 
| 82 |           size(0), | 
| 83 |           first(-1), | 
| 84 |           last(-1) | 
| 85 |     {} | 
| 86 |  | 
| 87 |     ~CircularBufferData() | 
| 88 |     { | 
| 89 |         // Release the raw memory | 
| 90 |         deallocate(p: data); | 
| 91 |     } | 
| 92 |  | 
| 93 |     int wraparound(int index) const | 
| 94 |     { | 
| 95 |         index = index < capacity ? index : (index - capacity); | 
| 96 |         Q_ASSERT(index < capacity); // make sure that wrapping around once was enough | 
| 97 |         return index; | 
| 98 |     } | 
| 99 |  | 
| 100 |     void *allocate(int count, size_t sizeOfT) | 
| 101 |     { return operator new[](count * sizeOfT); } | 
| 102 |     void deallocate(void *p) | 
| 103 |     { operator delete[](p); } | 
| 104 |  | 
| 105 |     void *data;      // Array of the actual data | 
| 106 | public: | 
| 107 |     int capacity; // Size of the m_data array | 
| 108 |     int size;     // Number of elements of m_data actually used | 
| 109 |     int first;    // Index in m_data of the first element of the circular buffer | 
| 110 |     int last;     // Index in m_data of the last element of the circular buffer | 
| 111 | }; | 
| 112 |  | 
| 113 | template <typename T> | 
| 114 | class TypedCircularBufferData : public CircularBufferData | 
| 115 | { | 
| 116 |     template <typename InputIterator> | 
| 117 |     explicit TypedCircularBufferData(InputIterator f, InputIterator l, std::input_iterator_tag) Q_DECL_EQ_DELETE; | 
| 118 | public: | 
| 119 |     TypedCircularBufferData() : CircularBufferData() {} | 
| 120 |     template <typename ForwardIterator> | 
| 121 |     explicit TypedCircularBufferData(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) | 
| 122 |     { | 
| 123 |         const int n = int(std::distance(f, l)); | 
| 124 |         CircularBufferData::data = allocate(count: n); | 
| 125 |         std::uninitialized_copy(f, l, data()); | 
| 126 |         first = 0; | 
| 127 |         last = n - 1; | 
| 128 |         size = capacity = n; | 
| 129 |     } | 
| 130 |     ~TypedCircularBufferData() | 
| 131 |     { | 
| 132 |         if (QTypeInfo<T>::isComplex && size != 0) { | 
| 133 |             // The type is complex so we manually call the destructor for each item | 
| 134 |             // since we used the placement new operator to instantiate them | 
| 135 |             if (first <= last) { | 
| 136 |                 // Destroy items from first to last | 
| 137 |                 T *b = data() + first; | 
| 138 |                 T *i = b + size; | 
| 139 |                 while (i-- != b) | 
| 140 |                      i->~T(); | 
| 141 |             } else { | 
| 142 |                 // Destroy items at end of data array | 
| 143 |                 T *b = data() + first; | 
| 144 |                 T *i = data() + capacity; | 
| 145 |                 while (i-- != b) | 
| 146 |                      i->~T(); | 
| 147 |  | 
| 148 |                 // Destroy items at beginning of data array | 
| 149 |                 b = data(); | 
| 150 |                 i = b + last; | 
| 151 |                 while (i-- != b) | 
| 152 |                      i->~T(); | 
| 153 |             } | 
| 154 |         } | 
| 155 |  | 
| 156 |     } | 
| 157 |  | 
| 158 |     using CircularBufferData::wraparound; | 
| 159 |     T *allocate(int count) { return static_cast<T*>(CircularBufferData::allocate(count, sizeOfT: sizeof(T))); } | 
| 160 |     using CircularBufferData::deallocate; | 
| 161 |     T *data() const { return static_cast<T*>(CircularBufferData::data); } | 
| 162 |     void setData(T *newdata) { CircularBufferData::data = static_cast<void*>(newdata); } | 
| 163 | }; | 
| 164 |  | 
| 165 | template <typename T> | 
| 166 | class QCircularBuffer | 
| 167 | { | 
| 168 |     typedef TypedCircularBufferData<T> Data; | 
| 169 | public: | 
| 170 |     typedef QPair<T*,int> array_range; | 
| 171 |     typedef QPair<const T*,int> const_array_range; | 
| 172 |     typedef array_range ArrayRange; | 
| 173 |     typedef const_array_range ConstArrayRange; | 
| 174 |  | 
| 175 |     QCircularBuffer() | 
| 176 |         : d(new Data()) | 
| 177 |     {} | 
| 178 |  | 
| 179 |     explicit QCircularBuffer(int amount); | 
| 180 |     explicit QCircularBuffer(int amount, const T &val); | 
| 181 |     explicit QCircularBuffer(int amount, int initialSize, const T &value); | 
| 182 | #ifdef Q_COMPILER_INITIALIZER_LISTS | 
| 183 |     QCircularBuffer(std::initializer_list<T> list) | 
| 184 |         : d(new Data(list.begin(), list.end(), std::random_access_iterator_tag())) | 
| 185 |     {} | 
| 186 | #endif | 
| 187 |     template <typename ForwardIterator> | 
| 188 |     explicit QCircularBuffer(ForwardIterator f, ForwardIterator l) | 
| 189 |         : d(new Data(f, l, typename std::iterator_traits<ForwardIterator>::iterator_category())) | 
| 190 |     {} | 
| 191 |  | 
| 192 |     QCircularBuffer(const QCircularBuffer<T> &other) | 
| 193 |         : d(other.d) | 
| 194 |     {} | 
| 195 |  | 
| 196 |     void swap(QCircularBuffer &other) { d.swap(other.d); } | 
| 197 |  | 
| 198 |     QCircularBuffer<T> &operator = (const QCircularBuffer<T> &other) | 
| 199 |     { | 
| 200 |         d = other.d; | 
| 201 |         return *this; | 
| 202 |     } | 
| 203 |  | 
| 204 |     ~QCircularBuffer() {} | 
| 205 |  | 
| 206 |     class iterator | 
| 207 |     { | 
| 208 |     public: | 
| 209 |         typedef std::random_access_iterator_tag iterator_category; | 
| 210 |         typedef ptrdiff_t difference_type; | 
| 211 |         typedef T value_type; | 
| 212 |         typedef T *pointer; | 
| 213 |         typedef T &reference; | 
| 214 |  | 
| 215 |         Q_DECL_CONSTEXPR iterator() : buffer(nullptr), index(-1) {} | 
| 216 |         iterator(QCircularBuffer<T> *buf, int idx) | 
| 217 |             : buffer(buf), index(idx) | 
| 218 |         {} | 
| 219 |  | 
| 220 |         T &operator*() const { return (*buffer)[ index ]; } | 
| 221 |         T *operator->() const { return &(*buffer)[index]; } | 
| 222 |         T &operator[](int j) const { return (*buffer)[ index + j ]; } | 
| 223 |  | 
| 224 |         bool operator==(const iterator &other) const | 
| 225 |         { | 
| 226 |             return (buffer == other.buffer && index == other.index); | 
| 227 |         } | 
| 228 |  | 
| 229 |         bool operator!=(const iterator &other) const | 
| 230 |         { | 
| 231 |             return (buffer != other.buffer || index != other.index); | 
| 232 |         } | 
| 233 |  | 
| 234 |         bool operator<(const iterator &other) const | 
| 235 |         { | 
| 236 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::iterator::operator<" , "iterators use different buffers" ); | 
| 237 |             return index < other.index; | 
| 238 |         } | 
| 239 |  | 
| 240 |         bool operator<=(const iterator &other) const | 
| 241 |         { | 
| 242 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::iterator::operator<=" , "iterators use different buffers" ); | 
| 243 |             return index <= other.index; | 
| 244 |         } | 
| 245 |  | 
| 246 |         bool operator>(const iterator &other) const | 
| 247 |         { | 
| 248 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::iterator::operator>" , "iterators use different buffers" ); | 
| 249 |             return index > other.index; | 
| 250 |         } | 
| 251 |  | 
| 252 |         bool operator>=(const iterator &other) const | 
| 253 |         { | 
| 254 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::iterator::operator>=" , "iterators use different buffers" ); | 
| 255 |             return index >= other.index; | 
| 256 |         } | 
| 257 |  | 
| 258 |         iterator &operator++() { ++index; return *this; } | 
| 259 |         iterator operator++(int) | 
| 260 |         { | 
| 261 |             iterator ans = *this; | 
| 262 |             ++index; | 
| 263 |             return ans; | 
| 264 |         } | 
| 265 |  | 
| 266 |         iterator &operator--() { --index; return *this; } | 
| 267 |         iterator operator--(int) | 
| 268 |         { | 
| 269 |             iterator ans = *this; | 
| 270 |             --index; | 
| 271 |             return ans; | 
| 272 |         } | 
| 273 |  | 
| 274 |         iterator &operator+=(int j) { index += j; return *this; } | 
| 275 |         iterator &operator-=(int j) { index -= j; return *this; } | 
| 276 |         iterator operator+(int j) const { return iterator(buffer, index + j); } | 
| 277 |         iterator operator-(int j) const { return iterator(buffer, index - j); } | 
| 278 |         int operator-(iterator other) const | 
| 279 |         { | 
| 280 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::iterator::operator-" , "iterators use different buffers" ); | 
| 281 |             return index - other.index; | 
| 282 |         } | 
| 283 |  | 
| 284 |     private: | 
| 285 |         QCircularBuffer<T> *buffer; | 
| 286 |         int index; | 
| 287 |         friend class QCircularBuffer; | 
| 288 |     }; | 
| 289 |     friend class iterator; | 
| 290 |  | 
| 291 |     class const_iterator | 
| 292 |     { | 
| 293 |     public: | 
| 294 |         typedef std::random_access_iterator_tag  iterator_category; | 
| 295 |         typedef ptrdiff_t difference_type; | 
| 296 |         typedef T value_type; | 
| 297 |         typedef const T *pointer; | 
| 298 |         typedef const T &reference; | 
| 299 |  | 
| 300 |         Q_DECL_CONSTEXPR const_iterator() : buffer(nullptr), index(-1) {} | 
| 301 |         const_iterator(const QCircularBuffer<T> *buff, int idx) | 
| 302 |             : buffer(buff), index(idx) | 
| 303 |         {} | 
| 304 |         const_iterator(const iterator &other) | 
| 305 |             : buffer(other.buffer), index(other.index) | 
| 306 |         {} | 
| 307 |  | 
| 308 |         const T &operator*() const { return buffer->at(index); } | 
| 309 |         const T *operator->() const { return &buffer->at(index); } | 
| 310 |         const T &operator[](int j) const { return buffer->at(index + j); } | 
| 311 |  | 
| 312 |         bool operator==(const const_iterator &other) const | 
| 313 |         { | 
| 314 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator==" , "iterators use different buffers" ); | 
| 315 |             return index == other.index; | 
| 316 |         } | 
| 317 |  | 
| 318 |         bool operator!=(const const_iterator &other) const | 
| 319 |         { | 
| 320 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator!=" , "iterators use different buffers" ); | 
| 321 |             return index != other.index; | 
| 322 |         } | 
| 323 |  | 
| 324 |         bool operator<(const const_iterator &other) const | 
| 325 |         { | 
| 326 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator<" , "iterators use different buffers" ); | 
| 327 |             return index < other.index; | 
| 328 |         } | 
| 329 |  | 
| 330 |         bool operator<=(const const_iterator &other) const | 
| 331 |         { | 
| 332 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator<=" , "iterators use different buffers" ); | 
| 333 |             return index <= other.index; | 
| 334 |         } | 
| 335 |  | 
| 336 |         bool operator>(const const_iterator &other) const | 
| 337 |         { | 
| 338 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator>" , "iterators use different buffers" ); | 
| 339 |             return index > other.index; | 
| 340 |         } | 
| 341 |  | 
| 342 |         bool operator>=(const const_iterator &other) const | 
| 343 |         { | 
| 344 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator>=" , "iterators use different buffers" ); | 
| 345 |             return index >= other.index; | 
| 346 |         } | 
| 347 |  | 
| 348 |         const_iterator &operator++() { ++index; return *this; } | 
| 349 |         const_iterator operator++(int) | 
| 350 |         { | 
| 351 |             const_iterator ans = *this; | 
| 352 |             ++index; | 
| 353 |             return ans; | 
| 354 |         } | 
| 355 |  | 
| 356 |         const_iterator &operator--() { --index; return *this; } | 
| 357 |         const_iterator operator--(int) | 
| 358 |         { | 
| 359 |             const_iterator ans = *this; | 
| 360 |             --index; | 
| 361 |             return ans; | 
| 362 |         } | 
| 363 |  | 
| 364 |         const_iterator &operator+=(int j) { index += j; return *this; } | 
| 365 |         const_iterator &operator-=(int j) { index -= j; return *this; } | 
| 366 |         const_iterator operator+(int j) const { return const_iterator(buffer, index + j); } | 
| 367 |         const_iterator operator-(int j) const { return const_iterator(buffer, index - j); } | 
| 368 |         int operator-(const_iterator other) const | 
| 369 |         { | 
| 370 |             Q_ASSERT_X(buffer == other.buffer, "QCircularBuffer<T>::const_iterator::operator-" , "iterators use different buffers" ); | 
| 371 |             return index - other.index; | 
| 372 |         } | 
| 373 |  | 
| 374 |     private: | 
| 375 |         const QCircularBuffer<T> *buffer; | 
| 376 |         int index; | 
| 377 |         friend class QCircularBuffer; | 
| 378 |     }; | 
| 379 |     friend class const_iterator; | 
| 380 |  | 
| 381 |     typedef std::reverse_iterator<iterator> reverse_iterator; | 
| 382 |     typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | 
| 383 |  | 
| 384 |     iterator begin() { return iterator(this, 0); } | 
| 385 |     const_iterator begin() const { return const_iterator(this, 0); } | 
| 386 |     const_iterator cbegin() const { return const_iterator(this, 0); } | 
| 387 |     reverse_iterator rbegin() { return reverse_iterator(end()); } | 
| 388 |     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } | 
| 389 |     const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } | 
| 390 |     const_iterator constBegin() const { return const_iterator(this, 0); } | 
| 391 |     iterator end() { return iterator(this, d->size); } | 
| 392 |     const_iterator end() const { return const_iterator(this, d->size); } | 
| 393 |     const_iterator cend() const { return const_iterator(this, d->size); } | 
| 394 |     reverse_iterator rend() { return reverse_iterator(begin()); } | 
| 395 |     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } | 
| 396 |     const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } | 
| 397 |     const_iterator constEnd() const { return const_iterator(this, d->size); } | 
| 398 |     iterator insert(const_iterator before, int number, const T &val) | 
| 399 |     { | 
| 400 |         insert(before.index, number, val); | 
| 401 |         return iterator(this, before.index); | 
| 402 |     } | 
| 403 |     iterator insert(const_iterator before, const T &val) { return insert(before, 1, val); } | 
| 404 |     iterator erase(const_iterator b, const_iterator e) | 
| 405 |     { | 
| 406 |         int number = e - b; | 
| 407 |         remove(b.index, number); | 
| 408 |         return iterator(this, e.index - number); | 
| 409 |     } | 
| 410 |     iterator erase(const_iterator pos) { return erase(pos, pos + 1); } | 
| 411 |  | 
| 412 |     // STL compatibility | 
| 413 |     typedef T value_type; | 
| 414 |     typedef value_type *pointer; | 
| 415 |     typedef const value_type *const_pointer; | 
| 416 |     typedef value_type &reference; | 
| 417 |     typedef const value_type &const_reference; | 
| 418 |     typedef ptrdiff_t difference_type; | 
| 419 |     typedef iterator Iterator; | 
| 420 |     typedef const_iterator ConstIterator; | 
| 421 |     typedef int size_type; | 
| 422 |  | 
| 423 |     void push_back(const T &t) { append(val: t); } | 
| 424 |     void push_front(const T &t) { prepend(val: t); } | 
| 425 |     void pop_back() { Q_ASSERT(!isEmpty()); erase(end() - 1); } | 
| 426 |     void pop_front() { Q_ASSERT(!isEmpty()); erase(begin()); } | 
| 427 |     bool empty() const { return isEmpty(); } | 
| 428 |     T &front() { return first(); } | 
| 429 |     const T &front() const { return first(); } | 
| 430 |     T &back() { return last(); } | 
| 431 |     const T &back() const { return last(); } | 
| 432 |  | 
| 433 |     QAtomicInt refCount() const { return d->ref; } | 
| 434 |  | 
| 435 |     void append(const T &val); | 
| 436 |  | 
| 437 |     const T &at(int i) const | 
| 438 |     { | 
| 439 |         Q_ASSERT_X(i >= 0 && i < d->size, "QCircularBuffer<T>::at" , "index out of range" ); | 
| 440 |         return d->data()[d->wraparound(d->first + i)]; | 
| 441 |     } | 
| 442 |  | 
| 443 |     const T &operator[](int i) const | 
| 444 |     { | 
| 445 |         Q_ASSERT_X(i >= 0 && i < d->size, "QCircularBuffer<T>::operator[]" , "index out of range" ); | 
| 446 |         return d->data()[d->wraparound(d->first + i)]; | 
| 447 |     } | 
| 448 |  | 
| 449 |     T &operator[](int i) | 
| 450 |     { | 
| 451 |         d.detach(); | 
| 452 |         Q_ASSERT_X(i >= 0 && i < d->size, "QCircularBuffer<T>::operator[]" , "index out of range" ); | 
| 453 |         return d->data()[d->wraparound(d->first + i)]; | 
| 454 |     } | 
| 455 |  | 
| 456 |     int capacity() const { return d->capacity; } | 
| 457 |  | 
| 458 |     void clear() { *this = QCircularBuffer<T>(d->capacity); } | 
| 459 |  | 
| 460 |     bool contains(const T &val) const; | 
| 461 |     int count(const T &val) const; | 
| 462 |     int count() const { return size(); } | 
| 463 |  | 
| 464 |     array_range data() | 
| 465 |     { | 
| 466 |         d.detach(); | 
| 467 |         if (d->size == 0) | 
| 468 |             return array_range(nullptr, 0); | 
| 469 |         if (!isLinearised()) | 
| 470 |             linearise(); | 
| 471 |         return array_range(d->data() + d->first, d->last - d->first + 1); | 
| 472 |     } | 
| 473 |     const_array_range data() const { return constData(); } | 
| 474 |     const_array_range constData() const | 
| 475 |     { | 
| 476 |         if (!isLinearised() || d->size == 0) | 
| 477 |             return const_array_range(nullptr, 0); | 
| 478 |         return const_array_range(d->data() + d->first, d->last - d->first + 1); | 
| 479 |     } | 
| 480 |  | 
| 481 |     array_range dataOne() | 
| 482 |     { | 
| 483 |         d.detach(); | 
| 484 |         if (d->size == 0) | 
| 485 |             return array_range(nullptr, 0); | 
| 486 |         if (isLinearised()) | 
| 487 |             return array_range(d->data() + d->first, d->last - d->first + 1); | 
| 488 |         else | 
| 489 |             return array_range(d->data() + d->first, d->capacity - d->first); | 
| 490 |     } | 
| 491 |     const_array_range dataOne() const { return constDataOne(); } | 
| 492 |     const_array_range constDataOne() const | 
| 493 |     { | 
| 494 |         if (d->size == 0) | 
| 495 |             return const_array_range(nullptr, 0); | 
| 496 |         if (isLinearised()) | 
| 497 |             return const_array_range(d->data() + d->first, d->last - d->first + 1); | 
| 498 |         else | 
| 499 |             return const_array_range(d->data() + d->first, d->capacity - d->first); | 
| 500 |     } | 
| 501 |  | 
| 502 |     array_range dataTwo() | 
| 503 |     { | 
| 504 |         d.detach(); | 
| 505 |         if (d->size == 0 || isLinearised()) | 
| 506 |             return array_range(nullptr, 0); | 
| 507 |         return array_range(d->data(), d->last + 1); | 
| 508 |     } | 
| 509 |     const_array_range dataTwo() const { return constDataTwo(); } | 
| 510 |     const_array_range constDataTwo() const | 
| 511 |     { | 
| 512 |         if (d->size == 0 || isLinearised()) | 
| 513 |             return const_array_range(nullptr, 0); | 
| 514 |         return const_array_range(d->data(), d->last + 1); | 
| 515 |     } | 
| 516 |  | 
| 517 |     bool endsWith(const T &val) const { return !isEmpty() && last() == val; } | 
| 518 |     QCircularBuffer<T> &fill(const T &val, int number = -1); | 
| 519 |     T &first() { Q_ASSERT(!isEmpty()); d.detach(); return d->data()[ d->first ]; } | 
| 520 |     const T &first() const { Q_ASSERT(!isEmpty()); return d->data()[ d->first ]; } | 
| 521 |     int freeSize() const { return sizeAvailable(); } | 
| 522 |  | 
| 523 |     static QCircularBuffer<T> fromList(const QList<T> &list) | 
| 524 |     { return QCircularBuffer(list.begin(), list.end()); } | 
| 525 |     static QCircularBuffer<T> fromVector(const QVector<T> &vector) | 
| 526 |     { return QCircularBuffer(vector.begin(), vector.end()); } | 
| 527 |  | 
| 528 |     int indexOf(const T &val, int from = 0) const; | 
| 529 |     void insert(int i, const T &val) { insert(i, 1, val); } | 
| 530 |     void insert(int i, int number, const T &val); | 
| 531 |     bool isEmpty() const { return d->size == 0; } | 
| 532 |     bool isFull() const { return d->size == d->capacity; } | 
| 533 |     bool isLinearised() const { return (d->last >= d->first); } | 
| 534 |     T &last() { Q_ASSERT(!isEmpty()); return d->data()[ d->last ]; } | 
| 535 |     const T &last() const { Q_ASSERT(!isEmpty()); return d->data()[ d->last ]; } | 
| 536 |     int lastIndexOf(const T &val, int from = -1) const; | 
| 537 |     void linearise() | 
| 538 |     { | 
| 539 |         if (!isLinearised()) { | 
| 540 |             QCircularBuffer linearized(this->cbegin(), this->cend()); | 
| 541 |             swap(other&: linearized); | 
| 542 |         } | 
| 543 |     } | 
| 544 |  | 
| 545 |     void prepend(const T &val); | 
| 546 |     void remove(int i) { remove(i, 1); } | 
| 547 |     void remove(int i, int number); | 
| 548 |  | 
| 549 |     void replace(int i, const T &val) | 
| 550 |     { | 
| 551 |         Q_ASSERT_X(i >= 0 && i < d->size, "QCircularBuffer<T>::replace" , "index out of range" ); | 
| 552 |         const T copy(val); | 
| 553 |         (*this)[ i ] = copy; | 
| 554 |     } | 
| 555 |  | 
| 556 |     void reserve(int amount) { setCapacity(amount); } | 
| 557 |     void resize(int newSize); | 
| 558 |     void setCapacity(int amount); | 
| 559 |     int size() const { return d->size; } | 
| 560 |     Q_DECL_CONSTEXPR int max_size() const { return std::numeric_limits<size_type>::max(); } | 
| 561 |     int sizeAvailable() const { return d->capacity - d->size; } | 
| 562 |     void squeeze() { setCapacity(size()); } | 
| 563 |     bool startsWith(const T &val) const { return !isEmpty() && first() == val; } | 
| 564 |  | 
| 565 |     QList<T> toList() const; | 
| 566 |     QVector<T> toVector() const; | 
| 567 |  | 
| 568 |     T value(int i) const | 
| 569 |     { | 
| 570 |         if (i < 0 || i >= d->size) | 
| 571 |             return T(); | 
| 572 |         return at(i); | 
| 573 |     } | 
| 574 |  | 
| 575 |     T value(int i, const T &defaultValue) const | 
| 576 |     { | 
| 577 |         if (i < 0 || i >= d->size) | 
| 578 |             return defaultValue; | 
| 579 |         return at(i); | 
| 580 |     } | 
| 581 |  | 
| 582 |     QCircularBuffer<T> &operator+=(const T &other) { append(val: other); return *this; } | 
| 583 |     QCircularBuffer<T> &operator+=(const QCircularBuffer<T> &other); | 
| 584 |     QCircularBuffer<T> &operator+=(const QVector<T> &other); | 
| 585 |     QCircularBuffer<T> &operator+=(const QList<T> &other); | 
| 586 |  | 
| 587 |     QCircularBuffer<T> &operator<<(const T &other) { append(val: other); return *this; } | 
| 588 |     QCircularBuffer<T> &operator<<(const QCircularBuffer<T> &other) { *this += other; return *this; } | 
| 589 |     QCircularBuffer<T> &operator<<(const QVector<T> &other) { *this += other; return *this; } | 
| 590 |     QCircularBuffer<T> &operator<<(const QList<T> &other) { *this += other; return *this; } | 
| 591 |  | 
| 592 |     inline bool isSharedWith(const QCircularBuffer &other) const { return d == other.d; } | 
| 593 |  | 
| 594 | private: | 
| 595 |     QExplicitlySharedDataPointer<Data> d; | 
| 596 | }; | 
| 597 |  | 
| 598 | template <typename T> | 
| 599 | QCircularBuffer<T> operator+(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs); | 
| 600 |  | 
| 601 | template <typename T> | 
| 602 | inline bool operator==(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 603 | { return lhs.isSharedWith(rhs) || (lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin())); } | 
| 604 |  | 
| 605 | template <typename T> | 
| 606 | inline bool operator!=(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 607 | { return !operator==(lhs, rhs); } | 
| 608 |  | 
| 609 | template <typename T> | 
| 610 | inline void swap(QCircularBuffer<T> &lhs, QCircularBuffer<T> &rhs) | 
| 611 | { lhs.swap(rhs); } | 
| 612 |  | 
| 613 | template <typename T> | 
| 614 | inline bool operator< (const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 615 | { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } | 
| 616 |  | 
| 617 | template <typename T> | 
| 618 | inline bool operator> (const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 619 | { return operator<(rhs, lhs); } | 
| 620 |  | 
| 621 | template <typename T> | 
| 622 | inline bool operator>=(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 623 | { return !operator<(lhs, rhs); } | 
| 624 |  | 
| 625 | template <typename T> | 
| 626 | inline bool operator<=(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 627 | { return !operator>(lhs, rhs); } | 
| 628 |  | 
| 629 | // out-of-line function implementations: | 
| 630 |  | 
| 631 | #ifndef Q_QDOC | 
| 632 |  | 
| 633 | template <typename T> | 
| 634 | QCircularBuffer<T>::QCircularBuffer(int amount) | 
| 635 |     : d(new Data()) | 
| 636 | { | 
| 637 |     // Allocate some raw memory | 
| 638 |     d->setData(d->allocate(amount)); | 
| 639 |     d->capacity = amount; | 
| 640 |  | 
| 641 |     // Initialize memory block to zero | 
| 642 |     memset(d->data(), 0, amount * sizeof(T)); | 
| 643 | } | 
| 644 |  | 
| 645 | template <typename T> | 
| 646 | QCircularBuffer<T>::QCircularBuffer(int amount, const T &val) | 
| 647 |     : d(new Data()) | 
| 648 | { | 
| 649 |     // Allocate some raw memory | 
| 650 |     d->setData(d->allocate(amount)); | 
| 651 |     d->capacity = amount; | 
| 652 |  | 
| 653 |     // Initialize the objects. In this case we always use the placement new operator | 
| 654 |     T *b = d->data(); | 
| 655 |     T *i = b + d->capacity; | 
| 656 |     while (i != b) | 
| 657 |         new (--i) T(val); | 
| 658 |     d->first = 0; | 
| 659 |     d->last = d->capacity - 1; | 
| 660 |     d->size = d->capacity; | 
| 661 | } | 
| 662 |  | 
| 663 | template <typename T> | 
| 664 | QCircularBuffer<T>::QCircularBuffer(int amount, int initialSize, const T &val) | 
| 665 |     : d(new Data()) | 
| 666 | { | 
| 667 |     Q_ASSERT_X(amount >= initialSize, "QCircularBuffer<T>::QCircularBuffer(int capacity, int size, const T &value)" , "size is greater than capacity" ); | 
| 668 |  | 
| 669 |     // Allocate some raw memory | 
| 670 |     d->setData(d->allocate(amount)); | 
| 671 |     d->capacity = amount; | 
| 672 |  | 
| 673 |     // Initialize the objects that need to be set to the specified value. | 
| 674 |     // In this case we always use the placement new operator | 
| 675 |     T *b = d->data(); | 
| 676 |     T *i = b + initialSize; | 
| 677 |     while (i != b) | 
| 678 |         new (--i) T(val); | 
| 679 |  | 
| 680 |     // Initialize the remaining memory to zero | 
| 681 |     memset(d->data() + initialSize, 0, (amount - initialSize) * sizeof(T)); | 
| 682 |  | 
| 683 |     d->first = 0; | 
| 684 |     d->last = initialSize - 1; | 
| 685 |     d->size = initialSize; | 
| 686 | } | 
| 687 |  | 
| 688 | template <typename T> | 
| 689 | void QCircularBuffer<T>::append(const T &val) | 
| 690 | { | 
| 691 |     // If we have no capacity we do nothing | 
| 692 |     if (!d->capacity) | 
| 693 |         return; | 
| 694 |     d.detach(); | 
| 695 |     if (d->size == d->capacity) { | 
| 696 |         // Buffer is full. Overwrite earliest item and rotate | 
| 697 |         d->data()[ d->first ] = val; | 
| 698 |         d->first = d->wraparound(++d->first); | 
| 699 |         d->last = d->wraparound(++d->last); | 
| 700 |     } else if (d->size != 0) { | 
| 701 |         // Buffer is partially full. Append data to end of array using appropriate method | 
| 702 |         int index = d->wraparound(d->first + d->size); | 
| 703 |         if (QTypeInfo<T>::isComplex) | 
| 704 |             new (d->data() + index) T(val); | 
| 705 |         else | 
| 706 |             d->data()[ index ] = val; | 
| 707 |         ++d->size; | 
| 708 |         ++d->last; | 
| 709 |     } else { | 
| 710 |         // Buffer is empty. Append data to end of array using appropriate method | 
| 711 |         d->size = 1; | 
| 712 |         d->first = d->last = 0; | 
| 713 |         if (QTypeInfo<T>::isComplex) | 
| 714 |             new (d->data() + d->first) T(val); | 
| 715 |         else | 
| 716 |             d->data()[ d->first ] = val; | 
| 717 |     } | 
| 718 | } | 
| 719 |  | 
| 720 | template <typename T> | 
| 721 | bool QCircularBuffer<T>::contains(const T &val) const | 
| 722 | { | 
| 723 |     if (isLinearised()) { | 
| 724 |         T *b = d->data() + d->first; | 
| 725 |         T *i = b + d->size; | 
| 726 |         while (i != b) | 
| 727 |             if (*--i == val) | 
| 728 |                 return true; | 
| 729 |         return false; | 
| 730 |     } else { | 
| 731 |         // Check the array from m_first to the end | 
| 732 |         T *b = d->data() + d->first; | 
| 733 |         T *i = d->data() + d->capacity; | 
| 734 |         while (i != b) | 
| 735 |             if (*--i == val) | 
| 736 |                 return true; | 
| 737 |  | 
| 738 |         // Check array from 0 to m_end | 
| 739 |         b = d->data(); | 
| 740 |         i = d->data() + d->last + 1; | 
| 741 |         while (i != b) | 
| 742 |             if (*--i == val) | 
| 743 |                 return true; | 
| 744 |  | 
| 745 |         return false; | 
| 746 |     } | 
| 747 | } | 
| 748 |  | 
| 749 | template <typename T> | 
| 750 | int QCircularBuffer<T>::count(const T &val) const | 
| 751 | { | 
| 752 |     int c = 0; | 
| 753 |     if (isLinearised()) { | 
| 754 |         T *b = d->data() + d->first; | 
| 755 |         T *i = b + d->size; | 
| 756 |         while (i != b) | 
| 757 |             if (*--i == val) | 
| 758 |                 ++c; | 
| 759 |     } else { | 
| 760 |         // Check the array from m_first to the end | 
| 761 |         T *b = d->data() + d->first; | 
| 762 |         T *i = d->data() + d->capacity; | 
| 763 |         while (i != b) | 
| 764 |             if (*--i == val) | 
| 765 |                 ++c; | 
| 766 |  | 
| 767 |         // Check array from 0 to m_end | 
| 768 |         b = d->data(); | 
| 769 |         i = d->data() + d->last + 1; | 
| 770 |         while (i != b) | 
| 771 |             if (*--i == val) | 
| 772 |                 ++c; | 
| 773 |     } | 
| 774 |     return c; | 
| 775 | } | 
| 776 |  | 
| 777 | template <typename T> | 
| 778 | QCircularBuffer<T> &QCircularBuffer<T>::fill(const T &val, int number) | 
| 779 | { | 
| 780 |     Q_ASSERT_X(d->capacity >= number, "QCircularBuffer<T>::fill" , "size is greater than capacity" ); | 
| 781 |     const T copy(val); | 
| 782 |     d.detach(); | 
| 783 |     int oldSize = d->size; | 
| 784 |     d->size = (number < 0 ? d->size : number); | 
| 785 |     d->first = (number == 0 ? -1 : 0); | 
| 786 |     d->last = d->size - 1; | 
| 787 |  | 
| 788 |     // Copy item into array size times | 
| 789 |     if (d->size) { | 
| 790 |         T *b = d->data(); | 
| 791 |         T *i = d->data() + d->size; | 
| 792 |         while (i != b) | 
| 793 |             *--i = copy; | 
| 794 |     } | 
| 795 |  | 
| 796 |     if (d->size < oldSize) { | 
| 797 |         // Cleanup old items beyond end of new array | 
| 798 |         T *b = d->data() + d->size; | 
| 799 |         T *i = d->data() + oldSize; | 
| 800 |         while (i-- != b) { | 
| 801 |             i->~T(); | 
| 802 |             //TODO: Optimize to a single memset call | 
| 803 |             memset(i, 0, sizeof(T)); | 
| 804 |         } | 
| 805 |     } | 
| 806 |  | 
| 807 |     return *this; | 
| 808 | } | 
| 809 |  | 
| 810 | template <typename T> | 
| 811 | int QCircularBuffer<T>::indexOf(const T &val, int from) const | 
| 812 | { | 
| 813 |     Q_ASSERT_X(from < d->size, "QCircularBuffer<T>::indexOf" , "from is greater than last valid index" ); | 
| 814 |     if (from < 0) | 
| 815 |         from = qMax(from + d->size, 0); | 
| 816 |     else if (from >= d->size) | 
| 817 |         from = d->size - 1; | 
| 818 |     for (int i = from; i < d->size; ++i) | 
| 819 |         if (at(i) == val) | 
| 820 |             return i; | 
| 821 |     return -1; | 
| 822 | } | 
| 823 |  | 
| 824 | template <typename T> | 
| 825 | void QCircularBuffer<T>::insert(int i, int number, const T &val) | 
| 826 | { | 
| 827 |     Q_ASSERT_X(i >= 0 && i <= d->size, "QCircularBuffer<T>::insert" , "index out of range" ); | 
| 828 |     d.detach(); | 
| 829 |     int freeCapacity = d->capacity - d->size; | 
| 830 |  | 
| 831 |     // Calculate number of elements that will actually be inserted. This | 
| 832 |     // depends upon where the insertion has been requested and any spare | 
| 833 |     // capacity left in the buffer. This is because elements at higher | 
| 834 |     // indices will be pushed to the right and will potentially wrap around | 
| 835 |     // to overwrite earlier elements. | 
| 836 |     int numToInsert = qMin(a: number, b: i + freeCapacity); | 
| 837 |  | 
| 838 |     // Calculate the number of elements at the beginning of the buffer that | 
| 839 |     // will be overwritten | 
| 840 |     int numToOverwrite = qMin(a: i, b: qMax(a: 0, b: number - freeCapacity)); | 
| 841 |  | 
| 842 |     // Decide which way to shift to minimize the amount of copying required. | 
| 843 |     if (i < d->size / 2) { | 
| 844 |         // Inserting in lower half of buffer so we shift earlier items down | 
| 845 |  | 
| 846 |         // Shift data at the bottom end down. This may only be a subset if some | 
| 847 |         // of the early data is to be overwritten. | 
| 848 |         if (QTypeInfo<T>::isStatic) { | 
| 849 |             int b = d->first + numToOverwrite; | 
| 850 |             int e = d->first + i - 1; | 
| 851 |             for (int j = b; j <= e; ++j) { | 
| 852 |                 int srcIndex = j % d->capacity; | 
| 853 |                 int dstIndex = (j - numToInsert + d->capacity) % d->capacity; | 
| 854 |                 T *src = d->data() + srcIndex; | 
| 855 |                 T *dst = d->data() + dstIndex; | 
| 856 |  | 
| 857 |                 new (dst) T(*src); | 
| 858 |             } | 
| 859 |         } else { | 
| 860 |             // We have a movable type so a simple memcopy (or maybe two or | 
| 861 |             // three) will suffice to shift the data at the bottom end | 
| 862 |             int numToMove = i - numToOverwrite; | 
| 863 |             if (numToMove > 0) { | 
| 864 |                 int srcBegin = (d->first + numToOverwrite) % d->capacity; | 
| 865 |                 int srcEnd = (d->first + i - 1) % d->capacity; | 
| 866 |                 int dstBegin = (srcBegin - numToInsert + d->capacity) % d->capacity; | 
| 867 |                 int dstEnd = (srcEnd - numToInsert + d->capacity) % d->capacity; | 
| 868 |  | 
| 869 |                 // Do we have any wrap-around problems to deal with? | 
| 870 |                 bool srcRegionWraps = (srcEnd < srcBegin); | 
| 871 |                 bool dstRegionWraps = (dstEnd < dstBegin); | 
| 872 |                 if (!srcRegionWraps && dstRegionWraps) { | 
| 873 |                     // Destination region wraps so do the move in two steps | 
| 874 |                     int wrapCount = abs(x: srcBegin - numToInsert); | 
| 875 |                     memmove(d->data() + d->capacity - wrapCount, d->data() + srcBegin, wrapCount * sizeof(T)); | 
| 876 |                     memmove(d->data(), d->data() + srcBegin + wrapCount, (numToMove - wrapCount) * sizeof(T)); | 
| 877 |                 } else if (srcRegionWraps && !dstRegionWraps) { | 
| 878 |                     // Source region wraps so do the move in two steps | 
| 879 |                     int wrapCount = d->capacity - srcBegin; | 
| 880 |                     memmove(d->data() + dstBegin, d->data() + d->capacity - wrapCount, wrapCount * sizeof(T)); | 
| 881 |                     memmove(d->data() + dstBegin + numToInsert, d->data(), (numToMove - wrapCount) * sizeof(T)); | 
| 882 |                 } else if (srcRegionWraps && dstRegionWraps) { | 
| 883 |                     // Source and destination regions wrap so we have to do this in three steps | 
| 884 |                     int srcWrapCount = d->capacity - srcBegin; | 
| 885 |                     memmove(d->data() + dstBegin, d->data() + d->capacity - srcWrapCount, srcWrapCount * sizeof(T)); | 
| 886 |                     memmove(d->data() + d->capacity - numToInsert, d->data(), numToInsert * sizeof(T)); | 
| 887 |                     memmove(d->data(), d->data() + numToInsert, (numToMove - srcWrapCount - numToInsert) * sizeof(T)); | 
| 888 |                 } else { | 
| 889 |                     // No wrap around - do a single memmove | 
| 890 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, numToMove * sizeof(T)); | 
| 891 |                 } | 
| 892 |             } | 
| 893 |         } | 
| 894 |  | 
| 895 |         // Insert the new items | 
| 896 |         int e = d->first + i; | 
| 897 |         int b = e - numToInsert; | 
| 898 |         for (int j = b; j < e; ++j) { | 
| 899 |             T *p = d->data() + ((j + d->capacity) % d->capacity); | 
| 900 |             new (p) T(val); | 
| 901 |         } | 
| 902 |  | 
| 903 |         // Adjust the first, last and size indices as needed. | 
| 904 |         // NB. The last index never changes in this regime. | 
| 905 |         d->size += qMin(a: number, b: freeCapacity); | 
| 906 |         d->first = (d->first - (numToInsert - numToOverwrite) + d->capacity) % d->capacity; | 
| 907 |     } else { | 
| 908 |         // Inserting in upper half of buffer so we shift later items up | 
| 909 |  | 
| 910 |         // Shift data at the top end up which may or may not overwrite some | 
| 911 |         // of the earliest data | 
| 912 |         if (QTypeInfo<T>::isStatic) { | 
| 913 |             int b = d->first + d->size - 1; | 
| 914 |             int e = d->first + i; | 
| 915 |             for (int j = b; j >= e; j--) { | 
| 916 |                 int srcIndex = j % d->capacity; | 
| 917 |                 int dstIndex = (j + numToInsert) % d->capacity; | 
| 918 |                 T *src = d->data() + srcIndex; | 
| 919 |                 T *dst = d->data() + dstIndex; | 
| 920 |  | 
| 921 |                 new (dst) T(*src); | 
| 922 |             } | 
| 923 |         } else { | 
| 924 |             // We have a movable type so a simple memcopy (or maybe two or | 
| 925 |             // three) will suffice to shift the data at the top end | 
| 926 |             int numToMove = d->size - i; | 
| 927 |             if (numToMove > 0) { | 
| 928 |                 int srcBegin = (d->first + i) % d->capacity; | 
| 929 |                 int srcEnd = d->last; | 
| 930 |                 int dstBegin = (srcBegin + numToInsert) % d->capacity; | 
| 931 |                 int dstEnd = (srcEnd + numToInsert) % d->capacity; | 
| 932 |  | 
| 933 |                 // Do we have any wrap-around problems to deal with? | 
| 934 |                 bool srcRegionWraps = (srcEnd < srcBegin); | 
| 935 |                 bool dstRegionWraps = (dstEnd < dstBegin); | 
| 936 |                 if (!srcRegionWraps && dstRegionWraps) { | 
| 937 |                     // Destination region wraps so do the move in two steps | 
| 938 |                     int wrapCount = srcEnd + numToInsert - d->capacity + 1; | 
| 939 |                     memmove(d->data(), d->data() + srcEnd - wrapCount + 1, wrapCount * sizeof(T)); | 
| 940 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - wrapCount) * sizeof(T)); | 
| 941 |                 } else if (srcRegionWraps && !dstRegionWraps) { | 
| 942 |                     // Source region wraps so do the move in two steps | 
| 943 |                     int wrapCount = d->last + 1; | 
| 944 |                     memmove(d->data() + numToInsert, d->data(), wrapCount * sizeof(T)); | 
| 945 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - wrapCount) * sizeof(T)); | 
| 946 |                 } else if (srcRegionWraps && dstRegionWraps) { | 
| 947 |                     // Source and destination regions wrap so we have to do this in three steps | 
| 948 |                     int srcWrapCount = d->last + 1; | 
| 949 |                     memmove(d->data() + numToInsert, d->data(), srcWrapCount * sizeof(T)); | 
| 950 |                     memmove(d->data(), d->data() + d->capacity - numToInsert, numToInsert * sizeof(T)); | 
| 951 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - srcWrapCount - numToInsert) * sizeof(T)); | 
| 952 |                 } else { | 
| 953 |                     // No wrap around - do a single memmove | 
| 954 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, numToMove * sizeof(T)); | 
| 955 |                 } | 
| 956 |             } | 
| 957 |         } | 
| 958 |  | 
| 959 |         // Insert the new items | 
| 960 |         for (int j = d->first + i; j < d->first + i + numToInsert; ++j) { | 
| 961 |             T *p = d->data() + (j % d->capacity); | 
| 962 |             new (p) T(val); | 
| 963 |         } | 
| 964 |  | 
| 965 |         // Adjust the first, last and size indices as needed | 
| 966 |         d->size += qMin(a: number, b: freeCapacity); | 
| 967 |         d->first = (d->first + numToOverwrite) % d->capacity; | 
| 968 |         d->last = (d->last + numToInsert) % d->capacity; | 
| 969 |     } | 
| 970 | } | 
| 971 |  | 
| 972 | template <typename T> | 
| 973 | int QCircularBuffer<T>::lastIndexOf(const T &val, int from) const | 
| 974 | { | 
| 975 |     if (from < 0) | 
| 976 |         from = qMax(from + d->size, 0); | 
| 977 |     else if (from >= d->size) | 
| 978 |         from = d->size - 1; | 
| 979 |     for (int i = from; i >= 0; --i) | 
| 980 |         if (at(i) == val) | 
| 981 |             return i; | 
| 982 |     return -1; | 
| 983 | } | 
| 984 |  | 
| 985 | template <typename T> | 
| 986 | void QCircularBuffer<T>::prepend(const T &val) | 
| 987 | { | 
| 988 |     // If we have no capacity we do nothing | 
| 989 |     if (!d->capacity) | 
| 990 |         return; | 
| 991 |  | 
| 992 |     d.detach(); | 
| 993 |     if (d->size == d->capacity) { | 
| 994 |         // Buffer is full. Overwrite last item and rotate | 
| 995 |         d->data()[ d->last ] = val; | 
| 996 |         d->first = (--d->first + d->capacity) % d->capacity; | 
| 997 |         d->last = (--d->last + d->capacity) % d->capacity; | 
| 998 |     } else if (d->size != 0) { | 
| 999 |         // Buffer is partially full. Prepend data to start of array using appropriate method | 
| 1000 |         d->first = (--d->first + d->capacity) % d->capacity; | 
| 1001 |         ++d->size; | 
| 1002 |         if (QTypeInfo<T>::isComplex) | 
| 1003 |             new (d->data() + d->first) T(val); | 
| 1004 |         else | 
| 1005 |             d->data()[ d->first ] = val; | 
| 1006 |     } else { | 
| 1007 |         // Buffer is empty. Prepend data to start of array using appropriate method | 
| 1008 |         d->size = 1; | 
| 1009 |         d->first = d->last = d->capacity - 1; | 
| 1010 |         if (QTypeInfo<T>::isComplex) | 
| 1011 |             new (d->data() + d->first) T(val); | 
| 1012 |         else | 
| 1013 |             d->data()[ d->first ] = val; | 
| 1014 |     } | 
| 1015 | } | 
| 1016 |  | 
| 1017 | template <typename T> | 
| 1018 | void QCircularBuffer<T>::remove(int i, int number) | 
| 1019 | { | 
| 1020 |     Q_ASSERT_X(i >= 0 && number > 0 && i + number <= d->size, "QCircularBuffer<T>::remove" , "index out of range" ); | 
| 1021 |     d.detach(); | 
| 1022 |  | 
| 1023 |     // HACK (it actually makes sense, but requires some more thinking) | 
| 1024 |     if ( i == 0 && !QTypeInfo<T>::isComplex ) { | 
| 1025 |         d->first = d->wraparound( d->first + number ); | 
| 1026 |         d->size -= number; | 
| 1027 |         return; | 
| 1028 |     } | 
| 1029 |  | 
| 1030 |     // Calculate the number of items that need to be moved downward | 
| 1031 |     int numToMoveDown = d->size - number - i; | 
| 1032 |     int numToMoveUp = i; | 
| 1033 |  | 
| 1034 |     if (numToMoveDown < numToMoveUp) { | 
| 1035 |         // Move higher items down | 
| 1036 |         int numToMove = numToMoveDown; | 
| 1037 |  | 
| 1038 |         if (QTypeInfo<T>::isComplex) { | 
| 1039 |             // Copy items down from higher positions | 
| 1040 |             int b = d->first + i; | 
| 1041 |             int e = b + numToMove; | 
| 1042 |             for (int j = b; j < e ; ++j) { | 
| 1043 |                 T *src = d->data() + ((j + number) % d->capacity); | 
| 1044 |                 T *dst = d->data() + (j % d->capacity); | 
| 1045 |                 new (dst) T(*src); | 
| 1046 |             } | 
| 1047 |  | 
| 1048 |             // Clean up items at end of buffer | 
| 1049 |             for (int j = d->last; j > d->last - number; --j) { | 
| 1050 |                 T *p = d->data() + ((j + d->capacity) % d->capacity); | 
| 1051 |                 p->~T(); | 
| 1052 |                 //TODO: Optimize to a single memset call | 
| 1053 |                 memset(p, 0, sizeof(T)); | 
| 1054 |             } | 
| 1055 |         } else { | 
| 1056 |             if (isLinearised()) { | 
| 1057 |                 // With a linearised buffer we can do a simple move and removal of items | 
| 1058 |                 memmove(d->data() + d->last - numToMove - number + 1, d->data() + d->last - numToMove + 1, numToMove * sizeof(T)); | 
| 1059 |                 memset(d->data() + d->last - number + 1, 0, number * sizeof(T)); | 
| 1060 |             } else { | 
| 1061 |                 // With a non-linearised buffer we need to be careful of wrapping issues | 
| 1062 |                 int srcBegin = (d->last - numToMove + 1 + d->capacity) % d->capacity; | 
| 1063 |                 int srcEnd = d->last; | 
| 1064 |                 int dstBegin = (d->first + i) % d->capacity; | 
| 1065 |                 int dstEnd = (dstBegin + numToMove - 1) % d->capacity; | 
| 1066 |  | 
| 1067 |                 bool srcRegionWraps = (srcEnd < srcBegin); | 
| 1068 |                 bool dstRegionWraps = (dstEnd < dstBegin); | 
| 1069 |                 if (srcRegionWraps && !dstRegionWraps) { | 
| 1070 |                     // Source region wraps so do the move in two steps | 
| 1071 |                     int wrapCount = d->capacity - srcBegin; | 
| 1072 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, wrapCount * sizeof(T)); | 
| 1073 |                     memmove(d->data() + dstBegin + wrapCount, d->data(), (numToMove - wrapCount) * sizeof(T)); | 
| 1074 |                 } else if (!srcRegionWraps && dstRegionWraps) { | 
| 1075 |                     // Destination region wraps so do the move in two steps | 
| 1076 |                     int wrapCount = number - srcBegin; | 
| 1077 |                     memmove(d->data() + d->capacity - wrapCount, d->data() + srcBegin, wrapCount * sizeof(T)); | 
| 1078 |                     memmove(d->data(), d->data() + srcBegin + wrapCount, (numToMove - wrapCount) * sizeof(T)); | 
| 1079 |                 } else if (srcRegionWraps && dstRegionWraps) { | 
| 1080 |                     // Source and destination regions wrap so we have to do this in three steps | 
| 1081 |                     int srcWrapCount = d->capacity - srcBegin; | 
| 1082 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, srcWrapCount * sizeof(T)); | 
| 1083 |                     memmove(d->data() + dstBegin + srcWrapCount, d->data(), number * sizeof(T)); | 
| 1084 |                     memmove(d->data(), d->data() + number, (numToMove - srcWrapCount - number) * sizeof(T)); | 
| 1085 |                 } else { | 
| 1086 |                     // No wrap around, so we can do this in one hit | 
| 1087 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, numToMove * sizeof(T)); | 
| 1088 |                 } | 
| 1089 |  | 
| 1090 |                 // We potentially have a disjoint region that needs zeroing | 
| 1091 |                 int zeroStart = (d->last - number + d->capacity + 1) % d->capacity; | 
| 1092 |                 int zeroEnd = d->last; | 
| 1093 |                 if (zeroEnd < zeroStart) { | 
| 1094 |                     // Region to be zeroed wraps. Do it in two steps. | 
| 1095 |                     memset(d->data(), 0, (d->last + 1) * sizeof(T)); | 
| 1096 |                     memset(d->data() + zeroStart, 0, (number - d->last - 1) * sizeof(T)); | 
| 1097 |                 } else { | 
| 1098 |                     // Region to be zeroed is contiguous | 
| 1099 |                     memset(d->data() + zeroStart, 0, number * sizeof(T)); | 
| 1100 |                 } | 
| 1101 |             } | 
| 1102 |         } | 
| 1103 |  | 
| 1104 |         // Adjust the indices | 
| 1105 |         d->size -= number; | 
| 1106 |         d->last = (d->last - number + d->capacity) % d->capacity; | 
| 1107 |     } else { | 
| 1108 |         // Move lower items up | 
| 1109 |         int numToMove = numToMoveUp; | 
| 1110 |  | 
| 1111 |         if (QTypeInfo<T>::isComplex) { | 
| 1112 |             // Copy items up from lower positions | 
| 1113 |             int b = d->first + i - 1; | 
| 1114 |             int e = b - numToMove; | 
| 1115 |             for (int j = b; j > e ; --j) { | 
| 1116 |                 T *src = d->data() + ((j + d->capacity) % d->capacity); | 
| 1117 |                 T *dst = d->data() + ((j + d->capacity + number) % d->capacity); | 
| 1118 |                 new (dst) T(*src); | 
| 1119 |             } | 
| 1120 |  | 
| 1121 |             // Clean up items at start of buffer | 
| 1122 |             for (int j = d->first; j < d->first + number; ++j) { | 
| 1123 |                 T *p = d->data() + (j % d->capacity); | 
| 1124 |                 p->~T(); | 
| 1125 |                 //TODO: Optimize to a single memset call | 
| 1126 |                 memset(p, 0, sizeof(T)); | 
| 1127 |             } | 
| 1128 |         } else { | 
| 1129 |             if (isLinearised()) { | 
| 1130 |                 // With a linearised buffer we can do a simple move and removal of items | 
| 1131 |                 memmove(d->data() + d->first + number, d->data() + d->first, numToMove * sizeof(T)); | 
| 1132 |                 memset(d->data() + d->first, 0, number * sizeof(T)); | 
| 1133 |             } else { | 
| 1134 |                 // With a non-linearised buffer we need to be careful of wrapping issues | 
| 1135 |                 int srcBegin = d->first; | 
| 1136 |                 int srcEnd = (srcBegin + numToMove - 1) % d->capacity; | 
| 1137 |                 int dstBegin = (srcBegin + number) % d->capacity; | 
| 1138 |                 int dstEnd = (dstBegin + numToMove - 1) % d->capacity; | 
| 1139 |  | 
| 1140 |                 bool srcRegionWraps = (srcEnd < srcBegin); | 
| 1141 |                 bool dstRegionWraps = (dstEnd < dstBegin); | 
| 1142 |                 if (srcRegionWraps && !dstRegionWraps) { | 
| 1143 |                     // Source region wraps so do the move in two steps | 
| 1144 |                     int wrapCount = srcEnd + 1; | 
| 1145 |                     memmove(d->data() + dstEnd - wrapCount + 1, d->data(), wrapCount * sizeof(T)); | 
| 1146 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - wrapCount) * sizeof(T)); | 
| 1147 |                 } else if (!srcRegionWraps && dstRegionWraps) { | 
| 1148 |                     // Destination region wraps so do the move in two steps | 
| 1149 |                     int wrapCount = dstEnd + 1; | 
| 1150 |                     memmove(d->data(), d->data() + srcEnd - wrapCount + 1, wrapCount * sizeof(T)); | 
| 1151 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - wrapCount) * sizeof(T)); | 
| 1152 |                 } else if (srcRegionWraps && dstRegionWraps) { | 
| 1153 |                     // Source and destination regions wrap so we have to do this in three steps | 
| 1154 |                     int srcWrapCount = srcEnd + 1; | 
| 1155 |                     memmove(d->data() + dstEnd - srcWrapCount + 1, d->data(), srcWrapCount * sizeof(T)); | 
| 1156 |                     memmove(d->data(), d->data() + d->capacity - number, number * sizeof(T)); | 
| 1157 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, (numToMove - srcWrapCount - number) * sizeof(T)); | 
| 1158 |                 } else { | 
| 1159 |                     // No wrap around, so we can do this in one hit | 
| 1160 |                     memmove(d->data() + dstBegin, d->data() + srcBegin, numToMove * sizeof(T)); | 
| 1161 |                 } | 
| 1162 |  | 
| 1163 |                 // We potentially have a disjoint region that needs zeroing | 
| 1164 |                 int zeroStart = d->first; | 
| 1165 |                 int zeroEnd = (zeroStart + number - 1) % d->capacity; | 
| 1166 |                 if (zeroEnd < zeroStart) { | 
| 1167 |                     // Region to be zeroed wraps. Do it in two steps. | 
| 1168 |                     memset(d->data() + zeroStart, 0, (d->capacity - d->first) * sizeof(T)); | 
| 1169 |                     memset(d->data(), 0, (number - d->capacity + d->first) * sizeof(T)); | 
| 1170 |                 } else { | 
| 1171 |                     // Region to be zeroed is contiguous | 
| 1172 |                     memset(d->data() + zeroStart, 0, number * sizeof(T)); | 
| 1173 |                 } | 
| 1174 |             } | 
| 1175 |         } | 
| 1176 |  | 
| 1177 |         // Adjust the indices | 
| 1178 |         d->size -= number; | 
| 1179 |         d->first = (d->first + number) % d->capacity; | 
| 1180 |     } | 
| 1181 | } | 
| 1182 |  | 
| 1183 | template <typename T> | 
| 1184 | void QCircularBuffer<T>::setCapacity(int amount) | 
| 1185 | { | 
| 1186 |     if (amount == d->capacity) | 
| 1187 |         return; | 
| 1188 |  | 
| 1189 |     d.detach(); | 
| 1190 |     // Allocate some new raw memory | 
| 1191 |     T *newData = d->allocate(amount); | 
| 1192 |  | 
| 1193 |     // How many items can we copy across? | 
| 1194 |     int newSize = qMin(d->size, amount); | 
| 1195 |  | 
| 1196 |     if (QTypeInfo<T>::isComplex) { | 
| 1197 |         // Copy across the elements from the original array | 
| 1198 |         for (int i = 0; i < newSize; ++i) { | 
| 1199 |             T *src = d->data() + ((d->first + i) % d->capacity); | 
| 1200 |             T *dst = newData + i; | 
| 1201 |             new (dst) T(*src); | 
| 1202 |         } | 
| 1203 |  | 
| 1204 |         // Destroy the original items. | 
| 1205 |         // The type is complex so we manually call the destructor for each item | 
| 1206 |         // since we used the placement new operator to instantiate them | 
| 1207 |         T *b = d->data(); | 
| 1208 |         T *i = b + d->capacity; | 
| 1209 |         while (i-- != b) | 
| 1210 |              i->~T(); | 
| 1211 |     } else { | 
| 1212 |         // Copy across the elements from the original array. The source region | 
| 1213 |         // potentially wraps so we may have to do this in one or two steps | 
| 1214 |         if (isLinearised()) { | 
| 1215 |             memmove(newData, d->data() + d->first, newSize * sizeof(T)); | 
| 1216 |         } else { | 
| 1217 |             int step1Size = qMin(newSize, d->capacity - d->first); | 
| 1218 |             memmove(newData, d->data() + d->first, step1Size * sizeof(T)); | 
| 1219 |             int step2Size = qMax(0, qMin(newSize - d->capacity + d->first, d->last + 1)); | 
| 1220 |             memmove(newData + step1Size, d->data(), step2Size * sizeof(T)); | 
| 1221 |         } | 
| 1222 |     } | 
| 1223 |  | 
| 1224 |     // Initialize any memory outside of the valid buffer (ie the unused items) | 
| 1225 |     memset(newData + newSize, 0, (amount - newSize) * sizeof(T)); | 
| 1226 |  | 
| 1227 |     // Release the raw memory for the old array | 
| 1228 |     d->deallocate(d->data()); | 
| 1229 |  | 
| 1230 |     // Assign the new memory to be our buffer data and fix indices | 
| 1231 |     d->setData(newData); | 
| 1232 |     d->capacity = amount; | 
| 1233 |     d->first = 0; | 
| 1234 |     d->size = newSize; | 
| 1235 |     d->last = d->size - 1; | 
| 1236 | } | 
| 1237 |  | 
| 1238 | template <typename T> | 
| 1239 | void QCircularBuffer<T>::resize(int newSize) | 
| 1240 | { | 
| 1241 |     Q_ASSERT_X(newSize >= 0 && newSize <= d->capacity, "QCircularBuffer<T>::resize" , "size out of range" ); | 
| 1242 |     d.detach(); | 
| 1243 |     if (newSize < d->size) { | 
| 1244 |         remove(newSize, d->size - newSize); | 
| 1245 |     } else if (newSize > d->size) { | 
| 1246 |         const T t = T(); | 
| 1247 |         insert(d->size, newSize - d->size, t); | 
| 1248 |     } | 
| 1249 | } | 
| 1250 |  | 
| 1251 | template <typename T> | 
| 1252 | QCircularBuffer<T> &QCircularBuffer<T>::operator+=(const QCircularBuffer<T> &other) | 
| 1253 | { | 
| 1254 |     d.detach(); | 
| 1255 |     // How many items do we need to copy? No point in ever copying across a number | 
| 1256 |     // greater than capacity | 
| 1257 |     int numToCopy = qMin(other.size(), d->capacity); | 
| 1258 |     int offset = other.size() - numToCopy; | 
| 1259 |     for (int i = 0; i < numToCopy; ++i) | 
| 1260 |         append(val: other.at(offset + i)); | 
| 1261 |     return *this; | 
| 1262 | } | 
| 1263 |  | 
| 1264 | template <typename T> | 
| 1265 | QCircularBuffer<T> &QCircularBuffer<T>::operator+=(const QVector<T> &other) | 
| 1266 | { | 
| 1267 |     d.detach(); | 
| 1268 |     // How many items do we need to copy? No point in ever copying across a number | 
| 1269 |     // greater than capacity | 
| 1270 |     int numToCopy = qMin(other.size(), d->capacity); | 
| 1271 |     int offset = other.size() - numToCopy; | 
| 1272 |     for (int i = 0; i < numToCopy; ++i) | 
| 1273 |         append(val: other.at(offset + i)); | 
| 1274 |     return *this; | 
| 1275 | } | 
| 1276 |  | 
| 1277 | template <typename T> | 
| 1278 | QCircularBuffer<T> &QCircularBuffer<T>::operator+=(const QList<T> &other) | 
| 1279 | { | 
| 1280 |     d.detach(); | 
| 1281 |     // How many items do we need to copy? No point in ever copying across a number | 
| 1282 |     // greater than capacity | 
| 1283 |     int numToCopy = qMin(other.size(), d->capacity); | 
| 1284 |     int offset = other.size() - numToCopy; | 
| 1285 |     for (int i = 0; i < numToCopy; ++i) | 
| 1286 |         append(val: other.at(offset + i)); | 
| 1287 |     return *this; | 
| 1288 | } | 
| 1289 |  | 
| 1290 | template <typename T> | 
| 1291 | QList<T> QCircularBuffer<T>::toList() const | 
| 1292 | { | 
| 1293 |     QList<T> list; | 
| 1294 |     list.reserve(size()); | 
| 1295 |     for (int i = 0; i < size(); ++i) | 
| 1296 |         list.append(at(i)); | 
| 1297 |     return list; | 
| 1298 | } | 
| 1299 |  | 
| 1300 | template <typename T> | 
| 1301 | QVector<T> QCircularBuffer<T>::toVector() const | 
| 1302 | { | 
| 1303 |     QVector<T> vector; | 
| 1304 |     vector.reserve(size()); | 
| 1305 |     for (int i = 0; i < size(); ++i) | 
| 1306 |         vector.append(at(i)); | 
| 1307 |     return vector; | 
| 1308 | } | 
| 1309 |  | 
| 1310 | template <typename T> | 
| 1311 | QCircularBuffer<T> operator+(const QCircularBuffer<T> &lhs, const QCircularBuffer<T> &rhs) | 
| 1312 | { | 
| 1313 |     QCircularBuffer<T> circ(lhs.size() + rhs.size()); | 
| 1314 |     for (int i = 0; i < lhs.size(); ++i) | 
| 1315 |         circ.append(lhs.at(i)); | 
| 1316 |     for (int i = 0; i < rhs.size(); ++i) | 
| 1317 |         circ.append(rhs.at(i)); | 
| 1318 |     return circ; | 
| 1319 | } | 
| 1320 |  | 
| 1321 | #endif // Q_QDOC | 
| 1322 |  | 
| 1323 | Q_DECLARE_SEQUENTIAL_ITERATOR(CircularBuffer) | 
| 1324 | Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(CircularBuffer) | 
| 1325 |  | 
| 1326 | } //Qt3D | 
| 1327 |  | 
| 1328 | QT_END_NAMESPACE | 
| 1329 |  | 
| 1330 | #endif // QT3DCORE_QCIRCULARBUFFER_H | 
| 1331 |  |