KIMAP

imapset.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "imapset.h"
8 
9 #include <QSharedData>
10 
11 using namespace KIMAP;
12 
13 class ImapInterval::Private : public QSharedData
14 {
15 public:
16  Private()
17  : QSharedData()
18  , begin(0)
19  , end(0)
20  {
21  }
22 
23  Private(const Private &other)
24  : QSharedData(other)
25  , begin(other.begin)
26  , end(other.end)
27  {
28  }
29 
30  Id begin;
31  Id end;
32 };
33 
34 class ImapSet::Private : public QSharedData
35 {
36 public:
37  Private()
38  : QSharedData()
39  {
40  }
41  Private(const Private &other)
42  : QSharedData(other)
43  , intervals(other.intervals)
44  {
45  }
46 
48 };
49 
51  : d(new Private)
52 {
53 }
54 
56  : d(other.d)
57 {
58 }
59 
61  : d(new Private)
62 {
63  d->begin = begin;
64  d->end = end;
65 }
66 
68 {
69 }
70 
72 {
73  if (this != &other) {
74  d = other.d;
75  }
76  return *this;
77 }
78 
79 bool ImapInterval::operator==(const ImapInterval &other) const
80 {
81  return (d->begin == other.d->begin && d->end == other.d->end);
82 }
83 
85 {
86  if (!d->begin && !d->end) {
87  return 0;
88  }
89  if (d->begin && !d->end) {
90  return Q_INT64_C(0x7FFFFFFFFFFFFFFF) - d->begin + 1;
91  }
92  return d->end - d->begin + 1;
93 }
94 
96 {
97  return d->begin != 0;
98 }
99 
101 {
102  return d->begin;
103 }
104 
106 {
107  return d->end != 0;
108 }
109 
111 {
112  if (hasDefinedEnd()) {
113  return d->end;
114  }
115  return std::numeric_limits<qint64>::max();
116 }
117 
119 {
120  Q_ASSERT(value >= 0);
121  Q_ASSERT(value <= d->end || !hasDefinedEnd());
122  d->begin = value;
123 }
124 
126 {
127  Q_ASSERT(value >= 0);
128  Q_ASSERT(value >= d->begin || !hasDefinedBegin());
129  d->end = value;
130 }
131 
133 {
134  if (size() == 0) {
135  return QByteArray();
136  }
137  if (size() == 1) {
138  return QByteArray::number(d->begin);
139  }
140  QByteArray rv = QByteArray::number(d->begin) + ':';
141  if (hasDefinedEnd()) {
142  rv += QByteArray::number(d->end);
143  } else {
144  rv += '*';
145  }
146  return rv;
147 }
148 
150 {
151  QList<QByteArray> values = sequence.split(':');
152  if (values.isEmpty() || values.size() > 2) {
153  return ImapInterval();
154  }
155 
156  bool ok = false;
157  Id begin = values[0].toLongLong(&ok);
158 
159  if (!ok) {
160  return ImapInterval();
161  }
162 
163  Id end;
164 
165  if (values.size() == 1) {
166  end = begin;
167  } else if (values[1] == QByteArray("*")) {
168  end = 0;
169  } else {
170  ok = false;
171  end = values[1].toLongLong(&ok);
172  if (!ok) {
173  return ImapInterval();
174  }
175  }
176 
177  return ImapInterval(begin, end);
178 }
179 
181  : d(new Private)
182 {
183 }
184 
185 ImapSet::ImapSet(Id begin, Id end)
186  : d(new Private)
187 {
188  add(ImapInterval(begin, end));
189 }
190 
192  : d(new Private)
193 {
194  add(QList<Id>() << value);
195 }
196 
198  : d(other.d)
199 {
200 }
201 
203 {
204 }
205 
207 {
208  if (this != &other) {
209  d = other.d;
210  }
211  return *this;
212 }
213 
214 bool ImapSet::operator==(const ImapSet &other) const
215 {
216  if (d->intervals.size() != other.d->intervals.size()) {
217  return false;
218  }
219 
220  for (const ImapInterval &interval : std::as_const(d->intervals)) {
221  if (!other.d->intervals.contains(interval)) {
222  return false;
223  }
224  }
225 
226  return true;
227 }
228 
229 void ImapSet::add(Id value)
230 {
231  add(QList<Id>() << value);
232 }
233 
234 void ImapSet::add(const QList<Id> &values)
235 {
236  QList<Id> vals = values;
237  std::sort(vals.begin(), vals.end());
238  for (int i = 0; i < vals.count(); ++i) {
239  const Id begin = vals[i];
240  Q_ASSERT(begin >= 0);
241  if (i == vals.count() - 1) {
242  d->intervals << ImapInterval(begin, begin);
243  break;
244  }
245  do {
246  ++i;
247  Q_ASSERT(vals[i] >= 0);
248  if (vals[i] != (vals[i - 1] + 1)) {
249  --i;
250  break;
251  }
252  } while (i < vals.count() - 1);
253  d->intervals << ImapInterval(begin, vals[i]);
254  }
255 }
256 
257 void ImapSet::add(const ImapInterval &interval)
258 {
259  d->intervals << interval;
260 }
261 
263 {
265  rv.reserve(d->intervals.count());
266  for (const ImapInterval &interval : std::as_const(d->intervals)) {
267  rv << interval.toImapSequence();
268  }
269 
270  QByteArray result;
271 
272  if (!rv.isEmpty()) {
273  result = rv.first();
276  ++it;
277  for (; it != end; ++it) {
278  result += ',' + (*it);
279  }
280  }
281 
282  return result;
283 }
284 
286 {
287  ImapSet result;
288 
289  const QList<QByteArray> intervals = sequence.split(',');
290 
291  for (const QByteArray &interval : std::as_const(intervals)) {
292  if (!interval.isEmpty()) {
293  result.add(ImapInterval::fromImapSequence(interval));
294  }
295  }
296 
297  return result;
298 }
299 
301 {
302  return d->intervals;
303 }
304 
305 bool ImapSet::isEmpty() const
306 {
307  return d->intervals.isEmpty();
308 }
309 
311 {
312  // There's nothing to optimize if we have fewer than 2 intervals
313  if (d->intervals.size() < 2) {
314  return;
315  }
316 
317  // Sort the intervals in ascending order by their beginning value
318  std::sort(d->intervals.begin(), d->intervals.end(), [](const ImapInterval &lhs, const ImapInterval &rhs) {
319  return lhs.begin() < rhs.begin();
320  });
321 
322  auto it = d->intervals.begin();
323  while (it != d->intervals.end() && it != std::prev(d->intervals.end())) {
324  auto next = std::next(it);
325  // +1 so that we also merge neighbouring intervals, e.g. 1:2,3:4 -> 1:4
326  if (it->hasDefinedEnd() && it->end() + 1 >= next->begin()) {
327  next->setBegin(it->begin());
328  if (next->hasDefinedEnd() && it->end() > next->end()) {
329  next->setEnd(it->end());
330  }
331  it = d->intervals.erase(it);
332  } else if (!it->hasDefinedEnd()) {
333  // We can eat up all the remaining intervals
334  it = d->intervals.erase(next, d->intervals.end());
335  } else {
336  ++it;
337  }
338  }
339 }
340 
341 QDebug &operator<<(QDebug &d, const ImapInterval &interval)
342 {
343  d << interval.toImapSequence();
344  return d;
345 }
346 
347 QDebug &operator<<(QDebug &d, const ImapSet &set)
348 {
349  d << set.toImapSequenceSet();
350  return d;
351 }
T & first()
qint64 Id
Describes the ids stored in the interval.
Definition: imapset.h:29
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
bool hasDefinedBegin() const
Returns true if this interval has a defined begin.
Definition: imapset.cpp:95
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:285
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:206
QByteArray toImapSequence() const
Converts this set into an IMAP compatible sequence.
Definition: imapset.cpp:132
bool operator==(const ImapInterval &other) const
Comparison operator.
Definition: imapset.cpp:79
void reserve(int alloc)
Id begin() const
Returns the begin of this interval.
Definition: imapset.cpp:100
Represents a single interval in an ImapSet.
Definition: imapset.h:23
Represents a set of natural numbers (1->∞) in a as compact as possible form.
Definition: imapset.h:126
bool isEmpty() const const
ImapInterval::List intervals() const
Returns the intervals this set consists of.
Definition: imapset.cpp:300
Id size() const
Returns the size of this interval.
Definition: imapset.cpp:84
~ImapInterval()
Destructor.
Definition: imapset.cpp:67
QList::const_iterator constEnd() const const
QByteArray toImapSequenceSet() const
Returns a IMAP-compatible QByteArray representation of this set.
Definition: imapset.cpp:262
bool operator==(const ImapSet &other) const
Comparison operator.
Definition: imapset.cpp:214
Id end() const
Returns the end of this interval.
Definition: imapset.cpp:110
ImapInterval & operator=(const ImapInterval &other)
Assignment operator.
Definition: imapset.cpp:71
qint64 Id
Describes the ids stored in the set.
Definition: imapset.h:132
QList::iterator begin()
void setEnd(Id value)
Sets the end of this interval.
Definition: imapset.cpp:125
void optimize()
Optimizes the ImapSet by sorting and merging overlapping intervals.
Definition: imapset.cpp:310
~ImapSet()
Destructor.
Definition: imapset.cpp:202
static ImapInterval fromImapSequence(const QByteArray &sequence)
Return the interval corresponding to the given IMAP-compatible QByteArray representation.
Definition: imapset.cpp:149
void setBegin(Id value)
Sets the begin of the interval.
Definition: imapset.cpp:118
ImapSet()
Constructs an empty set.
Definition: imapset.cpp:180
QList::iterator end()
bool hasDefinedEnd() const
Returns true if this intercal has been defined.
Definition: imapset.cpp:105
ImapInterval()
Constructs an interval that covers all positive numbers.
Definition: imapset.cpp:50
bool isEmpty() const
Returns true if this set doesn't contains any values.
Definition: imapset.cpp:305
QVector< V > values(const QMultiHash< K, V > &c)
void add(Id value)
Adds a single positive integer numbers to the set.
Definition: imapset.cpp:229
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 3 2023 03:51:44 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.