KIMAP2

imapset.cpp
1 /*
2  Copyright (c) 2007 Volker Krause <[email protected]>
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 
24 using namespace KIMAP2;
25 
26 class ImapInterval::Private : public QSharedData
27 {
28 public:
29  Private() :
30  QSharedData(),
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 
46 class ImapSet::Private : public QSharedData
47 {
48 public:
49  Private() : QSharedData() {}
50  Private(const Private &other) :
51  QSharedData(other)
52  {
53  intervals = other.intervals;
54  }
55 
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 
76 ImapInterval::~ ImapInterval()
77 {
78 }
79 
81 {
82  if (this != &other) {
83  d = other.d;
84  }
85  return *this;
86 }
87 
88 bool ImapInterval::operator ==(const ImapInterval &other) const
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 
195 ImapSet::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 
207 ImapSet::ImapSet(const ImapSet &other) :
208  d(other.d)
209 {
210 }
211 
213 {
214 }
215 
217 {
218  if (this != &other) {
219  d = other.d;
220  }
221  return *this;
222 }
223 
224 bool 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 
239 void ImapSet::add(Id value)
240 {
241  add(QVector<Id>() << value);
242 }
243 
244 void 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 
267 void 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 
314 bool ImapSet::isEmpty() const
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 
351 QDebug &operator<<(QDebug &d, const ImapInterval &interval)
352 {
353  d << interval.toImapSequence();
354  return d;
355 }
356 
357 QDebug &operator<<(QDebug &d, const ImapSet &set)
358 {
359  d << set.toImapSequenceSet();
360  return d;
361 }
T & first()
ImapInterval::List intervals() const
Returns the intervals this set consists of.
Definition: imapset.cpp:309
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
bool hasDefinedEnd() const
Returns true if this intercal has been defined.
Definition: imapset.cpp:114
QVector::iterator begin()
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
QByteArray number(int n, int base)
QList< QByteArray > split(char sep) const const
QList::const_iterator constBegin() const const
ImapSet & operator=(const ImapSet &other)
Assignment operator.
Definition: imapset.cpp:216
qint64 Id
Describes the ids stored in the set.
Definition: imapset.h:147
ImapInterval()
Constructs an interval that covers all positive numbers.
Definition: imapset.cpp:59
void reserve(int alloc)
QByteArray toImapSequence() const
Converts this set into an IMAP compatible sequence.
Definition: imapset.cpp:141
QByteArray toImapSequenceSet() const
Returns a IMAP-compatible QByteArray representation of this set.
Definition: imapset.cpp:272
Represents a set of natural numbers (1->∞) in a as compact as possible form.
Definition: imapset.h:141
bool isEmpty() const const
~ImapSet()
Destructor.
Definition: imapset.cpp:212
Id size() const
Returns the size of this interval.
Definition: imapset.cpp:93
static ImapInterval fromImapSequence(const QByteArray &sequence)
Return the interval corresponding to the given IMAP-compatible QByteArray representation.
Definition: imapset.cpp:159
bool operator==(const ImapInterval &other) const
Comparison operator.
Definition: imapset.cpp:88
ImapSet()
Constructs an empty set.
Definition: imapset.cpp:190
bool operator==(const ImapSet &other) const
Comparison operator.
Definition: imapset.cpp:224
QVector::iterator end()
void add(Id value)
Adds a single positive integer numbers to the set.
Definition: imapset.cpp:239
qint64 Id
Describes the ids stored in the interval.
Definition: imapset.h:44
bool isEmpty() const const
QList::const_iterator constEnd() const const
ImapInterval & operator=(const ImapInterval &other)
Assignment operator.
Definition: imapset.cpp:80
bool isEmpty() const
Returns true if this set doesn't contains any values.
Definition: imapset.cpp:314
Represents a single interval in an ImapSet.
Definition: imapset.h:38
void setEnd(Id value)
Sets the end of this interval.
Definition: imapset.cpp:134
int count(const T &value) const const
static ImapSet fromImapSequenceSet(const QByteArray &sequence)
Return the set corresponding to the given IMAP-compatible QByteArray representation.
Definition: imapset.cpp:294
void optimize()
Optimizes the ImapSet by sorting and merging overlapping intervals.
Definition: imapset.cpp:319
bool hasDefinedBegin() const
Returns true if this interval has a defined begin.
Definition: imapset.cpp:104
QVector< V > values(const QMultiHash< K, V > &c)
void setBegin(Id value)
Sets the begin of the interval.
Definition: imapset.cpp:127
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 03:47:43 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.