HalfOpenInterval.h
// HalfOpenInterval.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
#pragma once
#ifndef Ceda_cxUtils_HalfOpenInterval_H
#define Ceda_cxUtils_HalfOpenInterval_H
#include "Archive.h"
#include "xostream.h"
#include "CedaAssert.h"
#include <algorithm>
namespace ceda
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// HalfOpenInterval<T>
template <typename T>
struct HalfOpenInterval
{
typedef T value_type;
HalfOpenInterval() : t1(0), t2(0) {}
HalfOpenInterval(T _s1, T _s2) : t1(_s1), t2(_s2) {}
// Shift interval
HalfOpenInterval<T>& operator+=(T offset) { t1 += offset; t2 += offset; return *this; }
HalfOpenInterval<T>& operator-=(T offset) { t1 -= offset; t2 -= offset; return *this; }
const HalfOpenInterval<T> operator+(T offset) const { return HalfOpenInterval<T>(t1 + offset, t2 + offset); }
const HalfOpenInterval<T> operator-(T offset) const { return HalfOpenInterval<T>(t1 - offset, t2 - offset); }
// Note that empty intervals don't necessarily compare equal. The recommended approach is
// for empty intervals to be recorded in normal form with t1 = t2 = 0.
bool operator==(const HalfOpenInterval& rhs) const { return t1 == rhs.t1 && t2 == rhs.t2; }
bool operator!=(const HalfOpenInterval& rhs) const { return t1 != rhs.t1 || t2 != rhs.t2; }
// Returns true if this interval is before (and possibly adjacent to) rhs
bool Before(const HalfOpenInterval& rhs) const
{
cxAssert(!empty());
cxAssert(!rhs.empty());
return t2 <= rhs.t1;
}
// Returns true if this interval is after (and possibly adjacent to) rhs
bool After(const HalfOpenInterval& rhs) const
{
cxAssert(!empty());
cxAssert(!rhs.empty());
return t1 >= rhs.t2;
}
// Returns true if there is a non-empty gap between the two non-empty intervals.
bool HasGap(const HalfOpenInterval& rhs) const
{
cxAssert(!empty());
cxAssert(!rhs.empty());
return t2 < rhs.t1 || t1 > rhs.t2;
}
// Returns true if this interval intersects the given interval. Assumes that
// both the intervals are non-empty
bool DoesIntersect(const HalfOpenInterval& rhs) const
{
cxAssert(!empty());
cxAssert(!rhs.empty());
return t2 > rhs.t1 && rhs.t2 > t1;
}
// Returns true if this interval contains the given value
bool Contains(T t) const { return t1 <= t && t < t2; }
// Returns true if this interval contains the given interval. Assumes that
// both the given intervals are non-empty
bool Contains(const HalfOpenInterval& rhs) const
{
cxAssert(!empty());
cxAssert(!rhs.empty());
return t1 <= rhs.t1 && rhs.t2 <= t2;
}
// Returns true if this interval is empty
bool empty() const { return t1 >= t2; }
T size() const { return t2 - t1; }
T begin() const { return t1; }
T end() const { return t2; }
void setbegin(T x) { t1 = x; }
void setend(T x) { t2 = x; }
void ScalarMultiply(T f)
{
t1 *= f;
t2 *= f;
}
/////////////////// State //////////////////
// Represents the half open interval [t1,t2).
// The representation is normalised if either t1 < t2 or else t1 = t2 = 0.
T t1, t2;
};
// Return h1 intersect h2
template <typename T>
HalfOpenInterval<T> Intersect(const HalfOpenInterval<T>& h1, const HalfOpenInterval<T>& h2)
{
return HalfOpenInterval<T>(std::max(h1.t1, h2.t1), std::min(h1.t2, h2.t2));
}
// Return range of h1, h2 which equals h1 union h2 if h1,h2 overlap or are adjacent (i.e.
// there is no gap between them).
template <typename T>
HalfOpenInterval<T> GetRange(const HalfOpenInterval<T>& h1, const HalfOpenInterval<T>& h2)
{
return HalfOpenInterval<T>(std::min(h1.t1, h2.t1), std::max(h1.t2, h2.t2));
}
template <typename Archive, typename T>
inline void Serialise(Archive& ar, const HalfOpenInterval<T>& i)
{
ar << i.t1 << i.t2;
}
template <typename Archive, typename T>
inline void Deserialise(Archive& ar, HalfOpenInterval<T>& i)
{
ar >> i.t1 >> i.t2;
}
template <typename T>
xostream& operator<<(xostream& os, const HalfOpenInterval<T>& i)
{
os << '[' << i.t1 << ',' << i.t2 << ')';
return os;
}
} // namespace ceda
#endif // include guard