klayout/src/tl/tlIntervalSet.h

265 lines
5.7 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_tlIntervalMap
#define HDR_tlIntervalMap
#include <vector>
namespace tl
{
/**
* @brief A helper compare function for the interval map
*
* This version will also finds preceeding intervals
*/
template <class I>
class is_compare_f
{
public:
bool operator() (const std::pair<I, I> &p, const I &i) const
{
return p.second < i;
}
};
/**
* @brief A helper compare function for the interval map
*
* This version will not find preceeding intervals
*/
template <class I>
class is_compare_f2
{
public:
bool operator() (const std::pair<I, I> &p, const I &i) const
{
return !(i < p.second);
}
};
/**
* @brief An interval map
*/
template <class I>
class interval_set
{
public:
typedef std::pair<I, I> index_pair;
typedef std::vector<index_pair> index_set;
typedef typename index_set::const_iterator const_iterator;
/**
* @brief Add intervals from the sequence [from,to)
*/
template <class Iter>
void add (Iter from, Iter to)
{
for (Iter i = from; i != to; ++i) {
add (i->first, i->second);
}
}
/**
* @brief Add the interval [i1,i2)
*
* @param i1 The first index of the interval
* @param i2 The second index of the interval
*/
void add (I i1, I i2)
{
typename index_set::iterator lb = std::lower_bound (m_index_set.begin (), m_index_set.end (), i1, is_compare_f<I> ());
if (lb == m_index_set.end () || ! (lb->first < i2)) {
// current and new interval do not overlap: create new interval(s):
// we can simply insert, because we create a new entry
m_index_set.insert (lb, index_pair (i1, i2));
} else {
// current and new interval do overlap: extend the intervals
// and join others if required
if (i1 < lb->first) {
lb->first = i1;
}
typename index_set::iterator lb0 = lb;
while (lb != m_index_set.end () && !(i2 < lb->first)) {
if (i2 < lb->second) {
i2 = lb->second;
}
++lb;
}
lb0->second = i2;
++lb0;
if (lb0 != lb) {
m_index_set.erase (lb0, lb);
}
}
}
/**
* @brief Erase an interval
*
* Erases the interval [i1,i2) (set to unmapped)
*/
void erase (I i1, I i2)
{
typename index_set::iterator lb = std::lower_bound (m_index_set.begin (), m_index_set.end (), i1, is_compare_f2<I> ());
typename index_set::iterator lb0 = lb;
if (! (i1 < i2)) {
return;
}
size_t n = 0;
while (lb != m_index_set.end () && lb->first < i2) {
++n;
++lb;
}
if (n == 0) {
// past the end: do nothing
} else if (n == 1 && lb0->first < i1 && i2 < lb0->second) {
// we are creating a "hole"
index_pair v (*lb0); // this copy is important since the insert may invalid the element *lb!
lb0 = m_index_set.insert (lb0, v);
lb0->second = i1;
++lb0;
lb0->first = i2;
} else {
// check for remaining parts of intervals
if (lb0->first < i1) {
// the first one is overlapping below i1: cut it
lb0->second = i1;
++lb0;
}
--lb;
if (lb != m_index_set.end () && i2 < lb->second) {
// the last one is overlapping above i2: cut it
lb->first = i2;
} else {
++lb;
}
// erase the intervals no longer needed
if (lb0 != lb) {
m_index_set.erase (lb0, lb);
}
}
}
/**
* @brief Query a mapping
*
* Given the index i, this method will return false if there is no mapping
* and true otherwise.
*
* @param i The index to search for
* @return The address of the value object or 0 if not mapped
*/
bool mapped (I i) const
{
typename index_set::const_iterator lb = std::lower_bound (m_index_set.begin (), m_index_set.end (), i, is_compare_f2<I> ());
return (lb != m_index_set.end () && ! (i < lb->first));
}
/**
* @brief Do a brief check if the structure is sorted
*/
bool check () const
{
typename index_set::const_iterator lb = m_index_set.begin ();
while (lb != m_index_set.end ()) {
typename index_set::const_iterator lbb = lb;
++lb;
if (lb != m_index_set.end () && !(lbb->second < lb->first)) {
return false;
}
}
return true;
}
/**
* @brief Clear the index map
*/
void clear ()
{
m_index_set.clear ();
}
/**
* @brief begin Iterator
*/
const_iterator begin () const
{
return m_index_set.begin ();
}
/**
* @brief end Iterator
*/
const_iterator end () const
{
return m_index_set.end ();
}
/**
* @brief equality operator
*/
bool operator== (const interval_set<I> &d) const
{
return m_index_set == d.m_index_set;
}
/**
* @brief inequality operator
*/
bool operator!= (const interval_set<I> &d) const
{
return m_index_set != d.m_index_set;
}
private:
index_set m_index_set;
};
} // namespace tl
#endif