KIMAP2

imapset.cpp
1/*
2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "imapset.h"
21
22#include <QtCore/QSharedData>
23
24using namespace KIMAP2;
25
26class ImapInterval::Private : public QSharedData
27{
28public:
29 Private() :
31 begin(0),
32 end(0)
33 {}
34
35 Private(const Private &other) :
36 QSharedData(other)
37 {
38 begin = other.begin;
39 end = other.end;
40 }
41
42 Id begin;
43 Id end;
44};
45
46class ImapSet::Private : public QSharedData
47{
48public:
49 Private() : QSharedData() {}
50 Private(const Private &other) :
51 QSharedData(other)
52 {
53 intervals = other.intervals;
54 }
55
56 ImapInterval::List intervals;
57};
58
60 d(new Private)
61{
62}
63
65 d(other.d)
66{
67}
68
70 d(new Private)
71{
72 d->begin = begin;
73 d->end = end;
74}
75
76ImapInterval::~ ImapInterval()
77{
78}
79
81{
82 if (this != &other) {
83 d = other.d;
84 }
85 return *this;
86}
87
89{
90 return (d->begin == other.d->begin && d->end == other.d->end);
91}
92
94{
95 if (!d->begin && !d->end) {
96 return 0;
97 }
98 if (d->begin && !d->end) {
99 return Q_INT64_C(0x7FFFFFFFFFFFFFFF) - d->begin + 1;
100 }
101 return d->end - d->begin + 1;
102}
103
105{
106 return d->begin != 0;
107}
108
110{
111 return d->begin;
112}
113
115{
116 return d->end != 0;
117}
118
120{
121 if (hasDefinedEnd()) {
122 return d->end;
123 }
124 return 0xFFFFFFFF; // should be INT_MAX, but where is that defined again?
125}
126
128{
129 Q_ASSERT(value >= 0);
130 Q_ASSERT(value <= d->end || !hasDefinedEnd());
131 d->begin = value;
132}
133
135{
136 Q_ASSERT(value >= 0);
137 Q_ASSERT(value >= d->begin || !hasDefinedBegin());
138 d->end = value;
139}
140
142{
143 if (size() == 0) {
144 return QByteArray();
145 }
146 if (size() == 1) {
147 return QByteArray::number(d->begin);
148 }
149 QByteArray rv;
150 rv += QByteArray::number(d->begin) + ':';
151 if (hasDefinedEnd()) {
152 rv += QByteArray::number(d->end);
153 } else {
154 rv += '*';
155 }
156 return rv;
157}
158
160{
161 QList<QByteArray> values = sequence.split(':');
162 if (values.isEmpty() || values.size() > 2) {
163 return ImapInterval();
164 }
165
166 bool ok = false;
167 Id begin = values[0].toLongLong(&ok);
168
169 if (!ok) {
170 return ImapInterval();
171 }
172
173 Id end;
174
175 if (values.size() == 1) {
176 end = begin;
177 } else if (values[1] == QByteArray("*")) {
178 end = 0;
179 } else {
180 ok = false;
181 end = values[1].toLongLong(&ok);
182 if (!ok) {
183 return ImapInterval();
184 }
185 }
186
187 return ImapInterval(begin, end);
188}
189
191 d(new Private)
192{
193}
194
195ImapSet::ImapSet(Id begin, Id end) :
196 d(new Private)
197{
198 add(ImapInterval(begin, end));
199}
200
202 d(new Private)
203{
204 add(QVector<Id>() << value);
205}
206
208 d(other.d)
209{
210}
211
215
217{
218 if (this != &other) {
219 d = other.d;
220 }
221 return *this;
222}
223
224bool ImapSet::operator ==(const ImapSet &other) const
225{
226 if (d->intervals.size() != other.d->intervals.size()) {
227 return false;
228 }
229
230 foreach (const ImapInterval &interval, d->intervals) {
231 if (!other.d->intervals.contains(interval)) {
232 return false;
233 }
234 }
235
236 return true;
237}
238
239void ImapSet::add(Id value)
240{
241 add(QVector<Id>() << value);
242}
243
244void ImapSet::add(const QVector<Id> &values)
245{
246 QVector<Id> vals = values;
247 std::sort(vals.begin(), vals.end());
248 for (auto i = 0; i < vals.count(); ++i) {
249 const auto begin = vals[i];
250 Q_ASSERT(begin >= 0);
251 if (i == vals.count() - 1) {
252 d->intervals << ImapInterval(begin, begin);
253 break;
254 }
255 do {
256 ++i;
257 Q_ASSERT(vals[i] >= 0);
258 if (vals[i] != (vals[i - 1] + 1)) {
259 --i;
260 break;
261 }
262 } while (i < vals.count() - 1);
263 d->intervals << ImapInterval(begin, vals[i]);
264 }
265}
266
267void ImapSet::add(const ImapInterval &interval)
268{
269 d->intervals << interval;
270}
271
273{
275 rv.reserve(d->intervals.count());
276 foreach (const ImapInterval &interval, d->intervals) {
277 rv << interval.toImapSequence();
278 }
279
280 QByteArray result;
281
282 if (!rv.isEmpty()) {
283 result = rv.first();
285 ++it;
286 for (; it != rv.constEnd(); ++it) {
287 result += ',' + (*it);
288 }
289 }
290
291 return result;
292}
293
295{
296 ImapSet result;
297
298 QList<QByteArray> intervals = sequence.split(',');
299
300 foreach (const QByteArray &interval, intervals) {
301 if (!interval.isEmpty()) {
302 result.add(ImapInterval::fromImapSequence(interval));
303 }
304 }
305
306 return result;
307}
308
310{
311 return d->intervals;
312}
313
315{
316 return d->intervals.isEmpty();
317}
318
320{
321 // There's nothing to optimize if we have fewer than 2 intervals
322 if (d->intervals.size() < 2) {
323 return;
324 }
325
326 // Sort the intervals in ascending order by their beginning value
327 std::sort(d->intervals.begin(), d->intervals.end(),
328 [](const ImapInterval &lhs, const ImapInterval &rhs) {
329 return lhs.begin() < rhs.begin();
330 });
331
332 auto it = d->intervals.begin();
333 while (it != d->intervals.end() && it != std::prev(d->intervals.end())) {
334 auto next = std::next(it);
335 // +1 so that we also merge neighbouring intervals, e.g. 1:2,3:4 -> 1:4
336 if (it->hasDefinedEnd() && it->end() + 1 >= next->begin()) {
337 next->setBegin(it->begin());
338 if (next->hasDefinedEnd() && it->end() > next->end()) {
339 next->setEnd(it->end());
340 }
341 it = d->intervals.erase(it);
342 } else if (!it->hasDefinedEnd()) {
343 // We can eat up all the remaining intervals
344 it = d->intervals.erase(next, d->intervals.end());
345 } else {
346 ++it;
347 }
348 }
349}
350
351QDebug &operator<<(QDebug &d, const ImapInterval &interval)
352{
353 d << interval.toImapSequence();
354 return d;
355}
356
357QDebug &operator<<(QDebug &d, const ImapSet &set)
358{
359 d << set.toImapSequenceSet();
360 return d;
361}
Represents a single interval in an ImapSet.
Definition imapset.h:39
bool hasDefinedBegin() const
Returns true if this interval has a defined begin.
Definition imapset.cpp:104
ImapInterval()
Constructs an interval that covers all positive numbers.
Definition imapset.cpp:59
ImapInterval & operator=(const ImapInterval &other)
Assignment operator.
Definition imapset.cpp:80
static ImapInterval fromImapSequence(const QByteArray &sequence)
Return the interval corresponding to the given IMAP-compatible QByteArray representation.
Definition imapset.cpp:159
Id end() const
Returns the end of this interval.
Definition imapset.cpp:119
Id begin() const
Returns the begin of this interval.
Definition imapset.cpp:109
void setEnd(Id value)
Sets the end of this interval.
Definition imapset.cpp:134
Id size() const
Returns the size of this interval.
Definition imapset.cpp:93
bool operator==(const ImapInterval &other) const
Comparison operator.
Definition imapset.cpp:88
bool hasDefinedEnd() const
Returns true if this intercal has been defined.
Definition imapset.cpp:114
void setBegin(Id value)
Sets the begin of the interval.
Definition imapset.cpp:127
qint64 Id
Describes the ids stored in the interval.
Definition imapset.h:44
QByteArray toImapSequence() const
Converts this set into an IMAP compatible sequence.
Definition imapset.cpp:141
Represents a set of natural numbers (1->∞) in a as compact as possible form.
Definition imapset.h:142
~ImapSet()
Destructor.
Definition imapset.cpp:212
bool isEmpty() const
Returns true if this set doesn't contains any values.
Definition imapset.cpp:314
ImapSet()
Constructs an empty set.
Definition imapset.cpp:190
qint64 Id
Describes the ids stored in the set.
Definition imapset.h:147
void optimize()
Optimizes the ImapSet by sorting and merging overlapping intervals.
Definition imapset.cpp:319
QByteArray toImapSequenceSet() const
Returns a IMAP-compatible QByteArray representation of this set.
Definition imapset.cpp:272
void add(Id value)
Adds a single positive integer numbers to the set.
Definition imapset.cpp:239
static ImapSet fromImapSequenceSet(const QByteArray &sequence)
Return the set corresponding to the given IMAP-compatible QByteArray representation.
Definition imapset.cpp:294
bool operator==(const ImapSet &other) const
Comparison operator.
Definition imapset.cpp:224
ImapInterval::List intervals() const
Returns the intervals this set consists of.
Definition imapset.cpp:309
ImapSet & operator=(const ImapSet &other)
Assignment operator.
Definition imapset.cpp:216
bool isEmpty() const const
QByteArray number(double n, char format, int precision)
QList< QByteArray > split(char sep) const const
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator end()
T & first()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:09:53 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.