File indexing completed on 2024-03-24 17:26:38

0001 /*
0002     This file is part of the Okteta Core library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2003, 2007-2008 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #ifndef OKTETA_RANGE_HPP
0010 #define OKTETA_RANGE_HPP
0011 
0012 namespace Okteta {
0013 
0014 /** This template describes a range.
0015  * A range is something with a start and an end.
0016  * The start is a value relative before the end.
0017  * The distance cannot be estimated.
0018  *
0019  * @author Friedrich W. H.  Kossebau
0020 */
0021 template <typename T>
0022 class Range
0023 {
0024 public:
0025     Range(T S, T E)
0026         : Start(S)
0027         , End(E)
0028     {}
0029     Range()
0030         : Start(null())
0031         , End(null())
0032     {}
0033     Range(const Range& R) = default;
0034     ~Range() = default;
0035 
0036 public:
0037     Range& operator=(const Range& R) = default;
0038 
0039 public:
0040     bool operator==(const Range& R) const
0041     { return (Start == R.Start && End == R.End) || (!isValid() && !R.isValid()); }
0042     bool operator!=(const Range& R) const
0043     { return ((Start != R.Start) || (End != R.End)) && (isValid() || R.isValid()); }
0044 
0045 public: // modification access
0046     /** sets the first and the last index of the range */
0047     void set(T S, T E) { Start = S; End = E; }
0048     /** sets the first and the last index of the range */
0049     void set(const Range& R) { Start = R.Start; End = R.End; }
0050     /** sets the first index of the range */
0051     void setStart(T S)  { Start = S; }
0052     /** sets the last index of the range */
0053     void setEnd(T E)    { End = E; }
0054     /** sets the range to null */
0055     void unset()           { Start = End = null(); }
0056     /** restricts the range to Limit. If one of both ranges is invalid the behaviour is undefined */
0057     void restrictTo(const Range& Limit)
0058     { if (Start < Limit.start()) {Start = Limit.start();} if (End > Limit.end()) {End = Limit.end();}}
0059     /** restricts the start to Limit. If the range is invalid the behaviour is undefined */
0060     void restrictStartTo(T Limit)  { if (Start < Limit) {Start = Limit;}}
0061     /** restricts the end to Limit. If the range is invalid the behaviour is undefined */
0062     void restrictEndTo(T Limit)    { if (End > Limit) {End = Limit;}}
0063     /** extends the range to Limit. If one of both is invalid the behaviour is undefined */
0064     void extendTo(const Range& Limit)
0065     { if (Start > Limit.start()) {Start = Limit.start();} if (End < Limit.end()) {End = Limit.end();}}
0066     /** extends the start to Limit. If the range is invalid the behaviour is undefined */
0067     void extendStartTo(T Limit)  { if (Start > Limit) {Start = Limit;}}
0068     /** extends the end to Limit. If the range is invalid the behaviour is undefined */
0069     void extendEndTo(T Limit)    { if (End < Limit) {End = Limit;}}
0070     /** moves the start by D. If the range is invalid the behaviour is undefined */
0071     void moveStartBy(T D)  { Start += D; }
0072     /** moves the end by D. If the range is invalid the behaviour is undefined */
0073     void moveEndBy(T D)    { End += D; }
0074     /** moves the range by D. If the range is invalid the behaviour is undefined */
0075     void moveBy(T D)      { Start += D; End += D; }
0076 
0077 public: // value access
0078     /** @return start */
0079     T start() const { return Start; }
0080     /** @return end */
0081     T end()   const { return End; }
0082 
0083 public: // logic access
0084     /** returns true if Value is covered */
0085     bool includes(T Value)       const { return Start <= Value && Value <= End; }
0086     /** returns true if Value is covered and not at a side */
0087     bool includesInside(T Value) const { return Start < Value && Value < End; }
0088     /** returns true if range is behind index. if range is invalid the behaviour is undefined */
0089     bool startsBehind(T Value)   const { return Value < Start; }
0090     /** returns true is the range starts before index. If the range is invalid the behaviour is undefined */
0091     bool startsBefore(T Value)   const { return Start < Value; }
0092     /** returns true if the range ends later than index. If the range is invalid the behaviour is undefined */
0093     bool endsBehind(T Value)     const { return Value < End; }
0094     /** returns true if range is before index. if range is invalid the behaviour is undefined */
0095     bool endsBefore(T Value)     const { return End < Value; }
0096 
0097     /** returns true is the range covers R. If one of both is invalid the behaviour is undefined */
0098     bool includes(const Range& R)       const { return R.End <= End && Start <= R.Start; }
0099     /** returns true is the range covers R. If one of both is invalid the behaviour is undefined */
0100     bool includesInside(const Range& R) const { return R.End < End && Start < R.Start; }
0101     /** returns true is the range ends before R starts. If one of both is invalid the behaviour is undefined */
0102     bool endsBefore(const Range& R)     const { return End < R.Start; }
0103     /** returns true is the range starts later than R ends. If one of both is invalid the behaviour is undefined */
0104     bool startsBehind(const Range& R) const { return R.End < Start; }
0105     /** returns true is the range starts prior than R. If one of both is invalid the behaviour is undefined */
0106     bool startsBefore(const Range& R) const { return Start < R.Start; }
0107     /** returns true is the range ends later than R. If one of both is invalid the behaviour is undefined */
0108     bool endsBehind(const Range& R)   const { return R.End < End; }
0109     /** returns true is the range shares at least one index with R. If one of both is invalid the behaviour is undefined */
0110     bool overlaps(const Range& R) const { return Start <= R.End && R.Start <= End; }
0111 
0112     // TODO: this is wrong, a empty range is valid, too
0113     /** returns true if the range covers at least one index */
0114     bool isValid() const { return Start != null() && Start <= End; }
0115     /** returns true if the range has not been set */
0116     bool isEmpty() const { return Start == null() && End == null(); }
0117 
0118 protected:
0119     /** delivers a null element. Should be specialiced for complexer types. */
0120     const T null() const { return T(-1);}
0121 
0122 protected:
0123     /** first value of the range */
0124     T Start;
0125     /** last value of the range */
0126     T End;
0127 };
0128 
0129 }
0130 
0131 #endif