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