mirror of https://github.com/KLayout/klayout.git
Providing single-linked list implementation with fast size to address DRC merge performance issue on CentOS
This commit is contained in:
parent
43ff59750a
commit
035232c978
|
|
@ -1264,7 +1264,7 @@ connected_clusters<T>::join_cluster_with (typename local_cluster<T>::id_type id,
|
|||
}
|
||||
|
||||
connections_type &target = m_connections [id];
|
||||
target.splice (target.end (), to_join, to_join.begin (), to_join.end ());
|
||||
target.splice (to_join);
|
||||
|
||||
m_connections.erase (tc);
|
||||
|
||||
|
|
|
|||
|
|
@ -211,6 +211,273 @@ private:
|
|||
edge_connectivity_type m_ec;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The instance information for a cluster
|
||||
*/
|
||||
class DB_PUBLIC ClusterInstElement
|
||||
{
|
||||
public:
|
||||
ClusterInstElement (const db::InstElement &ie)
|
||||
{
|
||||
if (ie.array_inst.at_end ()) {
|
||||
|
||||
m_inst_cell_index = std::numeric_limits<db::cell_index_type>::max ();
|
||||
m_inst_trans = db::ICplxTrans ();
|
||||
m_inst_prop_id = 0;
|
||||
|
||||
} else {
|
||||
|
||||
m_inst_cell_index = ie.inst_ptr.cell_index ();
|
||||
m_inst_trans = ie.complex_trans ();
|
||||
m_inst_prop_id = ie.inst_ptr.prop_id ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id)
|
||||
: m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstElement ()
|
||||
: m_inst_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_inst_trans (), m_inst_prop_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the cluster does not have an instance
|
||||
*/
|
||||
bool has_instance () const
|
||||
{
|
||||
return m_inst_cell_index != std::numeric_limits<db::cell_index_type>::max ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cell index of the cell which is instantiated
|
||||
*/
|
||||
db::cell_index_type inst_cell_index () const
|
||||
{
|
||||
return m_inst_cell_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the instance transformation
|
||||
*/
|
||||
const db::ICplxTrans &inst_trans () const
|
||||
{
|
||||
return m_inst_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the instance properties id
|
||||
*/
|
||||
db::properties_id_type inst_prop_id () const
|
||||
{
|
||||
return m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the instance properties id
|
||||
*/
|
||||
void set_inst_prop_id (db::properties_id_type pid)
|
||||
{
|
||||
m_inst_prop_id = pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transform with the given transformation
|
||||
*/
|
||||
void transform (const db::ICplxTrans &tr)
|
||||
{
|
||||
m_inst_trans = tr * m_inst_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const ClusterInstElement &other) const
|
||||
{
|
||||
return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const ClusterInstElement &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const ClusterInstElement &other) const
|
||||
{
|
||||
if (m_inst_cell_index != other.m_inst_cell_index) {
|
||||
return m_inst_cell_index < other.m_inst_cell_index;
|
||||
}
|
||||
if (! m_inst_trans.equal (other.m_inst_trans)) {
|
||||
return m_inst_trans.less (other.m_inst_trans);
|
||||
}
|
||||
return m_inst_prop_id < other.m_inst_prop_id;
|
||||
}
|
||||
|
||||
private:
|
||||
db::cell_index_type m_inst_cell_index;
|
||||
db::ICplxTrans m_inst_trans;
|
||||
db::properties_id_type m_inst_prop_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A connection to a cluster in a child instance
|
||||
*/
|
||||
class DB_PUBLIC ClusterInstance
|
||||
: public ClusterInstElement
|
||||
{
|
||||
public:
|
||||
ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id)
|
||||
: ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance (size_t id, const db::InstElement &inst_element)
|
||||
: ClusterInstElement (inst_element), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance (size_t id)
|
||||
: ClusterInstElement (), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance ()
|
||||
: ClusterInstElement (), m_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cluster ID
|
||||
*/
|
||||
size_t id () const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const ClusterInstance &other) const
|
||||
{
|
||||
return m_id == other.m_id && ClusterInstElement::operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const ClusterInstance &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const ClusterInstance &other) const
|
||||
{
|
||||
if (m_id != other.m_id) {
|
||||
return m_id < other.m_id;
|
||||
}
|
||||
return ClusterInstElement::operator< (other);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class representing a list of ClusterInstance objects
|
||||
*
|
||||
* It is using a std::list internally, but adds fast size support for STLs which do not have that.
|
||||
*/
|
||||
class DB_PUBLIC ClusterInstanceList
|
||||
{
|
||||
public:
|
||||
typedef std::list<ClusterInstance> inner_list;
|
||||
typedef inner_list::iterator iterator;
|
||||
typedef inner_list::const_iterator const_iterator;
|
||||
|
||||
ClusterInstanceList ()
|
||||
: m_list (), m_size (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstanceList (const ClusterInstanceList &other)
|
||||
: m_list (other.m_list), m_size (other.m_size)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstanceList (ClusterInstanceList &&other)
|
||||
: m_list (other.m_list), m_size (other.m_size)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstanceList &operator= (const ClusterInstanceList &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_list = other.m_list;
|
||||
m_size = other.m_size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin () { return m_list.begin (); }
|
||||
iterator end () { return m_list.end (); }
|
||||
const_iterator begin () const { return m_list.begin (); }
|
||||
const_iterator end () const { return m_list.end (); }
|
||||
|
||||
bool empty () const
|
||||
{
|
||||
return m_list.empty ();
|
||||
}
|
||||
|
||||
void push_back (const ClusterInstance &inst)
|
||||
{
|
||||
m_list.push_back (inst);
|
||||
++m_size;
|
||||
}
|
||||
|
||||
void push_back (ClusterInstance &&inst)
|
||||
{
|
||||
m_list.push_back (inst);
|
||||
++m_size;
|
||||
}
|
||||
|
||||
void splice (ClusterInstanceList &other)
|
||||
{
|
||||
m_size += other.m_size;
|
||||
m_list.splice (m_list.end (), other.m_list, other.m_list.begin (), other.m_list.end ());
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
size_t size () const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
inner_list m_list;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a cluster of shapes
|
||||
*
|
||||
|
|
@ -596,195 +863,6 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int
|
|||
x.mem_stat (stat, purpose, cat, no_self, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The instance information for a cluster
|
||||
*/
|
||||
class DB_PUBLIC ClusterInstElement
|
||||
{
|
||||
public:
|
||||
ClusterInstElement (const db::InstElement &ie)
|
||||
{
|
||||
if (ie.array_inst.at_end ()) {
|
||||
|
||||
m_inst_cell_index = std::numeric_limits<db::cell_index_type>::max ();
|
||||
m_inst_trans = db::ICplxTrans ();
|
||||
m_inst_prop_id = 0;
|
||||
|
||||
} else {
|
||||
|
||||
m_inst_cell_index = ie.inst_ptr.cell_index ();
|
||||
m_inst_trans = ie.complex_trans ();
|
||||
m_inst_prop_id = ie.inst_ptr.prop_id ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id)
|
||||
: m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstElement ()
|
||||
: m_inst_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_inst_trans (), m_inst_prop_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the cluster does not have an instance
|
||||
*/
|
||||
bool has_instance () const
|
||||
{
|
||||
return m_inst_cell_index != std::numeric_limits<db::cell_index_type>::max ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cell index of the cell which is instantiated
|
||||
*/
|
||||
db::cell_index_type inst_cell_index () const
|
||||
{
|
||||
return m_inst_cell_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the instance transformation
|
||||
*/
|
||||
const db::ICplxTrans &inst_trans () const
|
||||
{
|
||||
return m_inst_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the instance properties id
|
||||
*/
|
||||
db::properties_id_type inst_prop_id () const
|
||||
{
|
||||
return m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the instance properties id
|
||||
*/
|
||||
void set_inst_prop_id (db::properties_id_type pid)
|
||||
{
|
||||
m_inst_prop_id = pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transform with the given transformation
|
||||
*/
|
||||
void transform (const db::ICplxTrans &tr)
|
||||
{
|
||||
m_inst_trans = tr * m_inst_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const ClusterInstElement &other) const
|
||||
{
|
||||
return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const ClusterInstElement &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const ClusterInstElement &other) const
|
||||
{
|
||||
if (m_inst_cell_index != other.m_inst_cell_index) {
|
||||
return m_inst_cell_index < other.m_inst_cell_index;
|
||||
}
|
||||
if (! m_inst_trans.equal (other.m_inst_trans)) {
|
||||
return m_inst_trans.less (other.m_inst_trans);
|
||||
}
|
||||
return m_inst_prop_id < other.m_inst_prop_id;
|
||||
}
|
||||
|
||||
private:
|
||||
db::cell_index_type m_inst_cell_index;
|
||||
db::ICplxTrans m_inst_trans;
|
||||
db::properties_id_type m_inst_prop_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A connection to a cluster in a child instance
|
||||
*/
|
||||
class DB_PUBLIC ClusterInstance
|
||||
: public ClusterInstElement
|
||||
{
|
||||
public:
|
||||
ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id)
|
||||
: ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance (size_t id, const db::InstElement &inst_element)
|
||||
: ClusterInstElement (inst_element), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance (size_t id)
|
||||
: ClusterInstElement (), m_id (id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ClusterInstance ()
|
||||
: ClusterInstElement (), m_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cluster ID
|
||||
*/
|
||||
size_t id () const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const ClusterInstance &other) const
|
||||
{
|
||||
return m_id == other.m_id && ClusterInstElement::operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const ClusterInstance &other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const ClusterInstance &other) const
|
||||
{
|
||||
if (m_id != other.m_id) {
|
||||
return m_id < other.m_id;
|
||||
}
|
||||
return ClusterInstElement::operator< (other);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_id;
|
||||
};
|
||||
|
||||
typedef std::list<std::pair<ClusterInstance, ClusterInstance> > cluster_instance_pair_list_type;
|
||||
|
||||
inline bool equal_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b)
|
||||
|
|
@ -1040,7 +1118,7 @@ public:
|
|||
|
||||
private:
|
||||
typename local_clusters<T>::const_iterator m_lc_iter;
|
||||
typedef std::list<ClusterInstance> connections_type;
|
||||
typedef ClusterInstanceList connections_type;
|
||||
typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator m_x_iter, m_x_iter_end;
|
||||
};
|
||||
|
||||
|
|
@ -1060,7 +1138,7 @@ class DB_PUBLIC_TEMPLATE connected_clusters
|
|||
{
|
||||
public:
|
||||
typedef typename local_clusters<T>::id_type id_type;
|
||||
typedef std::list<ClusterInstance> connections_type;
|
||||
typedef ClusterInstanceList connections_type;
|
||||
typedef typename local_clusters<T>::box_type box_type;
|
||||
typedef connected_clusters_iterator<T> all_iterator;
|
||||
typedef typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator connections_iterator;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ SOURCES = \
|
|||
tlLongInt.cc \
|
||||
tlUniqueId.cc \
|
||||
tlList.cc \
|
||||
tlSList.cc \
|
||||
tlEquivalenceClusters.cc \
|
||||
tlUniqueName.cc \
|
||||
tlRecipe.cc \
|
||||
|
|
@ -115,6 +116,7 @@ HEADERS = \
|
|||
tlLongInt.h \
|
||||
tlUniqueId.h \
|
||||
tlList.h \
|
||||
tlSList.h \
|
||||
tlEquivalenceClusters.h \
|
||||
tlUniqueName.h \
|
||||
tlRecipe.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "tlSList.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 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_tlSList
|
||||
#define HDR_tlSList
|
||||
|
||||
#include "tlCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A simple single-linked list implementation
|
||||
*
|
||||
* This implementation supports:
|
||||
* - fast size
|
||||
* - push_back, push_front
|
||||
* - forward iterator, const_iterator
|
||||
* - splice
|
||||
* - pop_front
|
||||
* - clear
|
||||
* - empty
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
class slist
|
||||
{
|
||||
private:
|
||||
struct node_type
|
||||
{
|
||||
node_type (const T &_t) : next (0), t (_t) { }
|
||||
node_type (T &&_t) : next (0), t (_t) { }
|
||||
node_type *next;
|
||||
T t;
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
typedef std::forward_iterator_tag category;
|
||||
typedef T value_type;
|
||||
typedef T &reference;
|
||||
typedef T *pointer;
|
||||
|
||||
iterator (node_type *p = 0) : mp_p (p) { }
|
||||
iterator operator++ () { mp_p = mp_p->next; return *this; }
|
||||
|
||||
T *operator-> () const
|
||||
{
|
||||
return &mp_p->t;
|
||||
}
|
||||
|
||||
T &operator* () const
|
||||
{
|
||||
return mp_p->t;
|
||||
}
|
||||
|
||||
bool operator== (iterator other) const { return mp_p == other.mp_p; }
|
||||
bool operator!= (iterator other) const { return mp_p != other.mp_p; }
|
||||
|
||||
private:
|
||||
node_type *mp_p;
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
typedef std::forward_iterator_tag category;
|
||||
typedef const T value_type;
|
||||
typedef const T &reference;
|
||||
typedef const T *pointer;
|
||||
|
||||
const_iterator (const node_type *p = 0) : mp_p (p) { }
|
||||
const_iterator operator++ () { mp_p = mp_p->next; return *this; }
|
||||
|
||||
const T *operator-> () const
|
||||
{
|
||||
return &mp_p->t;
|
||||
}
|
||||
|
||||
const T &operator* () const
|
||||
{
|
||||
return mp_p->t;
|
||||
}
|
||||
|
||||
bool operator== (const_iterator other) const { return mp_p == other.mp_p; }
|
||||
bool operator!= (const_iterator other) const { return mp_p != other.mp_p; }
|
||||
|
||||
private:
|
||||
const node_type *mp_p;
|
||||
};
|
||||
|
||||
slist ()
|
||||
: mp_first (0), mp_last (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
slist (Iter from, Iter to)
|
||||
: mp_first (0), mp_last (0), m_size (0)
|
||||
{
|
||||
for (Iter i = from; i != to; ++i) {
|
||||
push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
slist (const slist<T> &other)
|
||||
: mp_first (0), mp_last (0), m_size (0)
|
||||
{
|
||||
for (auto i = other.begin (); i != other.end (); ++i) {
|
||||
push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
slist (slist<T> &&other)
|
||||
: mp_first (0), mp_last (0), m_size (0)
|
||||
{
|
||||
std::swap (mp_first, other.mp_first);
|
||||
std::swap (mp_last, other.mp_last);
|
||||
std::swap (m_size, other.m_size);
|
||||
}
|
||||
|
||||
slist<T> &operator= (const slist<T> &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear ();
|
||||
for (const_iterator i = other.begin (); i != other.end (); ++i) {
|
||||
push_back (*i);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
slist<T> &operator= (slist<T> &&other)
|
||||
{
|
||||
clear ();
|
||||
std::swap (mp_first, other.mp_first);
|
||||
std::swap (mp_last, other.mp_last);
|
||||
std::swap (m_size, other.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~slist ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
iterator begin ()
|
||||
{
|
||||
return iterator (mp_first);
|
||||
}
|
||||
|
||||
iterator end ()
|
||||
{
|
||||
return iterator (0);
|
||||
}
|
||||
|
||||
const_iterator begin () const
|
||||
{
|
||||
return const_iterator (mp_first);
|
||||
}
|
||||
|
||||
const_iterator end () const
|
||||
{
|
||||
return const_iterator (0);
|
||||
}
|
||||
|
||||
size_t size () const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool empty () const
|
||||
{
|
||||
return mp_first == 0;
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
while (! empty ()) {
|
||||
pop_front ();
|
||||
}
|
||||
}
|
||||
|
||||
void swap (slist<T> &other)
|
||||
{
|
||||
std::swap (mp_first, other.mp_first);
|
||||
std::swap (mp_last, other.mp_last);
|
||||
std::swap (m_size, other.m_size);
|
||||
}
|
||||
|
||||
void pop_front ()
|
||||
{
|
||||
if (mp_first) {
|
||||
node_type *n = mp_first;
|
||||
if (n == mp_last) {
|
||||
mp_first = mp_last = 0;
|
||||
} else {
|
||||
mp_first = mp_first->next;
|
||||
}
|
||||
delete n;
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
T &front ()
|
||||
{
|
||||
return mp_first->t;
|
||||
}
|
||||
|
||||
const T &front () const
|
||||
{
|
||||
return mp_first->t;
|
||||
}
|
||||
|
||||
T &back ()
|
||||
{
|
||||
return mp_last->t;
|
||||
}
|
||||
|
||||
const T &back () const
|
||||
{
|
||||
return mp_last->t;
|
||||
}
|
||||
|
||||
void push_front (const T &t)
|
||||
{
|
||||
push_front_impl (new node_type (t));
|
||||
}
|
||||
|
||||
void push_front (T &&t)
|
||||
{
|
||||
push_front_impl (new node_type (t));
|
||||
}
|
||||
|
||||
void push_back (const T &t)
|
||||
{
|
||||
push_back_impl (new node_type (t));
|
||||
}
|
||||
|
||||
void push_back (T &&t)
|
||||
{
|
||||
push_back_impl (new node_type (t));
|
||||
}
|
||||
|
||||
void splice (slist<T> &other)
|
||||
{
|
||||
if (! other.mp_first) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! mp_first) {
|
||||
mp_first = other.mp_first;
|
||||
} else {
|
||||
mp_last->next = other.mp_first;
|
||||
}
|
||||
|
||||
mp_last = other.mp_last;
|
||||
m_size += other.m_size;
|
||||
|
||||
other.mp_first = other.mp_last = 0;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
node_type *mp_first, *mp_last;
|
||||
size_t m_size;
|
||||
|
||||
void push_front_impl (node_type *n)
|
||||
{
|
||||
if (mp_first) {
|
||||
n->next = mp_first;
|
||||
mp_first = n;
|
||||
} else {
|
||||
mp_first = mp_last = n;
|
||||
}
|
||||
++m_size;
|
||||
}
|
||||
|
||||
void push_back_impl (node_type *n)
|
||||
{
|
||||
if (mp_last) {
|
||||
mp_last->next = n;
|
||||
mp_last = n;
|
||||
} else {
|
||||
mp_first = mp_last = n;
|
||||
}
|
||||
++m_size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 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
|
||||
|
||||
*/
|
||||
|
||||
#include "tlSList.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static size_t obj_count = 0;
|
||||
|
||||
struct MyClass1
|
||||
{
|
||||
MyClass1 (int _n) : n (_n) { ++obj_count; }
|
||||
MyClass1 (const MyClass1 &other) : n (other.n) { ++obj_count; }
|
||||
MyClass1 &operator= (const MyClass1 &other) { n = other.n; return *this; }
|
||||
~MyClass1 () { --obj_count; }
|
||||
int n;
|
||||
bool operator== (const MyClass1 &other) const { return n == other.n; }
|
||||
bool operator< (const MyClass1 &other) const { return n < other.n; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2s (const tl::slist<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::slist<C>::const_iterator i = l.begin (); i != l.end (); ++i) {
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2s_nc (tl::slist<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::slist<C>::iterator i = l.begin (); i != l.end (); ++i) {
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
TEST(1_Basic)
|
||||
{
|
||||
obj_count = 0;
|
||||
|
||||
{
|
||||
MyClass1 c1 (-1);
|
||||
tl::slist<MyClass1> l1, l2;
|
||||
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
|
||||
l1.push_back (MyClass1 (17));
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "17");
|
||||
|
||||
l1.push_back (MyClass1 (42));
|
||||
l2 = l1;
|
||||
tl::slist<MyClass1> l3 (l2);
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (2));
|
||||
EXPECT_EQ (l2s (l1), "17,42");
|
||||
|
||||
l1.pop_front ();
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "42");
|
||||
|
||||
l1.clear ();
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
|
||||
EXPECT_EQ (l2s (l2), "17,42");
|
||||
l2.pop_front ();
|
||||
EXPECT_EQ (l2s (l2), "42");
|
||||
|
||||
l3.push_back (MyClass1 (2));
|
||||
l3.push_front (MyClass1 (1));
|
||||
EXPECT_EQ (l2s (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2s_nc (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l3.size (), size_t (4));
|
||||
|
||||
l3.pop_front ();
|
||||
EXPECT_EQ (l2s (l3), "17,42,2");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
c1 = l3.front ();
|
||||
EXPECT_EQ (c1.n, 17);
|
||||
|
||||
c1 = l3.back ();
|
||||
EXPECT_EQ (c1.n, 2);
|
||||
|
||||
l3.pop_front ();
|
||||
EXPECT_EQ (l2s (l3), "42,2");
|
||||
EXPECT_EQ (l3.size (), size_t (2));
|
||||
|
||||
l3.push_back (MyClass1 (1));
|
||||
EXPECT_EQ (l2s (l3), "42,2,1");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
l3.swap (l2);
|
||||
EXPECT_EQ (l2s (l2), "42,2,1");
|
||||
EXPECT_EQ (l2s (l3), "42");
|
||||
|
||||
l1.clear ();
|
||||
l2.swap (l1);
|
||||
EXPECT_EQ (l2s (l1), "42,2,1");
|
||||
EXPECT_EQ (l2s (l2), "");
|
||||
|
||||
l1.clear ();
|
||||
l3.clear ();
|
||||
|
||||
l2.swap (l1);
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
EXPECT_EQ (l2s (l2), "");
|
||||
}
|
||||
|
||||
EXPECT_EQ (obj_count, size_t (0));
|
||||
}
|
||||
|
||||
TEST(2_SpliceAndMove)
|
||||
{
|
||||
obj_count = 0;
|
||||
|
||||
{
|
||||
tl::slist<MyClass1> l1, l2;
|
||||
|
||||
l1.splice (l2);
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
|
||||
l1.push_back (MyClass1 (17));
|
||||
l1.push_back (MyClass1 (42));
|
||||
|
||||
l1.splice (l2);
|
||||
EXPECT_EQ (l2s (l1), "17,42");
|
||||
EXPECT_EQ (l2s (l2), "");
|
||||
l2.splice (l1);
|
||||
EXPECT_EQ (l2s (l2), "17,42");
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
|
||||
l1.swap (l2);
|
||||
|
||||
l2.push_back (MyClass1 (2));
|
||||
l2.push_back (MyClass1 (1));
|
||||
|
||||
l1.splice (l2);
|
||||
EXPECT_EQ (l2s (l1), "17,42,2,1");
|
||||
EXPECT_EQ (l2s (l2), "");
|
||||
|
||||
l2 = std::move (l1);
|
||||
EXPECT_EQ (l2s (l2), "17,42,2,1");
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
|
||||
l1 = tl::slist<MyClass1> (std::move (l2));
|
||||
EXPECT_EQ (l2s (l1), "17,42,2,1");
|
||||
EXPECT_EQ (l2s (l2), "");
|
||||
}
|
||||
|
||||
EXPECT_EQ (obj_count, size_t (0));
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ SOURCES = \
|
|||
tlThreadsTests.cc \
|
||||
tlUniqueIdTests.cc \
|
||||
tlListTests.cc \
|
||||
tlSListTests.cc \
|
||||
tlEquivalenceClustersTests.cc \
|
||||
tlUniqueNameTests.cc \
|
||||
tlGlobPatternTests.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue