File indexing completed on 2024-05-12 15:45:40
0001 /* 0002 SPDX-FileCopyrightText: 2001-2005 Christoph Cullmann <cullmann@kde.org> 0003 SPDX-FileCopyrightText: 2021 Dominik Haumann <dhaumann@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KTEXTEDITOR_LINERANGE_H 0009 #define KTEXTEDITOR_LINERANGE_H 0010 0011 #include <ktexteditor_export.h> 0012 0013 #include <QDebug> 0014 #include <QtGlobal> 0015 0016 namespace KTextEditor 0017 { 0018 /** 0019 * @class LineRange linerange.h <KTextEditor/LineRange> 0020 * 0021 * @short An object representing lines from a start line to an end line. 0022 * 0023 * A LineRange is a basic class which represents a range of lines, from a start() 0024 * line to an end() line. 0025 * 0026 * For simplicity and convenience, ranges always maintain their start() line to 0027 * be before or equal to their end() line. Attempting to set either the 0028 * start or end of the range beyond the respective end or start will result in 0029 * both values being set to the specified line. In the constructor, the 0030 * start and end will be swapped if necessary. 0031 * 0032 * @sa Range 0033 * 0034 * @since 5.79 0035 * @author Dominik Haumann \<dhaumann@kde.org\> 0036 */ 0037 class KTEXTEDITOR_EXPORT LineRange 0038 { 0039 public: 0040 /** 0041 * Default constructor. Creates a valid line range with both start and end 0042 * line set to 0. 0043 */ 0044 Q_DECL_CONSTEXPR LineRange() Q_DECL_NOEXCEPT 0045 { 0046 } 0047 0048 /** 0049 * Constructor which creates a range from \e start to \e end. 0050 * If start is after end, they will be swapped. 0051 * 0052 * @param start start line 0053 * @param end end line 0054 */ 0055 Q_DECL_CONSTEXPR LineRange(int start, int end) Q_DECL_NOEXCEPT : m_start(qMin(start, end)), m_end(qMax(start, end)) 0056 { 0057 } 0058 0059 /** 0060 * Validity check. In the base class, returns true unless the line range starts before (0,0). 0061 */ 0062 Q_DECL_CONSTEXPR inline bool isValid() const Q_DECL_NOEXCEPT 0063 { 0064 return m_start >= 0 && m_end >= 0; 0065 } 0066 0067 /** 0068 * Returns an invalid line range. 0069 */ 0070 Q_DECL_CONSTEXPR static LineRange invalid() Q_DECL_NOEXCEPT 0071 { 0072 return LineRange(-1, -1); 0073 } 0074 0075 /** 0076 * Returns the line range as string in the format 0077 * "[start line, end line]". 0078 * @see fromString() 0079 */ 0080 QString toString() const 0081 { 0082 return QLatin1Char('[') + QString::number(m_start) + QLatin1String(", ") + QString::number(m_end) + QLatin1Char(']'); 0083 } 0084 0085 /** 0086 * Returns a LineRange created from the string \p str containing the format 0087 * "[start line, end line]". 0088 * In case the string cannot be parsed, an LineRange::invalid() is returned. 0089 * @see toString() 0090 */ 0091 static LineRange fromString(QStringView str) Q_DECL_NOEXCEPT; 0092 0093 /** 0094 * @name Position 0095 * 0096 * The following functions provide access to, and manipulation of, the range's position. 0097 * @{ 0098 */ 0099 0100 /** 0101 * Get the start line of this line range. This will always be <= end(). 0102 * 0103 * @returns the start line of this line range. 0104 */ 0105 Q_DECL_CONSTEXPR inline int start() const Q_DECL_NOEXCEPT 0106 { 0107 return m_start; 0108 } 0109 0110 /** 0111 * Get the end line of this line range. This will always be >= start(). 0112 * 0113 * @returns the end line of this line range. 0114 */ 0115 Q_DECL_CONSTEXPR inline int end() const Q_DECL_NOEXCEPT 0116 { 0117 return m_end; 0118 } 0119 0120 /** 0121 * Set the start and end lines to \e start and \e end respectively. 0122 * 0123 * \note If \e start is after \e end, they will be reversed. 0124 * 0125 * \param start start line 0126 * \param end end line 0127 */ 0128 void setRange(const LineRange &range) Q_DECL_NOEXCEPT 0129 { 0130 setRange(range.start(), range.end()); 0131 } 0132 0133 /** 0134 * Set the start and end lines to \e start and \e end respectively. 0135 * 0136 * \note If \e start is after \e end, they will be reversed. 0137 * 0138 * \param start start line 0139 * \param end end line 0140 */ 0141 void setRange(int start, int end) Q_DECL_NOEXCEPT 0142 { 0143 m_start = qMin(start, end); 0144 m_end = qMax(start, end); 0145 } 0146 0147 /** 0148 * Convenience function. Set the start and end lines to \p line. 0149 * 0150 * @param line the line number to assign to start() and end() 0151 */ 0152 void setBothLines(int line) Q_DECL_NOEXCEPT 0153 { 0154 m_start = line; 0155 m_end = line; 0156 } 0157 0158 /** 0159 * Set the start line to \e start. 0160 * 0161 * @note If \e start is after current end, start and end will be set to new start value. 0162 * 0163 * @param start new start line 0164 */ 0165 inline void setStart(int start) Q_DECL_NOEXCEPT 0166 { 0167 if (start > end()) { 0168 setRange(start, start); 0169 } else { 0170 setRange(start, end()); 0171 } 0172 } 0173 0174 /** 0175 * Set the end line to \e end. 0176 * 0177 * @note If \e end is in front of current start, start and end will be set to new end value. 0178 * 0179 * @param end new end line 0180 */ 0181 inline void setEnd(int end) Q_DECL_NOEXCEPT 0182 { 0183 if (end < start()) { 0184 setRange(end, end); 0185 } else { 0186 setRange(start(), end); 0187 } 0188 } 0189 0190 /** 0191 * Expand this line range if necessary to contain \p range. 0192 * 0193 * @param range range which this range should contain 0194 * 0195 * @return \e true if expansion occurred, \e false otherwise 0196 */ 0197 bool expandToRange(const LineRange &range) Q_DECL_NOEXCEPT 0198 { 0199 if (start() > range.start()) 0200 if (end() < range.end()) { 0201 setRange(range); 0202 } else { 0203 setStart(range.start()); 0204 } 0205 else if (end() < range.end()) { 0206 setEnd(range.end()); 0207 } else { 0208 return false; 0209 } 0210 0211 return true; 0212 } 0213 0214 /** 0215 * Confine this range if necessary to fit within \p range. 0216 * 0217 * @param range range which should contain this range 0218 * 0219 * @return \e true if confinement occurred, \e false otherwise 0220 */ 0221 bool confineToRange(const LineRange &range) Q_DECL_NOEXCEPT 0222 { 0223 if (start() < range.start()) 0224 if (end() > range.end()) { 0225 setRange(range); 0226 } else { 0227 setStart(range.start()); 0228 } 0229 else if (end() > range.end()) { 0230 setEnd(range.end()); 0231 } else { 0232 return false; 0233 } 0234 0235 return true; 0236 } 0237 0238 /** 0239 * Check whether this line range is on one line. 0240 * 0241 * @return \e true if both the start and end line are equal, otherwise \e false 0242 */ 0243 Q_DECL_CONSTEXPR inline bool onSingleLine() const Q_DECL_NOEXCEPT 0244 { 0245 return start() == end(); 0246 } 0247 0248 /** 0249 * Returns the number of lines separating the start() and end() line. 0250 * 0251 * @return the number of lines separating the start() and end() line; 0252 * 0 if the start and end lines are the same. 0253 */ 0254 Q_DECL_CONSTEXPR inline int numberOfLines() const Q_DECL_NOEXCEPT 0255 { 0256 return end() - start(); 0257 } 0258 0259 // BEGIN comparison functions 0260 /** 0261 * @} 0262 * 0263 * @name Comparison 0264 * 0265 * The following functions perform checks against this range in comparison 0266 * to other lines and ranges. 0267 * @{ 0268 */ 0269 /** 0270 * Check whether the this range wholly encompasses \e range. 0271 * 0272 * @param range range to check 0273 * 0274 * @return \e true, if this range contains \e range, otherwise \e false 0275 */ 0276 Q_DECL_CONSTEXPR inline bool contains(const LineRange &range) const Q_DECL_NOEXCEPT 0277 { 0278 return range.start() >= start() && range.end() <= end(); 0279 } 0280 0281 /** 0282 * Returns true if this range wholly encompasses \p line. 0283 * 0284 * @param line line to check 0285 * 0286 * @return \e true if the line is wholly encompassed by this range, otherwise \e false. 0287 */ 0288 Q_DECL_CONSTEXPR inline bool containsLine(int line) const Q_DECL_NOEXCEPT 0289 { 0290 return line >= start() && line < end(); 0291 } 0292 0293 /** 0294 * Check whether the this range overlaps with \e range. 0295 * 0296 * @param range range to check against 0297 * 0298 * @return \e true, if this range overlaps with \e range, otherwise \e false 0299 */ 0300 Q_DECL_CONSTEXPR inline bool overlaps(const LineRange &range) const Q_DECL_NOEXCEPT 0301 { 0302 return (range.start() <= start()) ? (range.end() > start()) : (range.end() >= end()) ? (range.start() < end()) : contains(range); 0303 } 0304 0305 /** 0306 * Check whether the range overlaps at least part of \e line. 0307 * 0308 * @param line line to check 0309 * 0310 * @return \e true, if the range overlaps at least part of \e line, otherwise \e false 0311 */ 0312 Q_DECL_CONSTEXPR inline bool overlapsLine(int line) const Q_DECL_NOEXCEPT 0313 { 0314 return line >= start() && line <= end(); 0315 } 0316 //!\} 0317 // END 0318 0319 /** 0320 * Intersects this line range with another, returning the shared lines of 0321 * the two line ranges. 0322 * 0323 * @param range other line range to intersect with this 0324 * 0325 * @return the intersection of this range and the supplied \a range. 0326 */ 0327 Q_DECL_CONSTEXPR inline LineRange intersect(const LineRange &range) const Q_DECL_NOEXCEPT 0328 { 0329 return ((!isValid() || !range.isValid() || *this > range || *this < range)) ? invalid() 0330 : LineRange(qMax(start(), range.start()), qMin(end(), range.end())); 0331 } 0332 0333 /** 0334 * Returns the smallest range which encompasses this line range and the 0335 * supplied \a range. 0336 * 0337 * @param range other range to encompass 0338 * 0339 * @return the smallest range which contains this range and the supplied \a range. 0340 */ 0341 Q_DECL_CONSTEXPR inline LineRange encompass(const LineRange &range) const Q_DECL_NOEXCEPT 0342 { 0343 return (!isValid()) ? (range.isValid() ? range : invalid()) 0344 : (!range.isValid()) ? (*this) : LineRange(qMin(start(), range.start()), qMax(end(), range.end())); 0345 } 0346 0347 /** 0348 * Addition operator. Takes two ranges and returns their summation. 0349 * 0350 * @param r1 the first range 0351 * @param r2 the second range 0352 * 0353 * @return a the summation of the two input ranges 0354 */ 0355 Q_DECL_CONSTEXPR inline friend LineRange operator+(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0356 { 0357 return LineRange(r1.start() + r2.start(), r1.end() + r2.end()); 0358 } 0359 0360 /** 0361 * Addition assignment operator. Adds \p r2 to this range. 0362 * 0363 * @param r1 the first range 0364 * @param r2 the second range 0365 * 0366 * @return a reference to the line range which has just been added to 0367 */ 0368 inline friend LineRange &operator+=(LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0369 { 0370 r1.setRange(r1.start() + r2.start(), r1.end() + r2.end()); 0371 return r1; 0372 } 0373 0374 /** 0375 * Subtraction operator. Takes two ranges and returns the subtraction 0376 * of \p r2 from \p r1. 0377 * 0378 * @param r1 the first range 0379 * @param r2 the second range 0380 * 0381 * @return a range representing the subtraction of \p r2 from \p r1 0382 */ 0383 Q_DECL_CONSTEXPR inline friend LineRange operator-(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0384 { 0385 return LineRange(r1.start() - r2.start(), r1.end() - r2.end()); 0386 } 0387 0388 /** 0389 * Subtraction assignment operator. Subtracts \p r2 from \p r1. 0390 * 0391 * @param r1 the first range 0392 * @param r2 the second range 0393 * 0394 * @return a reference to the range which has just been subtracted from 0395 */ 0396 inline friend LineRange &operator-=(LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0397 { 0398 r1.setRange(r1.start() - r2.start(), r1.end() - r2.end()); 0399 return r1; 0400 } 0401 0402 /** 0403 * Intersects \a r1 and \a r2. 0404 * 0405 * @param r1 the first range 0406 * @param r2 the second range 0407 * 0408 * @return the intersected range, invalid() if there is no overlap 0409 */ 0410 Q_DECL_CONSTEXPR inline friend LineRange operator&(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0411 { 0412 return r1.intersect(r2); 0413 } 0414 0415 /** 0416 * Intersects \a r1 with \a r2 and assigns the result to \a r1. 0417 * 0418 * @param r1 the range to assign the intersection to 0419 * @param r2 the range to intersect \a r1 with 0420 * 0421 * @return a reference to this range, after the intersection has taken place 0422 */ 0423 inline friend LineRange &operator&=(LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0424 { 0425 r1.setRange(r1.intersect(r2)); 0426 return r1; 0427 } 0428 0429 /** 0430 * Equality operator. 0431 * 0432 * @param r1 first range to compare 0433 * @param r2 second range to compare 0434 * 0435 * @return \e true if \e r1 and \e r2 equal, otherwise \e false 0436 */ 0437 Q_DECL_CONSTEXPR inline friend bool operator==(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0438 { 0439 return r1.start() == r2.start() && r1.end() == r2.end(); 0440 } 0441 0442 /** 0443 * Inequality operator. 0444 * 0445 * @param r1 first range to compare 0446 * @param r2 second range to compare 0447 * 0448 * @return \e true if \e r1 and \e r2 do \e not equal, otherwise \e false 0449 */ 0450 Q_DECL_CONSTEXPR inline friend bool operator!=(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0451 { 0452 return r1.start() != r2.start() || r1.end() != r2.end(); 0453 } 0454 0455 /** 0456 * Greater than operator. Looks only at the lines of the two ranges, 0457 * does not consider their size. 0458 * 0459 * @param r1 first range to compare 0460 * @param r2 second range to compare 0461 * 0462 * @return \e true if \e r1 starts after where \e r2 ends, otherwise \e false 0463 */ 0464 Q_DECL_CONSTEXPR inline friend bool operator>(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0465 { 0466 return r1.start() > r2.end(); 0467 } 0468 0469 /** 0470 * Less than operator. Looks only at the lines of the two ranges, 0471 * does not consider their size. 0472 * 0473 * @param r1 first range to compare 0474 * @param r2 second range to compare 0475 * 0476 * @return \e true if \e r1 ends before \e r2 begins, otherwise \e false 0477 */ 0478 Q_DECL_CONSTEXPR inline friend bool operator<(const LineRange &r1, const LineRange &r2) Q_DECL_NOEXCEPT 0479 { 0480 return r1.end() < r2.start(); 0481 } 0482 0483 /** 0484 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way. 0485 */ 0486 inline friend QDebug operator<<(QDebug s, const LineRange &range) 0487 { 0488 s << "[" << range.start() << " -> " << range.end() << "]"; 0489 return s; 0490 } 0491 0492 private: 0493 /** 0494 * This range's start line. 0495 * 0496 * @internal 0497 */ 0498 int m_start = 0; 0499 0500 /** 0501 * This range's end line. 0502 * 0503 * @internal 0504 */ 0505 int m_end = 0; 0506 }; 0507 0508 } 0509 0510 Q_DECLARE_TYPEINFO(KTextEditor::LineRange, Q_MOVABLE_TYPE); 0511 Q_DECLARE_METATYPE(KTextEditor::LineRange) 0512 0513 /** 0514 * QHash function for KTextEditor::LineRange. 0515 * Returns the hash value for @p range. 0516 */ 0517 inline uint qHash(const KTextEditor::LineRange &range, uint seed = 0) Q_DECL_NOTHROW 0518 { 0519 return qHash(qMakePair(qHash(range.start()), qHash(range.end())), seed); 0520 } 0521 0522 namespace QTest 0523 { 0524 // forward declaration of template in qtestcase.h 0525 template<typename T> 0526 char *toString(const T &); 0527 0528 /** 0529 * QTestLib integration to have nice output in e.g. QCOMPARE failures. 0530 */ 0531 template<> 0532 KTEXTEDITOR_EXPORT char *toString(const KTextEditor::LineRange &range); 0533 } 0534 0535 #endif