File indexing completed on 2024-11-10 04:40:48
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "datastream_p_p.h" 0008 #include "imapset_p.h" 0009 0010 #include <QSharedData> 0011 0012 #include <limits> 0013 0014 namespace Akonadi 0015 { 0016 class ImapIntervalPrivate : public QSharedData 0017 { 0018 public: 0019 ImapInterval::Id begin = 0; 0020 ImapInterval::Id end = 0; 0021 }; 0022 0023 class ImapSetPrivate : public QSharedData 0024 { 0025 public: 0026 template<typename T> 0027 void add(const T &values) 0028 { 0029 T vals = values; 0030 std::sort(vals.begin(), vals.end()); 0031 for (int i = 0; i < vals.count(); ++i) { 0032 const int begin = vals[i]; 0033 Q_ASSERT(begin >= 0); 0034 if (i == vals.count() - 1) { 0035 intervals << ImapInterval(begin, begin); 0036 break; 0037 } 0038 do { 0039 ++i; 0040 Q_ASSERT(vals[i] >= 0); 0041 if (vals[i] != (vals[i - 1] + 1)) { 0042 --i; 0043 break; 0044 } 0045 } while (i < vals.count() - 1); 0046 intervals << ImapInterval(begin, vals[i]); 0047 } 0048 } 0049 0050 ImapInterval::List intervals; 0051 }; 0052 0053 ImapInterval::ImapInterval() 0054 : d(new ImapIntervalPrivate) 0055 { 0056 } 0057 0058 ImapInterval::ImapInterval(const ImapInterval &other) 0059 : d(other.d) 0060 { 0061 } 0062 0063 ImapInterval::ImapInterval(Id begin, Id end) 0064 : d(new ImapIntervalPrivate) 0065 { 0066 d->begin = begin; 0067 d->end = end; 0068 } 0069 0070 ImapInterval::~ImapInterval() = default; 0071 0072 ImapInterval &ImapInterval::operator=(const ImapInterval &other) 0073 { 0074 if (this != &other) { 0075 d = other.d; 0076 } 0077 0078 return *this; 0079 } 0080 0081 bool ImapInterval::operator==(const ImapInterval &other) const 0082 { 0083 return (d->begin == other.d->begin && d->end == other.d->end); 0084 } 0085 0086 ImapInterval::Id ImapInterval::size() const 0087 { 0088 if (!d->begin && !d->end) { 0089 return 0; 0090 } 0091 0092 return (d->end - d->begin + 1); 0093 } 0094 0095 bool ImapInterval::hasDefinedBegin() const 0096 { 0097 return (d->begin != 0); 0098 } 0099 0100 ImapInterval::Id ImapInterval::begin() const 0101 { 0102 return d->begin; 0103 } 0104 0105 bool ImapInterval::hasDefinedEnd() const 0106 { 0107 return (d->end != 0); 0108 } 0109 0110 ImapInterval::Id ImapInterval::end() const 0111 { 0112 if (hasDefinedEnd()) { 0113 return d->end; 0114 } 0115 0116 return std::numeric_limits<Id>::max(); 0117 } 0118 0119 void ImapInterval::setBegin(Id value) 0120 { 0121 Q_ASSERT(value >= 0); 0122 Q_ASSERT(value <= d->end || !hasDefinedEnd()); 0123 d->begin = value; 0124 } 0125 0126 void ImapInterval::setEnd(Id value) 0127 { 0128 Q_ASSERT(value >= 0); 0129 Q_ASSERT(value >= d->begin || !hasDefinedBegin()); 0130 d->end = value; 0131 } 0132 0133 QByteArray Akonadi::ImapInterval::toImapSequence() const 0134 { 0135 if (size() == 0) { 0136 return QByteArray(); 0137 } 0138 0139 if (size() == 1) { 0140 return QByteArray::number(d->begin); 0141 } 0142 0143 QByteArray rv = QByteArray::number(d->begin) + ':'; 0144 0145 if (hasDefinedEnd()) { 0146 rv += QByteArray::number(d->end); 0147 } else { 0148 rv += '*'; 0149 } 0150 0151 return rv; 0152 } 0153 0154 ImapSet::ImapSet() 0155 : d(new ImapSetPrivate) 0156 { 0157 } 0158 0159 ImapSet::ImapSet(Id id) 0160 : d(new ImapSetPrivate) 0161 { 0162 add(QList<Id>() << id); 0163 } 0164 ImapSet::ImapSet(const QList<qint64> &ids) 0165 : d(new ImapSetPrivate) 0166 { 0167 add(ids); 0168 } 0169 0170 ImapSet::ImapSet(const ImapInterval &interval) 0171 : d(new ImapSetPrivate) 0172 { 0173 add(interval); 0174 } 0175 0176 ImapSet::ImapSet(const ImapSet &other) 0177 : d(other.d) 0178 { 0179 } 0180 0181 ImapSet::~ImapSet() 0182 { 0183 } 0184 0185 ImapSet ImapSet::all() 0186 { 0187 ImapSet set; 0188 set.add(ImapInterval(1, 0)); 0189 return set; 0190 } 0191 0192 ImapSet &ImapSet::operator=(const ImapSet &other) 0193 { 0194 if (this != &other) { 0195 d = other.d; 0196 } 0197 0198 return *this; 0199 } 0200 0201 bool ImapSet::operator==(const ImapSet &other) const 0202 { 0203 return d->intervals == other.d->intervals; 0204 } 0205 0206 void ImapSet::add(const QList<Id> &values) 0207 { 0208 d->add(values); 0209 } 0210 0211 void ImapSet::add(const QSet<Id> &values) 0212 { 0213 QList<Id> v; 0214 v.reserve(values.size()); 0215 for (QSet<Id>::ConstIterator iter = values.constBegin(); iter != values.constEnd(); ++iter) { 0216 v.push_back(*iter); 0217 } 0218 0219 add(v); 0220 } 0221 0222 void ImapSet::add(const ImapInterval &interval) 0223 { 0224 d->intervals << interval; 0225 } 0226 0227 QByteArray ImapSet::toImapSequenceSet() const 0228 { 0229 QByteArray rv; 0230 for (auto iter = d->intervals.cbegin(), end = d->intervals.cend(); iter != end; ++iter) { 0231 if (iter != d->intervals.cbegin()) { 0232 rv += ','; 0233 } 0234 rv += iter->toImapSequence(); 0235 } 0236 0237 return rv; 0238 } 0239 0240 ImapInterval::List ImapSet::intervals() const 0241 { 0242 return d->intervals; 0243 } 0244 0245 bool ImapSet::isEmpty() const 0246 { 0247 return d->intervals.isEmpty() || (d->intervals.size() == 1 && d->intervals.at(0).size() == 0); 0248 } 0249 0250 void ImapSet::optimize() 0251 { 0252 // There's nothing to optimize if we have fewer than 2 intervals 0253 if (d->intervals.size() < 2) { 0254 return; 0255 } 0256 0257 // Sort the intervals in ascending order by their beginning value 0258 std::sort(d->intervals.begin(), d->intervals.end(), [](const ImapInterval &lhs, const ImapInterval &rhs) { 0259 return lhs.begin() < rhs.begin(); 0260 }); 0261 0262 auto it = d->intervals.begin(); 0263 while (it != d->intervals.end() && it != std::prev(d->intervals.end())) { 0264 auto next = std::next(it); 0265 // +1 so that we also merge neighbouring intervals, e.g. 1:2,3:4 -> 1:4 0266 if (it->hasDefinedEnd() && it->end() + 1 >= next->begin()) { 0267 next->setBegin(it->begin()); 0268 if (next->hasDefinedEnd() && it->end() > next->end()) { 0269 next->setEnd(it->end()); 0270 } 0271 it = d->intervals.erase(it); 0272 } else if (!it->hasDefinedEnd()) { 0273 // We can eat up all the remaining intervals 0274 it = d->intervals.erase(next, d->intervals.end()); 0275 } else { 0276 ++it; 0277 } 0278 } 0279 } 0280 0281 Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapInterval &interval) 0282 { 0283 return stream << interval.d->begin << interval.d->end; 0284 } 0285 0286 Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::ImapInterval &interval) 0287 { 0288 return stream >> interval.d->begin >> interval.d->end; 0289 } 0290 0291 Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapSet &set) 0292 { 0293 return stream << set.d->intervals; 0294 } 0295 0296 Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::ImapSet &set) 0297 { 0298 return stream >> set.d->intervals; 0299 } 0300 0301 } // namespace Akonadi 0302 0303 using namespace Akonadi; 0304 0305 QDebug operator<<(QDebug d, const Akonadi::ImapInterval &interval) 0306 { 0307 d << interval.toImapSequence(); 0308 return d; 0309 } 0310 0311 QDebug operator<<(QDebug d, const Akonadi::ImapSet &set) 0312 { 0313 d << set.toImapSequenceSet(); 0314 return d; 0315 }