mirror of https://github.com/KLayout/klayout.git
361 lines
8.8 KiB
C++
361 lines
8.8 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>
|
|
#include <algorithm>
|
|
|
|
namespace tl
|
|
{
|
|
|
|
/**
|
|
* @brief A helper compare function for the interval map
|
|
*/
|
|
template <class I, class T>
|
|
class iv_compare_f
|
|
{
|
|
public:
|
|
bool operator() (const std::pair< std::pair<I, I>, T> &p, const I &i) const
|
|
{
|
|
return !(i < p.first.second);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief An interval map
|
|
*/
|
|
template <class I, class T>
|
|
class interval_map
|
|
{
|
|
public:
|
|
typedef std::pair<I, I> index_pair;
|
|
typedef std::pair<index_pair, T> index_value_pair;
|
|
typedef std::vector<index_value_pair> index_map;
|
|
typedef typename index_map::const_iterator const_iterator;
|
|
typedef typename index_map::iterator iterator;
|
|
|
|
/**
|
|
* @brief Add values/intervals from the sequence [from,to)
|
|
*/
|
|
template <class Iter, class J>
|
|
void add (Iter from, Iter to, J &j)
|
|
{
|
|
for (Iter i = from; i != to; ++i) {
|
|
add (i->first.first, i->first.second, i->second, j);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Add a value t for the interval [i1,i2)
|
|
*
|
|
* If the interval overlaps with an already existing one
|
|
* the joining operator's operator() (T &a, const T &b)
|
|
* method is employed to join the existing value a with the
|
|
* new value b.
|
|
*
|
|
* @param i1 The first index of the interval
|
|
* @param i2 The second index of the interval
|
|
* @param t The value to insert
|
|
* @param j The joining operator
|
|
* @param compress Set this parameter to true to enable compression of the intervals where possible
|
|
*/
|
|
template <class J>
|
|
void add (I i1, I i2, const T &t, J &j)
|
|
{
|
|
typename index_map::iterator lb = std::lower_bound (m_index_map.begin (), m_index_map.end (), i1, iv_compare_f<I, T> ());
|
|
size_t ni = std::distance (m_index_map.begin (), lb);
|
|
|
|
while (i1 < i2) {
|
|
|
|
if (lb == m_index_map.end () || ! (lb->first.first < i2)) {
|
|
|
|
// current and new interval do not overlap: create new interval(s):
|
|
// we can simply insert, because we create a new entry
|
|
lb = m_index_map.insert (lb, index_value_pair (index_pair (i1, i2), t));
|
|
++lb;
|
|
i1 = i2;
|
|
|
|
} else {
|
|
|
|
// current and new interval do overlap: create new interval(s)
|
|
|
|
// the part of [i1,i2) before *lb ..
|
|
if (i1 < lb->first.first) {
|
|
I ii = lb->first.first;
|
|
lb = m_index_map.insert (lb, index_value_pair (index_pair (i1, i2), t));
|
|
if (! (i2 < ii)) {
|
|
lb->first.second = ii;
|
|
}
|
|
i1 = ii;
|
|
++lb;
|
|
}
|
|
|
|
// the part of *lb before [i1',i2)
|
|
if (lb->first.first < i1) {
|
|
index_value_pair v (*lb); // this copy is important since the insert may invalid the element *lb!
|
|
lb = m_index_map.insert (lb, v);
|
|
lb->first.second = i1;
|
|
++lb;
|
|
lb->first.first = i1;
|
|
}
|
|
|
|
// the part of *lb after [i1',i2)
|
|
if (i2 < lb->first.second) {
|
|
index_value_pair v (*lb); // this copy is important since the insert may invalid the element *lb!
|
|
lb = m_index_map.insert (lb, v);
|
|
lb->first.second = i2;
|
|
++lb;
|
|
lb->first.first = i2;
|
|
--lb;
|
|
}
|
|
|
|
// join with *lb and increment lb
|
|
j (lb->second, t);
|
|
i1 = lb->first.second;
|
|
++lb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// search for identical intervals that can be joined
|
|
// (only the one before the current interval and the one following can participate)
|
|
|
|
size_t nf = std::distance (m_index_map.begin (), lb);
|
|
if (nf < m_index_map.size ()) {
|
|
++nf;
|
|
}
|
|
|
|
lb = m_index_map.begin () + (ni > 0 ? ni - 1 : 0);
|
|
while (lb != m_index_map.begin () + nf) {
|
|
|
|
typename index_map::iterator lbb = lb;
|
|
|
|
do {
|
|
++lb;
|
|
} while (lb != m_index_map.end () &&
|
|
lbb->first.second == lb->first.first && lbb->second == lb->second);
|
|
|
|
// [lbb..lb[ can be joined: do so
|
|
if (lb != lbb + 1) {
|
|
--lb;
|
|
nf -= std::distance (lbb, lb);
|
|
lb->first.first = lbb->first.first;
|
|
lb = m_index_map.erase (lbb, lb);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Erase an interval
|
|
*
|
|
* Erases the interval [i1,i2) (set to unmapped)
|
|
*/
|
|
void erase (I i1, I i2)
|
|
{
|
|
typename index_map::iterator lb = std::lower_bound (m_index_map.begin (), m_index_map.end (), i1, iv_compare_f<I, T> ());
|
|
typename index_map::iterator lb0 = lb;
|
|
|
|
if (! (i1 < i2)) {
|
|
return;
|
|
}
|
|
|
|
size_t n = 0;
|
|
while (lb != m_index_map.end () && lb->first.first < i2) {
|
|
++n;
|
|
++lb;
|
|
}
|
|
|
|
if (n == 0) {
|
|
|
|
// past the end: do nothing
|
|
|
|
} else if (n == 1 && lb0->first.first < i1 && i2 < lb0->first.second) {
|
|
|
|
// we are creating a "hole"
|
|
index_value_pair v (*lb0); // this copy is important since the insert may invalid the element *lb!
|
|
lb0 = m_index_map.insert (lb0, v);
|
|
lb0->first.second = i1;
|
|
++lb0;
|
|
lb0->first.first = i2;
|
|
|
|
} else {
|
|
|
|
// check for remaining parts of intervals
|
|
if (lb0->first.first < i1) {
|
|
// the first one is overlapping below i1: cut it
|
|
lb0->first.second = i1;
|
|
++lb0;
|
|
}
|
|
--lb;
|
|
if (lb != m_index_map.end () && i2 < lb->first.second) {
|
|
// the last one is overlapping above i2: cut it
|
|
lb->first.first = i2;
|
|
} else {
|
|
++lb;
|
|
}
|
|
|
|
// erase the intervals no longer needed
|
|
if (lb0 != lb) {
|
|
m_index_map.erase (lb0, lb);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Query a mapping
|
|
*
|
|
* Given the index i, this method will return 0 if there is no mapping
|
|
* for the given index. Otherwise it will return the address of the
|
|
* value. The address is valid until the next add or erase method call
|
|
* only.
|
|
*
|
|
* @param i The index to search for
|
|
* @return The address of the value object or 0 if not mapped
|
|
*/
|
|
T *mapped (I i)
|
|
{
|
|
typename index_map::iterator lb = std::lower_bound (m_index_map.begin (), m_index_map.end (), i, iv_compare_f<I, T> ());
|
|
if (lb == m_index_map.end () || i < lb->first.first) {
|
|
return 0;
|
|
} else {
|
|
return &lb->second;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Query a mapping (const version)
|
|
*
|
|
* Given the index i, this method will return 0 if there is no mapping
|
|
* for the given index. Otherwise it will return the address of the
|
|
* value. The address is valid until the next add or erase method call
|
|
* only.
|
|
*
|
|
* @param i The index to search for
|
|
* @return The address of the value object or 0 if not mapped
|
|
*/
|
|
const T *mapped (I i) const
|
|
{
|
|
typename index_map::const_iterator lb = std::lower_bound (m_index_map.begin (), m_index_map.end (), i, iv_compare_f<I, T> ());
|
|
if (lb == m_index_map.end () || i < lb->first.first) {
|
|
return 0;
|
|
} else {
|
|
return &lb->second;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Do a brief check if the structure is sorted
|
|
*/
|
|
bool check () const
|
|
{
|
|
typename index_map::const_iterator lb = m_index_map.begin ();
|
|
while (lb != m_index_map.end ()) {
|
|
typename index_map::const_iterator lbb = lb;
|
|
++lb;
|
|
if (lb != m_index_map.end () && lb->first.first < lbb->first.second) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the size of the map
|
|
*/
|
|
size_t size () const
|
|
{
|
|
return m_index_map.size ();
|
|
}
|
|
|
|
/**
|
|
* @brief Clear the index map
|
|
*/
|
|
void clear ()
|
|
{
|
|
m_index_map.clear ();
|
|
}
|
|
|
|
/**
|
|
* @brief begin Iterator
|
|
*/
|
|
const_iterator begin () const
|
|
{
|
|
return m_index_map.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief end Iterator
|
|
*/
|
|
const_iterator end () const
|
|
{
|
|
return m_index_map.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief begin Iterator
|
|
*/
|
|
iterator begin ()
|
|
{
|
|
return m_index_map.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief end Iterator
|
|
*/
|
|
iterator end ()
|
|
{
|
|
return m_index_map.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief equality operator
|
|
*/
|
|
bool operator== (const interval_map<I, T> &d) const
|
|
{
|
|
return m_index_map == d.m_index_map;
|
|
}
|
|
|
|
/**
|
|
* @brief inequality operator
|
|
*/
|
|
bool operator!= (const interval_map<I, T> &d) const
|
|
{
|
|
return m_index_map != d.m_index_map;
|
|
}
|
|
|
|
private:
|
|
index_map m_index_map;
|
|
};
|
|
|
|
} // namespace tl
|
|
|
|
#endif
|
|
|