File indexing completed on 2024-11-24 04:52:54
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 #ifndef TROJITA_RINGBUFFER_H 0023 #define TROJITA_RINGBUFFER_H 0024 0025 #include <QVector> 0026 0027 namespace Common 0028 { 0029 0030 /** @short Circular buffer holding a number of items 0031 0032 This class holds a fixed number of items. Use the append() function to put stuff into it. When you want to retrieve them, 0033 obtain an iterator by calling begin(). The returned iterator will cease to be valid immediately after modifying the ring 0034 buffer. Iteration has to be performed by comparing the current value of an iterator for equivalence against the 0035 container's end(), and incrementing the iterator. Any other form is not supported. 0036 0037 Invalidated iterators will likely not get caught. 0038 */ 0039 template<typename T> 0040 class RingBuffer 0041 { 0042 public: 0043 /** @short Constat iterator fro visiting the items after each other, starting at the oldest one 0044 0045 The iterator itself is linear, ie. it won't wrap. It will however 0046 */ 0047 class const_iterator 0048 { 0049 const RingBuffer<T> *container_; 0050 int offset_; 0051 public: 0052 /** @short Dereference the iterator */ 0053 const T &operator*() const 0054 { 0055 // It has to point to a correct offset 0056 Q_ASSERT(offset_ >= 0 && offset_ < container_->buf_.size()); 0057 int pos = container_->wrapped_ ? 0058 // It got wrapped, so we have to get wrapped past the end, too, and start at the oldest one 0059 (container_->appendPos_ + offset_) % container_->buf_.size() : 0060 // It isn't full yet 0061 offset_; 0062 return container_->buf_[pos]; 0063 } 0064 0065 const T *operator->() const 0066 { 0067 return &operator*(); 0068 } 0069 0070 /** @short Increment the iterator */ 0071 const_iterator &operator++() 0072 { 0073 ++offset_; 0074 // Allow incrementing to the end, ie. one past the last item 0075 Q_ASSERT(offset_ <= container_->buf_.size()); 0076 return *this; 0077 } 0078 0079 /** @short Compare two iterators from the same container for equality */ 0080 bool operator==(const const_iterator &other) const 0081 { 0082 Q_ASSERT(container_ == other.container_); 0083 return offset_ == other.offset_; 0084 } 0085 0086 /** @short Compare two iterators from the same container for inqeuality */ 0087 bool operator!=(const const_iterator &other) const 0088 { 0089 return !(*this == other); 0090 } 0091 private: 0092 friend class RingBuffer<T>; 0093 const_iterator(const RingBuffer<T> *container, int offset): container_(container), offset_(offset) 0094 { 0095 } 0096 }; 0097 0098 /** @short Instantiate a ring buffer holding size elements */ 0099 RingBuffer(const int size): buf_(size), appendPos_(0), wrapped_(false), skipped_(0) 0100 { 0101 Q_ASSERT(size >= 1); 0102 } 0103 0104 /** @short Return an interator pointing to the oldest item in the container */ 0105 const_iterator begin() const 0106 { 0107 return const_iterator(this, 0); 0108 } 0109 0110 /** @short Return an interator pointing to one item past the recent addition */ 0111 const_iterator end() const 0112 { 0113 return const_iterator(this, wrapped_ ? buf_.size() : appendPos_); 0114 } 0115 0116 /** @short Append an item to the container. Oldest item could get overwritten. */ 0117 void append(const T &what) 0118 { 0119 if (appendPos_ == buf_.size()) { 0120 wrapped_ = true; 0121 appendPos_ = 0; 0122 } 0123 if (wrapped_) 0124 ++skipped_; 0125 buf_[appendPos_] = what; 0126 ++appendPos_; 0127 } 0128 0129 /** @short Remove all items from the container */ 0130 void clear() 0131 { 0132 buf_ = QVector<T>(buf_.size()); 0133 wrapped_ = false; 0134 appendPos_ = 0; 0135 skipped_ = 0; 0136 } 0137 0138 /** @short How many items were overwritten */ 0139 uint skippedCount() const 0140 { 0141 return skipped_; 0142 } 0143 0144 private: 0145 QVector<T> buf_; 0146 int appendPos_; 0147 bool wrapped_; 0148 uint skipped_; 0149 }; 0150 0151 } 0152 0153 #endif // TROJITA_RINGBUFFER_H