Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/dataflowAPI/rose/util/IntervalSet.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

730 lines
31 KiB
C++

// WARNING: Changes to this file must be contributed back to Sawyer or else they will
// be clobbered by the next update from Sawyer. The Sawyer repository is at
// https://github.com/matzke1/sawyer.
#ifndef Sawyer_IntervalSet_H
#define Sawyer_IntervalSet_H
#include "IntervalMap.h"
#include "Optional.h"
#include "Sawyer.h"
#include <stddef.h>
#include <utility>
#include <dyncompat/integer_traits.hpp>
#include <dyncompat/iterator/iterator_facade.hpp>
namespace Sawyer {
namespace Container {
/** A container holding a set of values.
*
* This container is somewhat like the STL <code>std::set</code> container except it is optimized for the case when large
* numbers of values are contiguous. It adds the ability to insert and erase intervals as well as scalars, and provides a
* mechanism to iterate over the storage nodes (intervals) rather than over the scalar values.
*
* An interval set always maintains a list containing a minimum number of largest possible intervals regardless of what
* intervals are inserted and erased. This feature makes for a very convenient way to compute address ranges for small
* things, or things that might overlap. For instance, if one has a list of intervals corresponding to machine instructions
* that belong to a single function in an executable (some of which might even overlap), we can easily compute whether the
* function is contiguous in memory, and whether any instructions overlap with each other:
*
* @code
* // Input is a list of intervals for instructions in a function
* typedef Sawyer::Container::Interval<uint32_t> AddressInterval;
* std::vector<AddressInterval> instructionIntervals = ...;
*
* // Build the functionExtent and count total instruction size
* Sawyer::Container::IntervalSet<AddressInterval> functionExtent;
* uint32_t insnTotalSize = 0;
* DYN_FOREACH (const AddressInterval &insnInterval, instructionIntervals) {
* functionExtent.insert(insnInterval);
* insnTotalSize += insnInterval.size();
* }
*
* // Final results
* bool isFunctionContiguous = functionExtent.nIntervals() <= 1;
* bool isInsnsDisjoint = functionExtent.size() == insnTotalSize;
* @endcode
*
* The @p Interval template parameter must implement the Sawyer::Container::Interval API, at least to some extent. */
template<class I>
class IntervalSet {
// We use an IntervalMap to do all our work, always storing int(0) as the value.
typedef IntervalMap<I, int> Map;
Map map_;
public:
typedef I Interval;
typedef typename I::Value Scalar; /**< Type of scalar values stored in this set. */
/** Interval iterator.
*
* Iterates over the intervals of the container, which are the Interval type provided as a class template
* parameter. Dereferencing the iterator will return a const reference to an interval (possibly a singlton interval). */
class ConstIntervalIterator: public dyncompat::iterator_facade<ConstIntervalIterator, const Interval,
dyncompat::bidirectional_traversal_tag> {
typedef typename IntervalMap<Interval, int>::ConstNodeIterator MapNodeIterator;
MapNodeIterator iter_;
public:
ConstIntervalIterator() {}
private:
friend struct dyncompat::iterator_core_access;
friend class IntervalSet;
explicit ConstIntervalIterator(MapNodeIterator iter): iter_(iter) {}
const Interval& dereference() const { return iter_->key(); }
bool equal(const ConstIntervalIterator &other) const { return iter_ == other.iter_; }
void increment() { ++iter_; }
void decrement() { --iter_; }
MapNodeIterator base() const { return iter_; }
};
/** Scalar value iterator.
*
* Scalar value iterators iterate over each scalar value in the set. Two caveats to beware of:
*
* @li The set can hold a very large number of values, even the entire value space, in which case iterating over values
* rather than storage nodes could take a very long time.
* @li Iterating over values for a non-integral type is most likely nonsensical. */
class ConstScalarIterator: public dyncompat::iterator_facade<ConstScalarIterator, const typename Interval::Value,
dyncompat::bidirectional_traversal_tag> {
ConstIntervalIterator iter_;
typename Interval::Value offset_;
mutable typename Interval::Value value_; // so dereference() can return a reference
public:
ConstScalarIterator(): offset_(0) {}
ConstScalarIterator(ConstIntervalIterator iter): iter_(iter), offset_(0) {}
private:
friend struct dyncompat::iterator_core_access;
friend class IntervalSet;
const typename Interval::Value& dereference() const {
ASSERT_require2(iter_->least() <= iter_->greatest(), "stored interval cannot be empty");
ASSERT_require(iter_->least() + offset_ <= iter_->greatest());
value_ = iter_->least() + offset_;
return value_; // must return a reference
}
bool equal(const ConstScalarIterator &other) const {
return iter_ == other.iter_ && offset_ == other.offset_;
}
void increment() {
ASSERT_require2(iter_->least() <= iter_->greatest(), "stored interval cannot be empty");
if (iter_->least() + offset_ == iter_->greatest()) {
++iter_;
offset_ = 0;
} else {
++offset_;
}
}
void decrement() {
ASSERT_require2(iter_->least() <= iter_->greatest(), "stored interval cannot be empty");
if (0==offset_) {
--iter_;
offset_ = width(*iter_);
} else {
--offset_;
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Default constructor.
*
* Creates an empty set. */
IntervalSet() {}
/** Copy constructor.
*
* The newly constructed set will contain copies of the nodes from @p other. */
template<class Interval2>
IntervalSet(const IntervalSet<Interval2> &other) {
typedef typename IntervalSet<Interval2>::ConstIntervalIterator OtherIntervalIterator;
for (OtherIntervalIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
insert(*otherIter);
}
/** Construct from an IntervalMap.
*
* The newly constructed set will contain copies of the intervals from the specified @ref IntervalMap. The map's
* intervals must be convertible to the set's interval type. The map's values are not used. */
template<class Interval2, class T, class Policy>
explicit IntervalSet(const IntervalMap<Interval2, T, Policy> &other) {
typedef typename IntervalMap<Interval2, T, Policy>::ConstNodeIterator OtherNodeIterator;
for (OtherNodeIterator otherIter=other.nodes().begin(); otherIter!=other.nodes().end(); ++otherIter)
insert(otherIter->key());
}
/** Construct from an iterator range.
*
* The newly constructed set will contain copies of the intervals from the specified iterator range. The range's
* dereferenced iterators must be convertible to the set's interval type. */
template<class Iterator>
IntervalSet(const dyncompat::iterator_range<Iterator> &intervals) {
for (Iterator iter=intervals.begin(); iter!=intervals.end(); ++iter)
insert(*iter);
}
/** Assignment from another set.
*
* Causes this set to contain the same intervals as the @p other set. The other set's intervals must be convertible to
* this set's interval type. */
template<class Interval2>
IntervalSet& operator=(const IntervalSet<Interval2> &other) {
clear();
typedef typename IntervalSet<Interval2>::ConstIntervalIterator OtherIntervalIterator;
for (OtherIntervalIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
insert(*otherIter);
return *this;
}
/** Assignment from an IntervalMap.
*
* Causes this set to contain the same intervals as the specified map. The map's intervals must be convertible to this
* set's interval type. Since sets and maps have different requirements regarding merging of neighboring intervals, the
* returned container might not have node-to-node correspondence with the map, but both will contain the same logical
* intervals. */
template<class Interval2, class T, class Policy>
IntervalSet& operator=(const IntervalMap<Interval2, T, Policy> &other) {
clear();
typedef typename IntervalMap<Interval2, T, Policy>::ConstNodeIterator OtherNodeIterator;
for (OtherNodeIterator otherIter=other.nodes().begin(); otherIter!=other.nodes().end(); ++otherIter)
insert(otherIter->key());
return *this;
}
/** Assignment from an iterator range.
*
* The newly constructed set will contain copies of the intervals from the specified iterator range. The range's
* dereferenced iterators must be convertible to the set's interval type. */
template<class Iterator>
IntervalSet& operator=(const dyncompat::iterator_range<Iterator> &intervals) {
clear();
for (Iterator iter=intervals.begin(); iter!=intervals.end(); ++iter)
insert(*iter);
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Iteration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Iterator range for all intervals actually stored by this set. */
dyncompat::iterator_range<ConstIntervalIterator> intervals() const {
return dyncompat::iterator_range<ConstIntervalIterator>(ConstIntervalIterator(map_.nodes().begin()),
ConstIntervalIterator(map_.nodes().end()));
}
/** Iterator range for all scalar values logically represented by this set. */
dyncompat::iterator_range<ConstScalarIterator> scalars() const {
return dyncompat::iterator_range<ConstScalarIterator>(ConstScalarIterator(intervals().begin()),
ConstScalarIterator(intervals().end()));
}
/** Find the first node whose interval ends at or above the specified scalar key.
*
* Returns an iterator to the node, or the end iterator if no such node exists. */
ConstIntervalIterator lowerBound(const typename Interval::Value &scalar) const {
return ConstIntervalIterator(map_.lowerBound(scalar));
}
/** Find the first node whose interval begins above the specified scalar key.
*
* Returns an iterator to the node, or the end iterator if no such node exists. */
ConstIntervalIterator upperBound(const typename Interval::Value &scalar) const {
return ConstIntervalIterator(map_.upperBound(scalar));
}
/** Find the last node whose interval starts at or below the specified scalar key.
*
* Returns an iterator to the node, or the end iterator if no such node exists. */
ConstIntervalIterator findPrior(const typename Interval::Value &scalar) const {
return ConstIntervalIterator(map_.findPrior(scalar));
}
/** Find the node containing the specified scalar key.
*
* Returns an iterator to the matching node, or the end iterator if no such node exists. */
ConstIntervalIterator find(const typename Interval::Value &scalar) const {
return ConstIntervalIterator(map_.find(scalar));
}
/** Finds all nodes overlapping the specified interval.
*
* Returns an iterator range that enumerates the nodes that overlap with the specified interval. */
dyncompat::iterator_range<ConstIntervalIterator> findAll(const Interval &interval) const {
dyncompat::iterator_range<typename Map::ConstNodeIterator> range = map_.findAll(interval);
return dyncompat::iterator_range<ConstIntervalIterator>(ConstIntervalIterator(range.begin()),
ConstIntervalIterator(range.end()));
}
/** Finds first node that overlaps with the specified interval.
*
* Returns an iterator to the matching node, or the end iterator if no such node exists. */
ConstIntervalIterator findFirstOverlap(const Interval &interval) const {
return ConstIntervalIterator(map_.findFirstOverlap(interval));
}
/** @} */
/** Find first nodes that overlap.
*
* Given two ranges of iterators for two sets, advance the iterators to the closest nodes that overlap with each other,
* and return the result as two iterators. If no overlaps can be found then the return value is two end iterators. */
std::pair<ConstIntervalIterator, ConstIntervalIterator>
findFirstOverlap(ConstIntervalIterator thisIter, const IntervalSet &other, ConstIntervalIterator otherIter) const {
std::pair<typename Map::ConstNodeIterator, typename Map::ConstNodeIterator> found =
map_.findFirstOverlap(thisIter.base(), other.map_, otherIter.base());
return std::make_pair(ConstIntervalIterator(found.first), ConstIntervalIterator(found.second));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Size
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Determine whether the container is empty.
*
* Returns true only if this set contains no elements. */
bool isEmpty() const {
return map_.isEmpty();
}
/** Number of scalar elements represented.
*
* Returns the number of scalar elements (not intervals or storage nodes) contained in this set. Since the return type is
* the same as the type used in the interval end points, this function can return overflowed values. For instance, a set
* that contains all possible values in the value space is likely to return zero. */
typename Interval::Value size() const {
return map_.size();
}
/** Number of storage nodes.
*
* Returns the number of nodes stored in this container, which for sets is always the number of maximally contiguous
* intervals. Most algorithms employed by IntervalSet methods are either logarithmic or scalar in this number. */
size_t nIntervals() const {
return map_.nIntervals();
}
/** Returns the range of values in this map. */
Interval hull() const {
return map_.hull();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Predicates
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Determines whether this set overlaps with the argument.
*
* Returns true if this set contains any values that are also present in the argument.
*
* @{ */
template<class Interval2>
bool isOverlapping(const Interval2 &interval) const {
return map_.isOverlapping(interval);
}
template<class Interval2>
bool isOverlapping(const IntervalSet<Interval2> &other) const {
return map_.isOverlapping(other.map_);
}
template<class Interval2, class T2, class Policy2>
bool isOverlapping(const IntervalMap<Interval2, T2, Policy2> &other) const {
return map_.isOverlapping(other);
}
/** @} */
/** Determines whether this set is distinct from the argument.
*
* Returns true if none of the values of this set are equal to any value in the argument.
*
* @{ */
template<class Interval2>
bool isDistinct(const Interval2 &/*interval*/) const {
return !isOverlapping();
}
template<class Interval2>
bool isDistinct(const IntervalSet<Interval2> &other) const {
return !isOverlapping(other);
}
template<class Interval2, class T2, class Policy2>
bool isDistinct(const IntervalMap<Interval2, T2, Policy2> &other) const {
return !isOverlapping(other);
}
/** @} */
/** Determines if a value exists in the set.
*
* Returns true if the specified value is a member of the set. */
bool exists(const typename Interval::Value &scalar) const {
return find(scalar)!=intervals().end();
}
/** Determines whether this set fully contains the argument.
*
* Returns true if this set contains all values represented by the argument.
*
* @{ */
bool contains(const typename Interval::Value &scalar) const {
return exists(scalar);
}
template<class Interval2>
bool contains(const Interval2 &interval) const {
return map_.contains(interval);
}
template<class Interval2>
bool contains(const IntervalSet<Interval2> &other) const {
return map_.contains(other.map_);
}
template<class Interval2, class T2, class Policy2>
bool contains(const IntervalMap<Interval2, T2, Policy2> &other) const {
return map_.contains(other);
}
/** @} */
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Searching
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Returns the minimum scalar contained in this set. */
Scalar least() const {
ASSERT_forbid(isEmpty());
return map_.least();
}
/** Returns the maximum scalar contained in this set. */
Scalar greatest() const {
ASSERT_forbid(isEmpty());
return map_.greatest();
}
/** Returns the limited-minimum scalar contained in this set.
*
* Returns the minimum scalar that exists in this set and which is greater than or equal to @p lowerLimit. If no such
* value exists then nothing is returned. */
Optional<Scalar> least(Scalar lowerLimit) const {
return map_.least(lowerLimit);
}
/** Returns the limited-maximum scalar contained in this set.
*
* Returns the maximum scalar that exists in this set and which is less than or equal to @p upperLimit. If no such
* value exists then nothing is returned. */
Optional<Scalar> greatest(Scalar upperLimit) const {
return map_.greatest(upperLimit);
}
/** Returns the limited-minimum scalar not contained in this set.
*
* Returns the minimum scalar equal to or greater than the @p lowerLimit which is not in this set. If no such value
* exists then nothing is returned. */
Optional<Scalar> leastNonExistent(Scalar lowerLimit) const {
return map_.leastUnmapped(lowerLimit);
}
/** Returns the limited-maximum scalar not contained in this set.
*
* Returns the maximum scalar equal to or less than the @p upperLimit which is not in this set. If no such value exists
* then nothing is returned. */
Optional<Scalar> greatestNonExistent(Scalar upperLimit) const {
return map_.greatestUnmapped(upperLimit);
}
/** Find the first fit node at or after a starting point.
*
* Finds the first node of contiguous values beginning at or after the specified starting iterator, @p start, and which is
* at least as large as the desired @p size. If there are no such nodes then the end iterator is returned.
*
* Caveat emptor: The @p size argument has the name type as the interval end points. If the end points have a signed type,
* then it is entirely likely that the size will overflow. In fact, it is also possible that unsigned sizes overflow
* since, for example, an 8-bit unsigned size cannot hold the size of an interval representing the entire 8-bit space.
* Therefore, use this method with care. */
ConstIntervalIterator firstFit(const typename Interval::Value &size, ConstIntervalIterator start) const {
return ConstIntervalIterator(map_.firstFit(size, start.iter_));
}
/** Find the best fit node at or after a starting point.
*
* Finds a node of contiguous values beginning at or after the specified starting iterator, @p start, and which is at
* least as large as the desired @p size. If there is more than one such node, then the first smallest such node is
* returned. If there are no such nodes then the end iterator is returned.
*
* Caveat emptor: The @p size argument has the name type as the interval end points. If the end points have a signed type,
* then it is entirely likely that the size will overflow. In fact, it is also possible that unsigned sizes overflow
* since, for example, an 8-bit unsigned size cannot hold the size of an interval representing the entire 8-bit space.
* Therefore, use this method with care. */
ConstIntervalIterator bestFit(const typename Interval::Value &size, ConstIntervalIterator start) const {
return ConstIntervalIterator(map_.bestFit(size, start.iter_));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Modifiers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Remove all values.
*
* All values are removed from this set and the set becomes empty. */
void clear() {
map_.clear();
}
/** Invert.
*
* Invert this set in place. */
void invert() {
invert(Interval::whole());
}
/** Invert and intersect.
*
* Inverts this set and then intersects it with @p restricted. */
void invert(const Interval &restricted) {
IntervalSet inverted;
if (!restricted.isEmpty()) {
typename Interval::Value pending = restricted.least();
bool insertTop = true;
for (typename Map::ConstIntervalIterator iter=map_.lowerBound(restricted.least());
iter!=map_.intervals().end(); ++iter) {
if (iter->least() > restricted.greatest())
break;
if (pending < iter->least())
inverted.insert(Interval::hull(pending, iter->least()-1));
if (iter->greatest() < restricted.greatest()) {
pending = iter->greatest() + 1;
} else {
insertTop = false;
break;
}
}
if (insertTop)
inverted.insert(Interval::hull(pending, restricted.greatest()));
}
std::swap(map_, inverted.map_);
}
/** Insert specified values.
*
* The values can be specified by a interval (or scalar if the interval has an implicit constructor), another set whose
* interval type is convertible to this set's interval type, or an IntervalMap whose intervals are convertible.
*
* @{ */
template<class Interval2>
void insert(const Interval2 &interval) {
map_.insert(interval, 0);
}
template<class Interval2>
void insertMultiple(const IntervalSet<Interval2> &other) {
typedef typename IntervalSet<Interval2>::ConstIntervalIterator OtherIterator;
for (OtherIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
map_.insert(*otherIter, 0);
}
template<class Interval2, class T, class Policy>
void insertMultiple(const IntervalMap<Interval2, T, Policy> &other) {
typedef typename IntervalMap<Interval2, T, Policy>::ConstIntervalIterator OtherIterator;
for (OtherIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
map_.insert(*otherIter, 0);
}
/** @} */
/** Remove specified values.
*
* The values can be specified by an interval (or scalar if the interval has an implicit constructor), another set whose
* interval type is convertible to this set's interval type, or an IntervalMap whose intervals are convertible.
*
* @{ */
template<class Interval2>
void erase(const Interval2 &interval) {
map_.erase(interval);
}
template<class Interval2>
void eraseMultiple(const IntervalSet<Interval2> &other) {
ASSERT_forbid2((void*)&other==(void*)this, "use IntervalSet::clear() instead");
typedef typename IntervalSet<Interval2>::ConstIntervalIterator OtherIntervalIterator;
for (OtherIntervalIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
map_.erase(*otherIter);
}
template<class Interval2, class T, class Policy>
void eraseMultiple(const IntervalMap<Interval2, T, Policy> &other) {
typedef typename IntervalMap<Interval2, T, Policy>::ConstIntervalIterator OtherIntervalIterator;
for (OtherIntervalIterator otherIter=other.intervals().begin(); otherIter!=other.intervals().end(); ++otherIter)
map_.erase(otherIter->first);
}
/** @} */
/** Interset with specified values.
*
* Computes in place intersection of this container with the specified argument. The argument may be an interval (or
* scalar if the interval has an implicit constructor), or another set whose interval type is convertible to this set's
* interval type.
*
* @{ */
template<class Interval2>
void intersect(const Interval2 &interval) {
if (isEmpty())
return;
if (interval.isEmpty()) {
clear();
return;
}
if (hull().least() < interval.least())
map_.erase(Interval::hull(hull().least(), interval.least()-1));
if (hull().greatest() > interval.greatest())
map_.erase(Interval::hull(interval.greatest(), hull().greatest()));
}
template<class Interval2>
void intersect(IntervalSet<Interval2> other) {
other.invert(hull());
map_.eraseMultiple(other.map_);
}
template<class Interval2, class T, class Policy>
void intersect(const IntervalMap<Interval2, T, Policy> &other);// FIXME[Robb Matzke 2014-04-12]: not implemented yet
/** @} */
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Operators
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Determines if two sets contain the same elements. */
bool operator==(const IntervalSet &other) const {
return !(*this!=other);
}
/** Determines if two sets contain different elements. */
bool operator!=(const IntervalSet &other) const {
if (map_.nIntervals()!=other.map_.nIntervals())
return true;
for (ConstIntervalIterator ai=intervals().begin(), bi=other.intervals().begin(); ai!=intervals().end(); ++ai, ++bi) {
if (*ai!=*bi)
return true;
}
return false;
}
/** Return inverse of specified set. */
IntervalSet operator~() const {
IntervalSet tmp = *this;
tmp.invert();
return tmp;
}
/** In-place union.
*
* Inserts the members of @p other set into @p this set. */
IntervalSet& operator|=(const IntervalSet &other) {
insertMultiple(other);
return *this;
}
/** In-place union with interval.
*
* Inserts the @p interval into @p this set. */
IntervalSet& operator|=(const Interval &interval) {
insert(interval);
return *this;
}
/** Union of two sets. */
IntervalSet operator|(const IntervalSet &other) const {
if (nIntervals() < other.nIntervals()) {
IntervalSet tmp = other;
tmp.insertMultiple(*this);
return tmp;
}
IntervalSet tmp = *this;
tmp.insertMultiple(other);
return tmp;
}
/** Union of set with interval.
*
* It's probably more efficient to insert the interval in place, but this method is sometimes convenient. */
IntervalSet operator|(const Interval &interval) const {
IntervalSet retval = *this;
retval.insert(interval);
return retval;
}
/** In-place intersection.
*
* Modifies @p this set so it contains only those members that are also in the @p other set. */
IntervalSet& operator&=(const IntervalSet &other) {
intersect(other);
return *this;
}
/** In-place intersection with an interval.
*
* Modifies @p this set so it contains only those members that are also in @p interval. */
IntervalSet& operator&=(const Interval &interval) {
intersect(interval);
return *this;
}
/** Intersection of two sets. */
IntervalSet operator&(const IntervalSet &other) const {
if (nIntervals() < other.nIntervals()) {
IntervalSet tmp = other;
tmp.intersect(*this);
return tmp;
}
IntervalSet tmp = *this;
tmp.intersect(other);
return tmp;
}
/** Intersection of set with interval. */
IntervalSet operator&(const Interval &interval) const {
IntervalSet retval = *this;
retval.intersect(interval);
return retval;
}
/** In-place subtraction.
*
* Subtracts from @p this set those members of the @p other set. */
IntervalSet& operator-=(const IntervalSet &other) {
eraseMultiple(other);
return *this;
}
/** In-place subtraction of an interval.
*
* Removes the specified @p interval of values from @p this set. */
IntervalSet& operator-=(const Interval &interval) {
erase(interval);
return *this;
}
/** Subtract another set from this one.
*
* <code>A-B</code> is equivalent to <code>A & ~B</code> but perhaps faster. */
IntervalSet operator-(const IntervalSet &other) const {
IntervalSet tmp = *this;
tmp.eraseMultiple(other);
return tmp;
}
};
} // namespace
} // namespace
#endif