File indexing completed on 2024-04-21 05:53:00
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