File indexing completed on 2024-04-21 16:33:52

0001 /*
0002     This file is part of the Okteta Core library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2003, 2007-2009 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_NUMBERRANGE_HPP
0010 #define OKTETA_NUMBERRANGE_HPP
0011 
0012 // lib
0013 #include "range.hpp"
0014 
0015 namespace Okteta {
0016 
0017 /** describes a range of numbers which have a distance of 1 each
0018  * @author Friedrich W. H.  Kossebau
0019  */
0020 template <typename N, typename S = N>
0021 class NumberRange : public Range<N>
0022 {
0023 public:
0024     /** constructs a range by width
0025      * @param startIndex starting index
0026      * @param width width of the range
0027      */
0028     static NumberRange fromWidth(N startIndex, S width);
0029     static NumberRange fromWidth(S width);
0030 
0031 public:
0032     /** constructs a range
0033      * @param startIndex starting index
0034      * @param endIndex end index
0035      */
0036     NumberRange(N startIndex, N endIndex);
0037     NumberRange(const NumberRange& other);
0038     NumberRange();
0039 
0040     ~NumberRange();
0041 
0042 public:
0043     NumberRange& operator=(const NumberRange& other);
0044 
0045 public:
0046     void setByWidth(N other, S width);
0047     /** sets the first index of the range's range one behind the other's end
0048      * If one of both is invalid the behaviour is undefined
0049      */
0050     void setStartNextBehind(const NumberRange& other);
0051     void setStartNextBehind(N index);
0052     /** sets the first index of the range's range one behind the other's end
0053      * If one of both is invalid or the other' start is 0 the behaviour is undefined
0054      */
0055     void setEndNextBefore(const NumberRange& other);
0056     void setEndNextBefore(N index);
0057     /** sets the first index of the range's range to be width-1 before the end
0058      * If the range is invalid the behaviour is undefined
0059      */
0060     void setStartByWidth(S width);
0061     /** sets the last index of the range's range to be width-1 behind the start
0062      * If the range is invalid the behaviour is undefined
0063      */
0064     void setEndByWidth(S width);
0065     /** restricts the end by width. If the range is invalid the behaviour is undefined */
0066     void restrictEndByWidth(S width);
0067     /** moves the range defined by a new start.
0068      * If the range is invalid the behaviour is undefined
0069      */
0070     void moveToStart(N other);
0071     /** moves the range defined by a new end.
0072      * If the range is invalid the behaviour is undefined
0073      */
0074     void moveToEnd(N end);
0075 
0076     void adaptToReplacement(N offset, S removedLength, S insertedLength);
0077 
0078     NumberRange splitAt(N index);
0079     NumberRange splitAtLocal(N index);
0080     NumberRange remove(const NumberRange& removeRange);
0081     NumberRange removeLocal(const NumberRange& removeRange);
0082 
0083     bool prepend(const NumberRange& other);
0084     bool append(const NumberRange& other);
0085 
0086 public:
0087     /**
0088      * @return the numbered of included indizes or 0, if the range is invalid
0089      */
0090     S width() const;
0091     N nextBeforeStart() const;
0092     N nextBehindEnd() const;
0093 
0094 public:
0095     /** @return index relative to the start */
0096     N localIndex(N index) const;
0097     NumberRange localRange(const NumberRange& other) const;
0098     /** @return range given by local  */
0099     NumberRange subRange(const NumberRange& localRange) const;
0100     /**
0101      * @return the needed start so that other gets included, undefined if any is invalid
0102      */
0103     N startForInclude(const NumberRange& other) const;
0104     /** @returns true if both range . If one of both is invalid the behaviour is undefined */
0105     bool isJoinable(const NumberRange& other) const;
0106 };
0107 
0108 template <typename N, typename S>
0109 NumberRange<N, S>::NumberRange(N startIndex, N endIndex) : Range<N>(startIndex, endIndex) {}
0110 template <typename N, typename S>
0111 NumberRange<N, S>::NumberRange(const NumberRange& other) : Range<N>(other.start(), other.end()) {}
0112 template <typename N, typename S>
0113 NumberRange<N, S>::NumberRange() = default;
0114 
0115 template <typename N, typename S>
0116 NumberRange<N, S>::~NumberRange() = default;
0117 
0118 template <typename N, typename S>
0119 inline NumberRange<N, S> NumberRange<N, S>::fromWidth(N startIndex, S width) { return NumberRange(startIndex, startIndex + width - 1); }
0120 template <typename N, typename S>
0121 inline NumberRange<N, S> NumberRange<N, S>::fromWidth(S width) { return NumberRange<N, S>(0, width - 1); }
0122 
0123 template <typename N, typename S>
0124 inline NumberRange<N, S>& NumberRange<N, S>::operator=(const NumberRange<N, S>& other) { Range<N>::operator=(other); return *this; }
0125 
0126 template <typename N, typename S>
0127 inline S NumberRange<N, S>::width()       const { return Range<N>::isValid() ? Range<N>::end() - Range<N>::start() + 1 : 0; }
0128 template <typename N, typename S>
0129 inline N NumberRange<N, S>::nextBeforeStart() const { return Range<N>::start() - 1; }
0130 template <typename N, typename S>
0131 inline N NumberRange<N, S>::nextBehindEnd()   const { return Range<N>::end() + 1; }
0132 
0133 template <typename N, typename S>
0134 inline void NumberRange<N, S>::setByWidth(N other, S width)  { Range<N>::setStart(other); Range<N>::setEnd(other + width - 1); }
0135 template <typename N, typename S>
0136 inline void NumberRange<N, S>::setStartByWidth(S width)  { Range<N>::setStart(Range<N>::end() - width + 1); }
0137 template <typename N, typename S>
0138 inline void NumberRange<N, S>::setEndByWidth(S width)    { Range<N>::setEnd(Range<N>::start() + width - 1); }
0139 template <typename N, typename S>
0140 inline void NumberRange<N, S>::setStartNextBehind(const NumberRange<N, S>& other)  { Range<N>::setStart(other.nextBehindEnd()); }
0141 template <typename N, typename S>
0142 inline void NumberRange<N, S>::setStartNextBehind(N index)  { Range<N>::setStart(index + 1); }
0143 template <typename N, typename S>
0144 inline void NumberRange<N, S>::setEndNextBefore(const NumberRange<N, S>& other)    { Range<N>::setEnd(other.nextBeforeStart()); }
0145 template <typename N, typename S>
0146 inline void NumberRange<N, S>::setEndNextBefore(N index)    { Range<N>::setEnd(index - 1); }
0147 template <typename N, typename S>
0148 inline void NumberRange<N, S>::restrictEndByWidth(S width) { Range<N>::restrictEndTo(Range<N>::start() + width - 1); }
0149 
0150 template <typename N, typename S>
0151 inline void NumberRange<N, S>::moveToStart(N other) { Range<N>::setEnd(other + width() - 1); Range<N>::setStart(other); }
0152 template <typename N, typename S>
0153 inline void NumberRange<N, S>::moveToEnd(N end)   { Range<N>::setStart(end - width() + 1); Range<N>::setEnd(end); }
0154 
0155 template <typename N, typename S>
0156 inline NumberRange<N, S> NumberRange<N, S>::splitAt(N index)
0157 {
0158     const N secondEnd = Range<N>::end();
0159     setEndNextBefore(index);
0160     return NumberRange<N, S>(index, secondEnd);
0161 }
0162 template <typename N, typename S>
0163 inline NumberRange<N, S> NumberRange<N, S>::splitAtLocal(N index)
0164 {
0165     const N secondEnd = Range<N>::end();
0166     setEndByWidth(index);
0167     return NumberRange<N, S>(nextBehindEnd(), secondEnd);
0168 }
0169 template <typename N, typename S>
0170 inline NumberRange<N, S> NumberRange<N, S>::remove(const NumberRange<N, S>& removeRange)
0171 {
0172     const N secondEnd = Range<N>::end();
0173     setEndNextBefore(removeRange);
0174     return NumberRange<N, S>(removeRange.nextBehindEnd(), secondEnd);
0175 }
0176 template <typename N, typename S>
0177 inline NumberRange<N, S> NumberRange<N, S>::removeLocal(const NumberRange<N, S>& removeRange)
0178 {
0179     const N secondEnd = Range<N>::end();
0180     setEndByWidth(removeRange.start());
0181     return NumberRange<N, S>(Range<N>::start() + removeRange.nextBehindEnd(), secondEnd);
0182 }
0183 
0184 template <typename N, typename S>
0185 inline N NumberRange<N, S>::localIndex(N index) const { return index - Range<N>::start(); }
0186 template <typename N, typename S>
0187 inline NumberRange<N, S> NumberRange<N, S>::localRange(const NumberRange<N, S>& other) const
0188 { return NumberRange<N, S>(other.start() - Range<N>::start(), other.end() - Range<N>::start()); }
0189 template <typename N, typename S>
0190 inline NumberRange<N, S> NumberRange<N, S>::subRange(const NumberRange<N, S>& localRange) const
0191 { return NumberRange<N, S>(localRange.start() + Range<N>::start(), localRange.end() + Range<N>::start()); }
0192 
0193 template <typename N, typename S>
0194 inline N NumberRange<N, S>::startForInclude(const NumberRange<N, S>& other) const
0195 {
0196     return Range<N>::startsBehind(other.start()) ? other.start() :
0197            Range<N>::endsBefore(other.end()) ?     other.end() - width() + 1 :
0198            Range<N>::start();
0199 }
0200 template <typename N, typename S>
0201 inline bool NumberRange<N, S>::isJoinable(const NumberRange<N, S>& other) const
0202 { return Range<N>::start() <= other.nextBehindEnd() && other.nextBeforeStart() <= Range<N>::end(); }
0203 
0204 template <typename N, typename S>
0205 inline bool NumberRange<N, S>::prepend(const NumberRange<N, S>& other)
0206 {
0207     const bool mergeable = (other.nextBehindEnd() == Range<N>::start()); if (mergeable) {
0208         Range<N>::setStart(other.start());
0209     }
0210     return mergeable;
0211 }
0212 template <typename N, typename S>
0213 inline bool NumberRange<N, S>::append(const NumberRange<N, S>& other)
0214 {
0215     const bool mergeable = (nextBehindEnd() == other.start()); if (mergeable) {
0216         Range<N>::setEnd(other.end());
0217     }
0218     return mergeable;
0219 }
0220 
0221 template <typename N, typename S>
0222 inline void NumberRange<N, S>::adaptToReplacement(N offset, S removedLength, S insertedLength)
0223 {
0224     // nothing to adapt or not affected at all??
0225     if (!Range<N>::isValid() || Range<N>::endsBefore(offset - 1)) {
0226         return;
0227     }
0228 
0229     // indirectly affected?
0230     if (!Range<N>::startsBefore(offset + removedLength)) {
0231         Range<N>::moveBy(insertedLength - removedLength);
0232     }
0233     // changes overlap, oh well
0234     else {
0235         // only inserted?
0236         if (removedLength == 0) {
0237             if (Range<N>::startsBefore(offset) && !Range<N>::endsBefore(offset - 1)) {
0238                 Range<N>::moveEndBy(insertedLength);
0239             }
0240         }
0241         // only removed?
0242         else if (insertedLength == 0) {
0243             Range<N>::extendStartTo(offset);
0244             Range<N>::moveEndBy(-removedLength);
0245             Range<N>::extendEndTo(offset - 1);
0246             // equals "if( End>offset+removedLength ) End -= removedLength; else End = offset-1;"
0247         } else {
0248             if (Range<N>::startsBehind(offset)) {
0249                 Range<N>::setStart(offset + insertedLength);
0250             }
0251             if (Range<N>::endsBefore(offset + removedLength - 1)) {
0252                 Range<N>::setEnd(offset - 1);
0253             } else {
0254                 Range<N>::moveEndBy(insertedLength - removedLength);
0255             }
0256         }
0257     }
0258 }
0259 
0260 }
0261 
0262 #endif