2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
17 template<typename Value
>
22 Range(const Value
& offset
, const Value
& size
)
29 Value
EndOffset() const
36 template<typename Value
>
39 typedef Range
<Value
> RangeType
;
43 inline RangeArray(const RangeArray
<Value
>& other
);
45 inline int32
CountRanges() const
46 { return fRanges
.Count(); }
47 inline bool IsEmpty() const
48 { return fRanges
.IsEmpty(); }
49 inline const RangeType
* Ranges() const
50 { return fRanges
.Elements(); }
52 inline bool AddRange(const RangeType
& range
);
53 bool AddRange(const Value
& offset
,
55 inline bool RemoveRange(const RangeType
& range
);
56 bool RemoveRange(const Value
& offset
,
58 inline bool RemoveRanges(int32 index
, int32 count
= 1);
60 inline void Clear() { fRanges
.Clear(); }
61 inline void MakeEmpty() { fRanges
.MakeEmpty(); }
63 inline bool IntersectsWith(const RangeType
& range
) const;
64 bool IntersectsWith(const Value
& offset
,
65 const Value
& size
) const;
67 int32
InsertionIndex(const Value
& offset
) const;
69 inline const RangeType
& RangeAt(int32 index
) const
70 { return fRanges
.ElementAt(index
); }
72 inline const RangeType
& operator[](int32 index
) const
73 { return fRanges
[index
]; }
75 inline RangeArray
<Value
>& operator=(const RangeArray
<Value
>& other
);
78 inline RangeType
& _RangeAt(int32 index
)
79 { return fRanges
.ElementAt(index
); }
82 Array
<RangeType
> fRanges
;
86 template<typename Value
>
88 RangeArray
<Value
>::RangeArray()
93 template<typename Value
>
95 RangeArray
<Value
>::RangeArray(const RangeArray
<Value
>& other
)
97 fRanges(other
.fRanges
)
102 template<typename Value
>
104 RangeArray
<Value
>::AddRange(const RangeType
& range
)
106 return AddRange(range
.offset
, range
.size
);
110 /*! Adds the range starting at \a offset with size \a size.
112 The range is automatically joined with ranges it adjoins or overlaps with.
114 \return \c true, if the range was added successfully, \c false, if a memory
117 template<typename Value
>
119 RangeArray
<Value
>::AddRange(const Value
& offset
, const Value
& size
)
124 int32 index
= InsertionIndex(offset
);
126 // determine the last range the range intersects with/adjoins
127 Value endOffset
= offset
+ size
;
128 int32 endIndex
= index
;
129 // index after the last affected range
130 int32 count
= CountRanges();
131 while (endIndex
< count
&& RangeAt(endIndex
).offset
<= endOffset
)
134 // determine whether the range adjoins the previous range
135 if (index
> 0 && offset
== RangeAt(index
- 1).EndOffset())
138 if (index
== endIndex
) {
139 // no joining possible -- just insert the new range
140 return fRanges
.Insert(RangeType(offset
, size
), index
);
143 // Joining is possible. We'll adjust the first affected range and remove the
145 endOffset
= std::max(endOffset
, RangeAt(endIndex
- 1).EndOffset());
146 RangeType
& firstRange
= _RangeAt(index
);
147 firstRange
.offset
= std::min(firstRange
.offset
, offset
);
148 firstRange
.size
= endOffset
- firstRange
.offset
;
150 if (index
+ 1 < endIndex
)
151 RemoveRanges(index
+ 1, endIndex
- index
- 1);
157 template<typename Value
>
159 RangeArray
<Value
>::RemoveRange(const RangeType
& range
)
161 return RemoveRange(range
.offset
, range
.size
);
165 /*! Removes the range starting at \a offset with size \a size.
167 Ranges that are completely covered by the given range are removed. Ranges
168 that partially intersect with it are cut accordingly.
170 If a range is split into two ranges by the operation, a memory allocation
171 might be necessary and the method can fail, if the memory allocation fails.
173 \return \c true, if the range was removed successfully, \c false, if a
174 memory allocation failed.
176 template<typename Value
>
178 RangeArray
<Value
>::RemoveRange(const Value
& offset
, const Value
& size
)
183 int32 index
= InsertionIndex(offset
);
185 // determine the last range the range intersects with
186 Value endOffset
= offset
+ size
;
187 int32 endIndex
= index
;
188 // index after the last affected range
189 int32 count
= CountRanges();
190 while (endIndex
< count
&& RangeAt(endIndex
).offset
< endOffset
)
193 if (index
== endIndex
) {
194 // the given range doesn't intersect with any exiting range
198 // determine what ranges to remove completely
199 RangeType
& firstRange
= _RangeAt(index
);
200 RangeType
& lastRange
= _RangeAt(endIndex
- 1);
202 int32 firstRemoveIndex
= firstRange
.offset
>= offset
? index
: index
+ 1;
203 int32 endRemoveIndex
= lastRange
.EndOffset() <= endOffset
204 ? endIndex
: endIndex
- 1;
206 if (firstRemoveIndex
> endRemoveIndex
) {
207 // The range lies in the middle of an existing range. We need to split.
208 RangeType
newRange(endOffset
, firstRange
.EndOffset() - endOffset
);
209 if (!fRanges
.Insert(newRange
, index
+ 1))
212 firstRange
.size
= offset
- firstRange
.offset
;
216 // cut first and last range
217 if (index
< firstRemoveIndex
)
218 firstRange
.size
= offset
- firstRange
.offset
;
220 if (endOffset
> endRemoveIndex
) {
221 lastRange
.size
= lastRange
.EndOffset() - endOffset
;
222 lastRange
.offset
= endOffset
;
226 if (firstRemoveIndex
< endRemoveIndex
)
227 RemoveRanges(firstRemoveIndex
, endRemoveIndex
- firstRemoveIndex
);
233 template<typename Value
>
235 RangeArray
<Value
>::RemoveRanges(int32 index
, int32 count
)
237 return fRanges
.Remove(index
, count
);
241 template<typename Value
>
243 RangeArray
<Value
>::IntersectsWith(const RangeType
& range
) const
245 return IntersectsWith(range
.offset
, range
.size
);
249 template<typename Value
>
251 RangeArray
<Value
>::IntersectsWith(const Value
& offset
, const Value
& size
) const
253 int32 index
= InsertionIndex(offset
);
254 return index
< CountRanges() && RangeAt(index
).offset
< offset
+ size
;
258 /*! Returns the insertion index of a range starting at \a offset.
260 If the array contains a range that starts at, includes (but doesn't end at)
261 \a offset, the index of that range is returned. If \a offset lies in between
262 two ranges or before the first range, the index of the range following
263 \a offset is returned. Otherwise \c CountRanges() is returned.
265 \return The insertion index for a range starting at \a offset.
267 template<typename Value
>
269 RangeArray
<Value
>::InsertionIndex(const Value
& offset
) const
271 // binary search the index
273 int32 upper
= CountRanges();
275 while (lower
< upper
) {
276 int32 mid
= (lower
+ upper
) / 2;
277 const RangeType
& range
= RangeAt(mid
);
278 if (offset
>= range
.EndOffset())
288 template<typename Value
>
289 inline RangeArray
<Value
>&
290 RangeArray
<Value
>::operator=(const RangeArray
<Value
>& other
)
292 fRanges
= other
.fRanges
;
297 } // namespace BPrivate
300 using BPrivate::Range
;
301 using BPrivate::RangeArray
;
304 #endif // _RANGE_ARRAY_H