Akonadi

imapset.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "datastream_p_p.h"
8#include "imapset_p.h"
9
10#include <QSharedData>
11
12#include <limits>
13
14namespace Akonadi
15{
16class ImapIntervalPrivate : public QSharedData
17{
18public:
19 ImapInterval::Id begin = 0;
20 ImapInterval::Id end = 0;
21};
22
23class ImapSetPrivate : public QSharedData
24{
25public:
26 template<typename T>
27 void add(const T &values)
28 {
29 T vals = values;
30 std::sort(vals.begin(), vals.end());
31 for (int i = 0; i < vals.count(); ++i) {
32 const int begin = vals[i];
33 Q_ASSERT(begin >= 0);
34 if (i == vals.count() - 1) {
35 intervals << ImapInterval(begin, begin);
36 break;
37 }
38 do {
39 ++i;
40 Q_ASSERT(vals[i] >= 0);
41 if (vals[i] != (vals[i - 1] + 1)) {
42 --i;
43 break;
44 }
45 } while (i < vals.count() - 1);
46 intervals << ImapInterval(begin, vals[i]);
47 }
48 }
49
50 ImapInterval::List intervals;
51};
52
53ImapInterval::ImapInterval()
54 : d(new ImapIntervalPrivate)
55{
56}
57
58ImapInterval::ImapInterval(const ImapInterval &other)
59 : d(other.d)
60{
61}
62
63ImapInterval::ImapInterval(Id begin, Id end)
64 : d(new ImapIntervalPrivate)
65{
66 d->begin = begin;
67 d->end = end;
68}
69
70ImapInterval::~ImapInterval() = default;
71
72ImapInterval &ImapInterval::operator=(const ImapInterval &other)
73{
74 if (this != &other) {
75 d = other.d;
76 }
77
78 return *this;
79}
80
81bool ImapInterval::operator==(const ImapInterval &other) const
82{
83 return (d->begin == other.d->begin && d->end == other.d->end);
84}
85
86ImapInterval::Id ImapInterval::size() const
87{
88 if (!d->begin && !d->end) {
89 return 0;
90 }
91
92 return (d->end - d->begin + 1);
93}
94
95bool ImapInterval::hasDefinedBegin() const
96{
97 return (d->begin != 0);
98}
99
100ImapInterval::Id ImapInterval::begin() const
101{
102 return d->begin;
103}
104
105bool ImapInterval::hasDefinedEnd() const
106{
107 return (d->end != 0);
108}
109
110ImapInterval::Id ImapInterval::end() const
111{
112 if (hasDefinedEnd()) {
113 return d->end;
114 }
115
116 return std::numeric_limits<Id>::max();
117}
118
119void ImapInterval::setBegin(Id value)
120{
121 Q_ASSERT(value >= 0);
122 Q_ASSERT(value <= d->end || !hasDefinedEnd());
123 d->begin = value;
124}
125
126void ImapInterval::setEnd(Id value)
127{
128 Q_ASSERT(value >= 0);
129 Q_ASSERT(value >= d->begin || !hasDefinedBegin());
130 d->end = value;
131}
132
133QByteArray Akonadi::ImapInterval::toImapSequence() const
134{
135 if (size() == 0) {
136 return QByteArray();
137 }
138
139 if (size() == 1) {
140 return QByteArray::number(d->begin);
141 }
142
143 QByteArray rv = QByteArray::number(d->begin) + ':';
144
145 if (hasDefinedEnd()) {
146 rv += QByteArray::number(d->end);
147 } else {
148 rv += '*';
149 }
150
151 return rv;
152}
153
154ImapSet::ImapSet()
155 : d(new ImapSetPrivate)
156{
157}
158
159ImapSet::ImapSet(Id id)
160 : d(new ImapSetPrivate)
161{
162 add(QList<Id>() << id);
163}
164ImapSet::ImapSet(const QList<qint64> &ids)
165 : d(new ImapSetPrivate)
166{
167 add(ids);
168}
169
170ImapSet::ImapSet(const ImapInterval &interval)
171 : d(new ImapSetPrivate)
172{
173 add(interval);
174}
175
176ImapSet::ImapSet(const ImapSet &other)
177 : d(other.d)
178{
179}
180
181ImapSet::~ImapSet()
182{
183}
184
185ImapSet ImapSet::all()
186{
187 ImapSet set;
188 set.add(ImapInterval(1, 0));
189 return set;
190}
191
192ImapSet &ImapSet::operator=(const ImapSet &other)
193{
194 if (this != &other) {
195 d = other.d;
196 }
197
198 return *this;
199}
200
201bool ImapSet::operator==(const ImapSet &other) const
202{
203 return d->intervals == other.d->intervals;
204}
205
206void ImapSet::add(const QList<Id> &values)
207{
208 d->add(values);
209}
210
211void ImapSet::add(const QSet<Id> &values)
212{
213 QList<Id> v;
214 v.reserve(values.size());
215 for (QSet<Id>::ConstIterator iter = values.constBegin(); iter != values.constEnd(); ++iter) {
216 v.push_back(*iter);
217 }
218
219 add(v);
220}
221
222void ImapSet::add(const ImapInterval &interval)
223{
224 d->intervals << interval;
225}
226
227QByteArray ImapSet::toImapSequenceSet() const
228{
229 QByteArray rv;
230 for (auto iter = d->intervals.cbegin(), end = d->intervals.cend(); iter != end; ++iter) {
231 if (iter != d->intervals.cbegin()) {
232 rv += ',';
233 }
234 rv += iter->toImapSequence();
235 }
236
237 return rv;
238}
239
240ImapInterval::List ImapSet::intervals() const
241{
242 return d->intervals;
243}
244
245bool ImapSet::isEmpty() const
246{
247 return d->intervals.isEmpty() || (d->intervals.size() == 1 && d->intervals.at(0).size() == 0);
248}
249
250void ImapSet::optimize()
251{
252 // There's nothing to optimize if we have fewer than 2 intervals
253 if (d->intervals.size() < 2) {
254 return;
255 }
256
257 // Sort the intervals in ascending order by their beginning value
258 std::sort(d->intervals.begin(), d->intervals.end(), [](const ImapInterval &lhs, const ImapInterval &rhs) {
259 return lhs.begin() < rhs.begin();
260 });
261
262 auto it = d->intervals.begin();
263 while (it != d->intervals.end() && it != std::prev(d->intervals.end())) {
264 auto next = std::next(it);
265 // +1 so that we also merge neighbouring intervals, e.g. 1:2,3:4 -> 1:4
266 if (it->hasDefinedEnd() && it->end() + 1 >= next->begin()) {
267 next->setBegin(it->begin());
268 if (next->hasDefinedEnd() && it->end() > next->end()) {
269 next->setEnd(it->end());
270 }
271 it = d->intervals.erase(it);
272 } else if (!it->hasDefinedEnd()) {
273 // We can eat up all the remaining intervals
274 it = d->intervals.erase(next, d->intervals.end());
275 } else {
276 ++it;
277 }
278 }
279}
280
281Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapInterval &interval)
282{
283 return stream << interval.d->begin << interval.d->end;
284}
285
286Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::ImapInterval &interval)
287{
288 return stream >> interval.d->begin >> interval.d->end;
289}
290
291Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapSet &set)
292{
293 return stream << set.d->intervals;
294}
295
296Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::ImapSet &set)
297{
298 return stream >> set.d->intervals;
299}
300
301} // namespace Akonadi
302
303using namespace Akonadi;
304
305QDebug operator<<(QDebug d, const Akonadi::ImapInterval &interval)
306{
307 d << interval.toImapSequence();
308 return d;
309}
310
311QDebug operator<<(QDebug d, const Akonadi::ImapSet &set)
312{
313 d << set.toImapSequenceSet();
314 return d;
315}
Helper integration between Akonadi and Qt.
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QDebug operator<<(QDebug dbg, const DcrawInfoContainer &c)
KGuiItem add()
const QList< QKeySequence > & begin()
const QList< QKeySequence > & next()
const QList< QKeySequence > & end()
bool isEmpty() const const
QByteArray number(double n, char format, int precision)
void push_back(parameter_type value)
void reserve(qsizetype size)
ConstIterator
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:01:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.