File indexing completed on 2024-05-19 04:00:02
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 <QtGlobal> 0014 0015 class QDebug; 0016 class QString; 0017 class QStringView; 0018 0019 namespace KTextEditor 0020 { 0021 /** 0022 * @class LineRange linerange.h <KTextEditor/LineRange> 0023 * 0024 * @short An object representing lines from a start line to an end line. 0025 * 0026 * A LineRange is a basic class which represents a range of lines, from a start() 0027 * line to an end() line. 0028 * 0029 * For simplicity and convenience, ranges always maintain their start() line to 0030 * be before or equal to their end() line. Attempting to set either the 0031 * start or end of the range beyond the respective end or start will result in 0032 * both values being set to the specified line. In the constructor, the 0033 * start and end will be swapped if necessary. 0034 * 0035 * @sa Range 0036 * 0037 * @since 5.79 0038 * @author Dominik Haumann \<dhaumann@kde.org\> 0039 */ 0040 class KTEXTEDITOR_EXPORT LineRange 0041 { 0042 public: 0043 /** 0044 * Default constructor. Creates a valid line range with both start and end 0045 * line set to 0. 0046 */ 0047 constexpr LineRange() noexcept = default; 0048 0049 /** 0050 * Constructor which creates a range from \e start to \e end. 0051 * If start is after end, they will be swapped. 0052 * 0053 * @param start start line 0054 * @param end end line 0055 */ 0056 constexpr LineRange(int start, int end) noexcept 0057 : m_start(qMin(start, end)) 0058 , m_end(qMax(start, end)) 0059 { 0060 } 0061 0062 /** 0063 * Validity check. In the base class, returns true unless the line range starts before (0,0). 0064 */ 0065 constexpr bool isValid() const noexcept 0066 { 0067 return m_start >= 0 && m_end >= 0; 0068 } 0069 0070 /** 0071 * Returns an invalid line range. 0072 */ 0073 constexpr static LineRange invalid() noexcept 0074 { 0075 return LineRange(-1, -1); 0076 } 0077 0078 /** 0079 * Returns the line range as string in the format 0080 * "[start line, end line]". 0081 * @see fromString() 0082 */ 0083 QString toString() const; 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) 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 constexpr int start() const 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 constexpr int end() const 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(LineRange range) 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) 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) 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 void setStart(int start) 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 void setEnd(int end) 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(LineRange range) 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(LineRange range) 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 constexpr bool onSingleLine() const 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 constexpr int numberOfLines() const 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 constexpr bool contains(LineRange range) const 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 constexpr bool containsLine(int line) const 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 constexpr bool overlaps(LineRange range) const 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 constexpr bool overlapsLine(int line) const 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 constexpr LineRange intersect(LineRange range) const 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 constexpr LineRange encompass(LineRange range) const noexcept 0342 { 0343 return (!isValid()) ? (range.isValid() ? range : invalid()) 0344 : (!range.isValid()) ? (*this) 0345 : LineRange(qMin(start(), range.start()), qMax(end(), range.end())); 0346 } 0347 0348 /** 0349 * Addition operator. Takes two ranges and returns their summation. 0350 * 0351 * @param r1 the first range 0352 * @param r2 the second range 0353 * 0354 * @return a the summation of the two input ranges 0355 */ 0356 constexpr friend LineRange operator+(LineRange r1, LineRange r2) noexcept 0357 { 0358 return LineRange(r1.start() + r2.start(), r1.end() + r2.end()); 0359 } 0360 0361 /** 0362 * Addition assignment operator. Adds \p r2 to this range. 0363 * 0364 * @param r1 the first range 0365 * @param r2 the second range 0366 * 0367 * @return a reference to the line range which has just been added to 0368 */ 0369 friend LineRange &operator+=(LineRange &r1, LineRange r2) noexcept 0370 { 0371 r1.setRange(r1.start() + r2.start(), r1.end() + r2.end()); 0372 return r1; 0373 } 0374 0375 /** 0376 * Subtraction operator. Takes two ranges and returns the subtraction 0377 * of \p r2 from \p r1. 0378 * 0379 * @param r1 the first range 0380 * @param r2 the second range 0381 * 0382 * @return a range representing the subtraction of \p r2 from \p r1 0383 */ 0384 constexpr friend LineRange operator-(LineRange r1, LineRange r2) noexcept 0385 { 0386 return LineRange(r1.start() - r2.start(), r1.end() - r2.end()); 0387 } 0388 0389 /** 0390 * Subtraction assignment operator. Subtracts \p r2 from \p r1. 0391 * 0392 * @param r1 the first range 0393 * @param r2 the second range 0394 * 0395 * @return a reference to the range which has just been subtracted from 0396 */ 0397 friend LineRange &operator-=(LineRange &r1, LineRange r2) noexcept 0398 { 0399 r1.setRange(r1.start() - r2.start(), r1.end() - r2.end()); 0400 return r1; 0401 } 0402 0403 /** 0404 * Intersects \a r1 and \a r2. 0405 * 0406 * @param r1 the first range 0407 * @param r2 the second range 0408 * 0409 * @return the intersected range, invalid() if there is no overlap 0410 */ 0411 constexpr friend LineRange operator&(LineRange r1, LineRange r2) noexcept 0412 { 0413 return r1.intersect(r2); 0414 } 0415 0416 /** 0417 * Intersects \a r1 with \a r2 and assigns the result to \a r1. 0418 * 0419 * @param r1 the range to assign the intersection to 0420 * @param r2 the range to intersect \a r1 with 0421 * 0422 * @return a reference to this range, after the intersection has taken place 0423 */ 0424 friend LineRange &operator&=(LineRange &r1, LineRange r2) noexcept 0425 { 0426 r1.setRange(r1.intersect(r2)); 0427 return r1; 0428 } 0429 0430 /** 0431 * Equality operator. 0432 * 0433 * @param r1 first range to compare 0434 * @param r2 second range to compare 0435 * 0436 * @return \e true if \e r1 and \e r2 equal, otherwise \e false 0437 */ 0438 constexpr friend bool operator==(LineRange r1, LineRange r2) noexcept 0439 { 0440 return r1.start() == r2.start() && r1.end() == r2.end(); 0441 } 0442 0443 /** 0444 * Inequality operator. 0445 * 0446 * @param r1 first range to compare 0447 * @param r2 second range to compare 0448 * 0449 * @return \e true if \e r1 and \e r2 do \e not equal, otherwise \e false 0450 */ 0451 constexpr friend bool operator!=(LineRange r1, LineRange r2) noexcept 0452 { 0453 return r1.start() != r2.start() || r1.end() != r2.end(); 0454 } 0455 0456 /** 0457 * Greater than operator. Looks only at the lines of the two ranges, 0458 * does not consider their size. 0459 * 0460 * @param r1 first range to compare 0461 * @param r2 second range to compare 0462 * 0463 * @return \e true if \e r1 starts after where \e r2 ends, otherwise \e false 0464 */ 0465 constexpr friend bool operator>(LineRange r1, LineRange r2) noexcept 0466 { 0467 return r1.start() > r2.end(); 0468 } 0469 0470 /** 0471 * Less than operator. Looks only at the lines of the two ranges, 0472 * does not consider their size. 0473 * 0474 * @param r1 first range to compare 0475 * @param r2 second range to compare 0476 * 0477 * @return \e true if \e r1 ends before \e r2 begins, otherwise \e false 0478 */ 0479 constexpr friend bool operator<(LineRange r1, LineRange r2) noexcept 0480 { 0481 return r1.end() < r2.start(); 0482 } 0483 0484 private: 0485 /** 0486 * This range's start line. 0487 * 0488 * @internal 0489 */ 0490 int m_start = 0; 0491 0492 /** 0493 * This range's end line. 0494 * 0495 * @internal 0496 */ 0497 int m_end = 0; 0498 }; 0499 0500 /** 0501 * QHash function for KTextEditor::LineRange. 0502 * Returns the hash value for @p range. 0503 */ 0504 KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::LineRange range, size_t seed = 0) noexcept; 0505 } 0506 0507 Q_DECLARE_TYPEINFO(KTextEditor::LineRange, Q_PRIMITIVE_TYPE); 0508 0509 /** 0510 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way. 0511 */ 0512 KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, KTextEditor::LineRange range); 0513 0514 namespace QTest 0515 { 0516 // forward declaration of template in qtestcase.h 0517 template<typename T> 0518 char *toString(const T &); 0519 0520 /** 0521 * QTestLib integration to have nice output in e.g. QCOMPARE failures. 0522 */ 0523 template<> 0524 KTEXTEDITOR_EXPORT char *toString(const KTextEditor::LineRange &range); 0525 } 0526 0527 #endif