#ifndef _RANGE_ARRAY_H
#define _RANGE_ARRAY_H
#include <algorithm>
#include <Array.h>
namespace BPrivate {
template<typename Value>
struct Range {
Value offset;
Value size;
Range(const Value& offset, const Value& size)
:
offset(offset),
size(size)
{
}
Value EndOffset() const
{
return offset + size;
}
};
template<typename Value>
class RangeArray {
public:
typedef Range<Value> RangeType;
public:
inline RangeArray();
inline RangeArray(const RangeArray<Value>& other);
inline int32 CountRanges() const
{ return fRanges.Count(); }
inline bool IsEmpty() const
{ return fRanges.IsEmpty(); }
inline const RangeType* Ranges() const
{ return fRanges.Elements(); }
inline bool AddRange(const RangeType& range);
bool AddRange(const Value& offset,
const Value& size);
inline bool RemoveRange(const RangeType& range);
bool RemoveRange(const Value& offset,
const Value& size);
inline bool RemoveRanges(int32 index, int32 count = 1);
inline void Clear() { fRanges.Clear(); }
inline void MakeEmpty() { fRanges.MakeEmpty(); }
inline bool IntersectsWith(const RangeType& range) const;
bool IntersectsWith(const Value& offset,
const Value& size) const;
int32 InsertionIndex(const Value& offset) const;
inline const RangeType& RangeAt(int32 index) const
{ return fRanges.ElementAt(index); }
inline const RangeType& operator[](int32 index) const
{ return fRanges[index]; }
inline RangeArray<Value>& operator=(const RangeArray<Value>& other);
private:
inline RangeType& _RangeAt(int32 index)
{ return fRanges.ElementAt(index); }
private:
Array<RangeType> fRanges;
};
template<typename Value>
inline
RangeArray<Value>::RangeArray()
{
}
template<typename Value>
inline
RangeArray<Value>::RangeArray(const RangeArray<Value>& other)
:
fRanges(other.fRanges)
{
}
template<typename Value>
inline bool
RangeArray<Value>::AddRange(const RangeType& range)
{
return AddRange(range.offset, range.size);
}
template<typename Value>
bool
RangeArray<Value>::AddRange(const Value& offset, const Value& size)
{
if (size == 0)
return true;
int32 index = InsertionIndex(offset);
Value endOffset = offset + size;
int32 endIndex = index;
int32 count = CountRanges();
while (endIndex < count && RangeAt(endIndex).offset <= endOffset)
endIndex++;
if (index > 0 && offset == RangeAt(index - 1).EndOffset())
index--;
if (index == endIndex) {
return fRanges.Insert(RangeType(offset, size), index);
}
endOffset = std::max(endOffset, RangeAt(endIndex - 1).EndOffset());
RangeType& firstRange = _RangeAt(index);
firstRange.offset = std::min(firstRange.offset, offset);
firstRange.size = endOffset - firstRange.offset;
if (index + 1 < endIndex)
RemoveRanges(index + 1, endIndex - index - 1);
return true;
}
template<typename Value>
inline bool
RangeArray<Value>::RemoveRange(const RangeType& range)
{
return RemoveRange(range.offset, range.size);
}
template<typename Value>
bool
RangeArray<Value>::RemoveRange(const Value& offset, const Value& size)
{
if (size == 0)
return true;
int32 index = InsertionIndex(offset);
Value endOffset = offset + size;
int32 endIndex = index;
int32 count = CountRanges();
while (endIndex < count && RangeAt(endIndex).offset < endOffset)
endIndex++;
if (index == endIndex) {
return true;
}
RangeType& firstRange = _RangeAt(index);
RangeType& lastRange = _RangeAt(endIndex - 1);
int32 firstRemoveIndex = firstRange.offset >= offset ? index : index + 1;
int32 endRemoveIndex = lastRange.EndOffset() <= endOffset
? endIndex : endIndex - 1;
if (firstRemoveIndex > endRemoveIndex) {
RangeType newRange(endOffset, firstRange.EndOffset() - endOffset);
if (!fRanges.Insert(newRange, index + 1))
return false;
firstRange.size = offset - firstRange.offset;
return true;
}
if (index < firstRemoveIndex)
firstRange.size = offset - firstRange.offset;
if (endOffset > endRemoveIndex) {
lastRange.size = lastRange.EndOffset() - endOffset;
lastRange.offset = endOffset;
}
if (firstRemoveIndex < endRemoveIndex)
RemoveRanges(firstRemoveIndex, endRemoveIndex - firstRemoveIndex);
return true;
}
template<typename Value>
inline bool
RangeArray<Value>::RemoveRanges(int32 index, int32 count)
{
return fRanges.Remove(index, count);
}
template<typename Value>
inline bool
RangeArray<Value>::IntersectsWith(const RangeType& range) const
{
return IntersectsWith(range.offset, range.size);
}
template<typename Value>
bool
RangeArray<Value>::IntersectsWith(const Value& offset, const Value& size) const
{
int32 index = InsertionIndex(offset);
return index < CountRanges() && RangeAt(index).offset < offset + size;
}
template<typename Value>
int32
RangeArray<Value>::InsertionIndex(const Value& offset) const
{
int32 lower = 0;
int32 upper = CountRanges();
while (lower < upper) {
int32 mid = (lower + upper) / 2;
const RangeType& range = RangeAt(mid);
if (offset >= range.EndOffset())
lower = mid + 1;
else
upper = mid;
}
return lower;
}
template<typename Value>
inline RangeArray<Value>&
RangeArray<Value>::operator=(const RangeArray<Value>& other)
{
fRanges = other.fRanges;
return *this;
}
}
using BPrivate::Range;
using BPrivate::RangeArray;
#endif