mirror of https://github.com/KLayout/klayout.git
Merge pull request #1855 from KLayout/issue-1853
Issue 1853 (slow Cell#write any Layout#write with huge polygons)
This commit is contained in:
commit
ff708186ec
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "dbPolygonGenerators.h"
|
#include "dbPolygonGenerators.h"
|
||||||
|
#include "tlTimer.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
@ -51,18 +52,18 @@ struct PGPoint
|
||||||
class PGPolyContour
|
class PGPolyContour
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::deque <db::Point> contour_type;
|
typedef std::list <db::Point> contour_type;
|
||||||
typedef contour_type::const_iterator const_iterator;
|
typedef contour_type::const_iterator const_iterator;
|
||||||
typedef contour_type::iterator iterator;
|
typedef contour_type::iterator iterator;
|
||||||
|
|
||||||
PGPolyContour ()
|
PGPolyContour ()
|
||||||
: m_is_hole (false), m_next (-1), m_last (-1)
|
: m_is_hole (false), m_next (-1), m_last (-1), m_size (0)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
PGPolyContour (const PGPolyContour &d)
|
PGPolyContour (const PGPolyContour &d)
|
||||||
: m_contour (d.m_contour), m_is_hole (d.m_is_hole), m_next (d.m_next), m_last (d.m_last)
|
: m_contour (d.m_contour), m_is_hole (d.m_is_hole), m_next (d.m_next), m_last (d.m_last), m_size (d.m_size)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +75,7 @@ public:
|
||||||
m_is_hole = d.m_is_hole;
|
m_is_hole = d.m_is_hole;
|
||||||
m_next = d.m_next;
|
m_next = d.m_next;
|
||||||
m_last = d.m_last;
|
m_last = d.m_last;
|
||||||
|
m_size = d.m_size;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -86,14 +88,45 @@ public:
|
||||||
db::Point &front () { return m_contour.front (); }
|
db::Point &front () { return m_contour.front (); }
|
||||||
const db::Point &back () const { return m_contour.back (); }
|
const db::Point &back () const { return m_contour.back (); }
|
||||||
db::Point &back () { return m_contour.back (); }
|
db::Point &back () { return m_contour.back (); }
|
||||||
void push_back (const db::Point &p) { m_contour.push_back (p); }
|
|
||||||
void push_front (const db::Point &p) { m_contour.push_front (p); }
|
void push_back (const db::Point &p)
|
||||||
void pop_back () { m_contour.pop_back (); }
|
{
|
||||||
void pop_front () { m_contour.pop_front (); }
|
m_contour.push_back (p);
|
||||||
iterator erase (iterator i) { return m_contour.erase (i); }
|
++m_size;
|
||||||
iterator insert (iterator i, const db::Point &p) { return m_contour.insert (i, p); }
|
}
|
||||||
|
|
||||||
|
void push_front (const db::Point &p)
|
||||||
|
{
|
||||||
|
m_contour.push_front (p);
|
||||||
|
++m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back ()
|
||||||
|
{
|
||||||
|
m_contour.pop_back ();
|
||||||
|
--m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front ()
|
||||||
|
{
|
||||||
|
m_contour.pop_front ();
|
||||||
|
--m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase (iterator i)
|
||||||
|
{
|
||||||
|
--m_size;
|
||||||
|
return m_contour.erase (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert (iterator i, const db::Point &p)
|
||||||
|
{
|
||||||
|
++m_size;
|
||||||
|
return m_contour.insert (i, p);
|
||||||
|
}
|
||||||
|
|
||||||
bool empty () const { return m_contour.empty (); }
|
bool empty () const { return m_contour.empty (); }
|
||||||
size_t size () const { return m_contour.size (); }
|
size_t size () const { return m_size; }
|
||||||
|
|
||||||
void last (long n)
|
void last (long n)
|
||||||
{
|
{
|
||||||
|
|
@ -127,6 +160,7 @@ public:
|
||||||
|
|
||||||
void clear ()
|
void clear ()
|
||||||
{
|
{
|
||||||
|
m_size = 0;
|
||||||
m_next = -1;
|
m_next = -1;
|
||||||
m_last = -1;
|
m_last = -1;
|
||||||
m_contour.clear ();
|
m_contour.clear ();
|
||||||
|
|
@ -134,16 +168,29 @@ public:
|
||||||
|
|
||||||
void erase (iterator from, iterator to)
|
void erase (iterator from, iterator to)
|
||||||
{
|
{
|
||||||
|
m_size -= std::distance (from, to);
|
||||||
m_contour.erase (from, to);
|
m_contour.erase (from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splice (iterator at, PGPolyContour &contour)
|
||||||
|
{
|
||||||
|
m_size += contour.size ();
|
||||||
|
contour.m_size = 0;
|
||||||
|
m_contour.splice (at, contour.m_contour);
|
||||||
|
}
|
||||||
|
|
||||||
template <class I>
|
template <class I>
|
||||||
iterator insert (iterator at, I from, I to)
|
iterator insert (iterator at, I from, I to)
|
||||||
{
|
{
|
||||||
|
m_size += std::distance (from, to);
|
||||||
|
#if 0
|
||||||
// NOTE: in some STL m_contour.insert already returns the new iterator
|
// NOTE: in some STL m_contour.insert already returns the new iterator
|
||||||
size_t index_at = at - m_contour.begin ();
|
size_t index_at = at - m_contour.begin ();
|
||||||
m_contour.insert (at, from, to);
|
m_contour.insert (at, from, to);
|
||||||
return m_contour.begin () + index_at;
|
return m_contour.begin () + index_at;
|
||||||
|
#else
|
||||||
|
return m_contour.insert (at, from, to);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -151,8 +198,44 @@ private:
|
||||||
bool m_is_hole;
|
bool m_is_hole;
|
||||||
long m_next;
|
long m_next;
|
||||||
long m_last;
|
long m_last;
|
||||||
|
size_t m_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline
|
||||||
|
PGPolyContour::const_iterator operator+ (PGPolyContour::const_iterator i, int n)
|
||||||
|
{
|
||||||
|
while (n-- > 0) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
PGPolyContour::iterator operator+ (PGPolyContour::iterator i, int n)
|
||||||
|
{
|
||||||
|
while (n-- > 0) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
PGPolyContour::const_iterator operator- (PGPolyContour::const_iterator i, int n)
|
||||||
|
{
|
||||||
|
while (n-- > 0) {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
PGPolyContour::iterator operator- (PGPolyContour::iterator i, int n)
|
||||||
|
{
|
||||||
|
while (n-- > 0) {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
class PGContourList
|
class PGContourList
|
||||||
{
|
{
|
||||||
|
|
@ -487,7 +570,7 @@ void PolygonGenerator::eliminate_hole ()
|
||||||
tl_assert (cprev.size () >= 2);
|
tl_assert (cprev.size () >= 2);
|
||||||
|
|
||||||
// Compute intersection point with next edge
|
// Compute intersection point with next edge
|
||||||
db::Edge eprev (cprev.end ()[-2], cprev.back ());
|
db::Edge eprev (*(cprev.end () - 2), cprev.back ());
|
||||||
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
|
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
|
||||||
db::Point pprev (xprev, m_y);
|
db::Point pprev (xprev, m_y);
|
||||||
|
|
||||||
|
|
@ -497,7 +580,7 @@ void PolygonGenerator::eliminate_hole ()
|
||||||
|
|
||||||
cc.is_hole (false);
|
cc.is_hole (false);
|
||||||
cc.push_back (c.front ());
|
cc.push_back (c.front ());
|
||||||
cc.push_back (c.begin ()[1]);
|
cc.push_back (*(c.begin () + 1));
|
||||||
if (pprev != cc.back ()) {
|
if (pprev != cc.back ()) {
|
||||||
cc.push_back (pprev);
|
cc.push_back (pprev);
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +589,7 @@ void PolygonGenerator::eliminate_hole ()
|
||||||
}
|
}
|
||||||
|
|
||||||
cprev.back () = pprev;
|
cprev.back () = pprev;
|
||||||
while (cprev.size () > 2 && cprev.back ().y () == m_y && cprev.end ()[-2].y () == m_y && cprev.back ().x () <= cprev.end ()[-2].x ()) {
|
while (cprev.size () > 2 && cprev.back ().y () == m_y && (cprev.end () - 2)->y () == m_y && cprev.back ().x () <= (cprev.end () - 2)->x ()) {
|
||||||
cprev.pop_back ();
|
cprev.pop_back ();
|
||||||
}
|
}
|
||||||
cprev.insert (cprev.end (), c.end () - 2, c.end ());
|
cprev.insert (cprev.end (), c.end () - 2, c.end ());
|
||||||
|
|
@ -597,7 +680,7 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
tl_assert (cprev.size () >= 2);
|
tl_assert (cprev.size () >= 2);
|
||||||
|
|
||||||
// compute intersection point with next edge
|
// compute intersection point with next edge
|
||||||
db::Edge eprev (cprev.end ()[-2], cprev.back ());
|
db::Edge eprev (*(cprev.end () - 2), cprev.back ());
|
||||||
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
|
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
|
||||||
db::Point pprev (xprev, m_y);
|
db::Point pprev (xprev, m_y);
|
||||||
|
|
||||||
|
|
@ -605,13 +688,13 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
tl_assert (c2.size () >= 2);
|
tl_assert (c2.size () >= 2);
|
||||||
|
|
||||||
cprev.back () = pprev;
|
cprev.back () = pprev;
|
||||||
while (cprev.size () > 2 && cprev.back ().y () == m_y && cprev.end ()[-2].y () == m_y && cprev.back ().x () <= cprev.end ()[-2].x ()) {
|
while (cprev.size () > 2 && cprev.back ().y () == m_y && (cprev.end () - 2)->y () == m_y && cprev.back ().x () <= (cprev.end () - 2)->x ()) {
|
||||||
cprev.pop_back ();
|
cprev.pop_back ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iprev == i1) {
|
if (iprev == i1) {
|
||||||
|
|
||||||
if (cprev.begin ()->y () == m_y && cprev.begin ()[1].y () == m_y && cprev.front ().x () >= cprev.begin ()[1].x ()) {
|
if (cprev.front ().y () == m_y && (cprev.begin () + 1)->y () == m_y && cprev.front ().x () >= (cprev.begin () + 1)->x ()) {
|
||||||
cprev.front () = cprev.back ();
|
cprev.front () = cprev.back ();
|
||||||
} else {
|
} else {
|
||||||
cprev.push_front (cprev.back ());
|
cprev.push_front (cprev.back ());
|
||||||
|
|
@ -621,7 +704,7 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
cprev.insert (cprev.end (), c1.begin (), c1.end ());
|
cprev.splice (cprev.end (), c1);
|
||||||
cprev.is_hole (false);
|
cprev.is_hole (false);
|
||||||
|
|
||||||
mp_contours->join (iprev, i1);
|
mp_contours->join (iprev, i1);
|
||||||
|
|
@ -666,9 +749,11 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
|
|
||||||
// remove c1 from list of contours, join with c2
|
// remove c1 from list of contours, join with c2
|
||||||
if (c2.is_hole ()) {
|
if (c2.is_hole ()) {
|
||||||
c2.insert (c2.end (), c1.begin () + 1, c1.end ());
|
c1.pop_front ();
|
||||||
|
c2.splice (c2.end (), c1);
|
||||||
} else {
|
} else {
|
||||||
c2.insert (c2.begin (), c1.begin (), c1.end () - 1);
|
c1.pop_back ();
|
||||||
|
c2.splice (c2.begin (), c1);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_contours->join (i2, i1);
|
mp_contours->join (i2, i1);
|
||||||
|
|
@ -685,9 +770,11 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
|
|
||||||
// remove c1 from list of contours, join with c2
|
// remove c1 from list of contours, join with c2
|
||||||
if (c2.is_hole ()) { // yes! c2 is correct!
|
if (c2.is_hole ()) { // yes! c2 is correct!
|
||||||
c1.insert (c1.end (), c2.begin () + 1, c2.end ());
|
c2.pop_front ();
|
||||||
|
c1.splice (c1.end (), c2);
|
||||||
} else {
|
} else {
|
||||||
c1.insert (c1.begin (), c2.begin (), c2.end () - 1);
|
c2.pop_back ();
|
||||||
|
c1.splice (c1.begin (), c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_contours->join (i1, i2);
|
mp_contours->join (i1, i2);
|
||||||
|
|
@ -740,8 +827,8 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
// shallow analysis: insert the cutline at the end of the sequence - this may
|
// shallow analysis: insert the cutline at the end of the sequence - this may
|
||||||
// cut lines collinear with contour edges
|
// cut lines collinear with contour edges
|
||||||
|
|
||||||
eprev = db::Edge (ins[-2], ins[-1]);
|
eprev = db::Edge (*(ins - 2), *(ins - 1));
|
||||||
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (ins[-2], ins[-1]), m_y));
|
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (*(ins - 2), *(ins - 1)), m_y));
|
||||||
#else
|
#else
|
||||||
// deep analysis: determine insertion point: pick the one where the cutline is shortest
|
// deep analysis: determine insertion point: pick the one where the cutline is shortest
|
||||||
|
|
||||||
|
|
@ -763,17 +850,17 @@ PolygonGenerator::join_contours (db::Coord x)
|
||||||
db::Point pprev (xprev, m_y);
|
db::Point pprev (xprev, m_y);
|
||||||
|
|
||||||
// remove collinear edges along the cut line
|
// remove collinear edges along the cut line
|
||||||
ins[-1] = pprev;
|
*(ins - 1) = pprev;
|
||||||
while (ins - cprev.begin () > 1 && ins[-2].y () == m_y && ins[-1].y () == m_y) {
|
while (ins - 1 != cprev.begin () && (ins - 2)->y () == m_y && (ins - 1)->y () == m_y) {
|
||||||
ins = cprev.erase (ins - 1);
|
ins = cprev.erase (ins - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c1.begin () + 1)->y () == m_y) {
|
if ((c1.begin () + 1)->y () == m_y) {
|
||||||
ins = cprev.insert (ins, c1.begin () + 1, c1.end ());
|
ins = cprev.insert (ins, c1.begin () + 1, c1.end ());
|
||||||
ins += c1.size () - 1;
|
ins = ins + (c1.size () - 1);
|
||||||
} else {
|
} else {
|
||||||
ins = cprev.insert (ins, c1.begin (), c1.end ());
|
ins = cprev.insert (ins, c1.begin (), c1.end ());
|
||||||
ins += c1.size ();
|
ins = ins + c1.size ();
|
||||||
}
|
}
|
||||||
|
|
||||||
ins = cprev.insert (ins, pprev);
|
ins = cprev.insert (ins, pprev);
|
||||||
|
|
|
||||||
|
|
@ -109,16 +109,130 @@ private:
|
||||||
bool m_owned;
|
bool m_owned;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An iterator for the linked list
|
||||||
|
*/
|
||||||
|
template <class C>
|
||||||
|
class list_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::bidirectional_iterator_tag category;
|
||||||
|
typedef C value_type;
|
||||||
|
typedef C &reference;
|
||||||
|
typedef C *pointer;
|
||||||
|
|
||||||
|
list_iterator (C *p = 0) : mp_p (p) { }
|
||||||
|
list_iterator operator++ () { mp_p = static_cast<C *> (mp_p->mp_next); return *this; }
|
||||||
|
list_iterator operator-- () { mp_p = static_cast<C *> (mp_p->mp_prev); return *this; }
|
||||||
|
|
||||||
|
list_iterator operator++ (int)
|
||||||
|
{
|
||||||
|
list_iterator r = *this;
|
||||||
|
++*this;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterator operator-- (int)
|
||||||
|
{
|
||||||
|
list_iterator r = *this;
|
||||||
|
--*this;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
C *operator-> () const
|
||||||
|
{
|
||||||
|
return mp_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
C &operator* () const
|
||||||
|
{
|
||||||
|
return *mp_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (list_iterator other) const { return mp_p == other.mp_p; }
|
||||||
|
bool operator!= (list_iterator other) const { return mp_p != other.mp_p; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
C *mp_p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A reverse iterator for the linked list
|
||||||
|
*/
|
||||||
|
template <class C>
|
||||||
|
class reverse_list_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::bidirectional_iterator_tag category;
|
||||||
|
typedef C value_type;
|
||||||
|
typedef C &reference;
|
||||||
|
typedef C *pointer;
|
||||||
|
|
||||||
|
reverse_list_iterator (C *p = 0) : mp_p (p) { }
|
||||||
|
reverse_list_iterator operator++ () { mp_p = static_cast<C *> (mp_p->mp_prev); return *this; }
|
||||||
|
reverse_list_iterator operator-- () { mp_p = static_cast<C *> (mp_p->mp_next); return *this; }
|
||||||
|
|
||||||
|
reverse_list_iterator operator++ (int)
|
||||||
|
{
|
||||||
|
reverse_list_iterator r = *this;
|
||||||
|
++*this;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_list_iterator operator-- (int)
|
||||||
|
{
|
||||||
|
reverse_list_iterator r = *this;
|
||||||
|
--*this;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
C *operator-> () const
|
||||||
|
{
|
||||||
|
return mp_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
C &operator* () const
|
||||||
|
{
|
||||||
|
return *mp_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (reverse_list_iterator other) const { return mp_p == other.mp_p; }
|
||||||
|
bool operator!= (reverse_list_iterator other) const { return mp_p != other.mp_p; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
C *mp_p;
|
||||||
|
};
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
class list_impl<C, false>
|
class list_impl<C, false>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef list_iterator<C> iterator;
|
||||||
|
typedef list_iterator<const C> const_iterator;
|
||||||
|
typedef reverse_list_iterator<C> reverse_iterator;
|
||||||
|
typedef reverse_list_iterator<const C> const_reverse_iterator;
|
||||||
|
|
||||||
|
typedef C value_type;
|
||||||
|
|
||||||
list_impl () : m_head (), m_back ()
|
list_impl () : m_head (), m_back ()
|
||||||
{
|
{
|
||||||
m_head.mp_next = &m_back;
|
m_head.mp_next = &m_back;
|
||||||
m_back.mp_prev = &m_head;
|
m_back.mp_prev = &m_head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_impl (const list_impl &&other)
|
||||||
|
{
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_impl &operator= (const list_impl &&other)
|
||||||
|
{
|
||||||
|
if (&other != this) {
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
list_impl (const list_impl &) { tl_assert (false); }
|
list_impl (const list_impl &) { tl_assert (false); }
|
||||||
list_impl &operator= (const list_impl &) { tl_assert (false); return *this; }
|
list_impl &operator= (const list_impl &) { tl_assert (false); return *this; }
|
||||||
|
|
||||||
|
|
@ -143,6 +257,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erase (iterator i)
|
||||||
|
{
|
||||||
|
erase (i.operator-> ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase (iterator from, iterator to)
|
||||||
|
{
|
||||||
|
while (from != to) {
|
||||||
|
erase (from++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void swap (list_impl<C, false> &other)
|
void swap (list_impl<C, false> &other)
|
||||||
{
|
{
|
||||||
std::swap (m_head.mp_next, other.m_head.mp_next);
|
std::swap (m_head.mp_next, other.m_head.mp_next);
|
||||||
|
|
@ -196,14 +322,24 @@ public:
|
||||||
delete first ();
|
delete first ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert (C *after, C *new_obj)
|
C *insert (C *after, C *new_obj)
|
||||||
{
|
{
|
||||||
insert_impl (after, new_obj, true);
|
return insert_impl (after, new_obj, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before (C *before, C *new_obj)
|
iterator insert (iterator after, C *new_obj)
|
||||||
{
|
{
|
||||||
insert_before_impl (before, new_obj, true);
|
return iterator (insert (after.operator-> (), new_obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
C *insert_before (C *before, C *new_obj)
|
||||||
|
{
|
||||||
|
return insert_before_impl (before, new_obj, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert_before (iterator before, C *new_obj)
|
||||||
|
{
|
||||||
|
return iterator (insert_before_impl (before.operator-> (), new_obj, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back (C *new_obj)
|
void push_back (C *new_obj)
|
||||||
|
|
@ -216,14 +352,24 @@ public:
|
||||||
push_front_impl (new_obj, true);
|
push_front_impl (new_obj, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert (C *after, C &new_obj)
|
C *insert (C *after, C &new_obj)
|
||||||
{
|
{
|
||||||
insert_impl (after, &new_obj, false);
|
return insert_impl (after, &new_obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before (C *before, C &new_obj)
|
iterator insert (iterator after, C &new_obj)
|
||||||
{
|
{
|
||||||
insert_before_impl (before, &new_obj, false);
|
return iterator (insert_impl (after.operator-> (), &new_obj, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
C *insert_before (C *before, C &new_obj)
|
||||||
|
{
|
||||||
|
return insert_before_impl (before, &new_obj, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert_before (iterator before, C &new_obj)
|
||||||
|
{
|
||||||
|
return iterator (insert_before_impl (before.operator-> (), &new_obj, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back (C &new_obj)
|
void push_back (C &new_obj)
|
||||||
|
|
@ -269,7 +415,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
list_node<C> m_head, m_back;
|
list_node<C> m_head, m_back;
|
||||||
|
|
||||||
void insert_impl (C *after, C *new_obj, bool owned)
|
C *insert_impl (C *after, C *new_obj, bool owned)
|
||||||
{
|
{
|
||||||
list_node<C> *after_node = after;
|
list_node<C> *after_node = after;
|
||||||
if (! after) {
|
if (! after) {
|
||||||
|
|
@ -281,9 +427,11 @@ private:
|
||||||
after_node->mp_next = new_obj;
|
after_node->mp_next = new_obj;
|
||||||
new_obj->mp_prev = after_node;
|
new_obj->mp_prev = after_node;
|
||||||
new_obj->mp_next->mp_prev = new_obj;
|
new_obj->mp_next->mp_prev = new_obj;
|
||||||
|
|
||||||
|
return new_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before_impl (C *before, C *new_obj, bool owned)
|
C *insert_before_impl (C *before, C *new_obj, bool owned)
|
||||||
{
|
{
|
||||||
list_node<C> *before_node = before;
|
list_node<C> *before_node = before;
|
||||||
if (! before) {
|
if (! before) {
|
||||||
|
|
@ -295,6 +443,8 @@ private:
|
||||||
before_node->mp_prev = new_obj;
|
before_node->mp_prev = new_obj;
|
||||||
new_obj->mp_next = before_node;
|
new_obj->mp_next = before_node;
|
||||||
new_obj->mp_prev->mp_next = new_obj;
|
new_obj->mp_prev->mp_next = new_obj;
|
||||||
|
|
||||||
|
return new_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back_impl (C *new_obj, bool owned)
|
void push_back_impl (C *new_obj, bool owned)
|
||||||
|
|
@ -313,6 +463,11 @@ class list_impl<C, true>
|
||||||
: public list_impl<C, false>
|
: public list_impl<C, false>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef typename list_impl<C, false>::iterator iterator;
|
||||||
|
typedef typename list_impl<C, false>::const_iterator const_iterator;
|
||||||
|
typedef typename list_impl<C, false>::reverse_iterator reverse_iterator;
|
||||||
|
typedef typename list_impl<C, false>::const_reverse_iterator const_reverse_iterator;
|
||||||
|
|
||||||
using list_impl<C, false>::insert;
|
using list_impl<C, false>::insert;
|
||||||
using list_impl<C, false>::push_back;
|
using list_impl<C, false>::push_back;
|
||||||
using list_impl<C, false>::pop_back;
|
using list_impl<C, false>::pop_back;
|
||||||
|
|
@ -339,14 +494,52 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert (C *after, const C &obj)
|
C *insert (C *after, const C &obj)
|
||||||
{
|
{
|
||||||
insert (after, new C (obj));
|
return insert (after, new C (obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before (C *before, const C &obj)
|
iterator insert (iterator after, const C &obj)
|
||||||
{
|
{
|
||||||
insert_before (before, new C (obj));
|
return insert (after, new C (obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
iterator insert (iterator after, Iter from, Iter to)
|
||||||
|
{
|
||||||
|
if (from == to) {
|
||||||
|
return after;
|
||||||
|
} else {
|
||||||
|
iterator first = this->insert (after, *from++);
|
||||||
|
for (iterator next = first; from != to; ++from) {
|
||||||
|
next = this->insert (next, *from);
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C *insert_before (C *before, const C &obj)
|
||||||
|
{
|
||||||
|
return insert_before (before, new C (obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert_before (iterator before, const C &obj)
|
||||||
|
{
|
||||||
|
return insert_before (before, new C (obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
iterator insert_before (iterator before, Iter from, Iter to)
|
||||||
|
{
|
||||||
|
if (from == to) {
|
||||||
|
return before;
|
||||||
|
} else {
|
||||||
|
iterator first = this->insert_before (before, *from++);
|
||||||
|
for (iterator next = first; from != to; ++from) {
|
||||||
|
next = this->insert (next, *from);
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back (const C &obj)
|
void push_back (const C &obj)
|
||||||
|
|
@ -360,72 +553,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An iterator for the linked list
|
|
||||||
*/
|
|
||||||
template <class C>
|
|
||||||
class list_iterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::bidirectional_iterator_tag category;
|
|
||||||
typedef C value_type;
|
|
||||||
typedef C &reference;
|
|
||||||
typedef C *pointer;
|
|
||||||
|
|
||||||
list_iterator (C *p = 0) : mp_p (p) { }
|
|
||||||
list_iterator operator++ () { mp_p = static_cast<C *> (mp_p->mp_next); return *this; }
|
|
||||||
list_iterator operator-- () { mp_p = static_cast<C *> (mp_p->mp_prev); return *this; }
|
|
||||||
|
|
||||||
C *operator-> () const
|
|
||||||
{
|
|
||||||
return mp_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
C &operator* () const
|
|
||||||
{
|
|
||||||
return *mp_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator== (list_iterator other) const { return mp_p == other.mp_p; }
|
|
||||||
bool operator!= (list_iterator other) const { return mp_p != other.mp_p; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
C *mp_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A reverse iterator for the linked list
|
|
||||||
*/
|
|
||||||
template <class C>
|
|
||||||
class reverse_list_iterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::bidirectional_iterator_tag category;
|
|
||||||
typedef C value_type;
|
|
||||||
typedef C &reference;
|
|
||||||
typedef C *pointer;
|
|
||||||
|
|
||||||
reverse_list_iterator (C *p = 0) : mp_p (p) { }
|
|
||||||
reverse_list_iterator operator++ () { mp_p = static_cast<C *> (mp_p->mp_prev); return *this; }
|
|
||||||
reverse_list_iterator operator-- () { mp_p = static_cast<C *> (mp_p->mp_next); return *this; }
|
|
||||||
|
|
||||||
C *operator-> () const
|
|
||||||
{
|
|
||||||
return mp_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
C &operator* () const
|
|
||||||
{
|
|
||||||
return *mp_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator== (reverse_list_iterator other) const { return mp_p == other.mp_p; }
|
|
||||||
bool operator!= (reverse_list_iterator other) const { return mp_p != other.mp_p; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
C *mp_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A linked list
|
* @brief A linked list
|
||||||
*
|
*
|
||||||
|
|
@ -448,12 +575,10 @@ class list
|
||||||
: public list_impl<C, CanCopy>
|
: public list_impl<C, CanCopy>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef list_iterator<C> iterator;
|
typedef typename list_impl<C, CanCopy>::iterator iterator;
|
||||||
typedef list_iterator<const C> const_iterator;
|
typedef typename list_impl<C, CanCopy>::const_iterator const_iterator;
|
||||||
typedef reverse_list_iterator<C> reverse_iterator;
|
typedef typename list_impl<C, CanCopy>::reverse_iterator reverse_iterator;
|
||||||
typedef reverse_list_iterator<const C> const_reverse_iterator;
|
typedef typename list_impl<C, CanCopy>::const_reverse_iterator const_reverse_iterator;
|
||||||
|
|
||||||
typedef C value_type;
|
|
||||||
|
|
||||||
using list_impl<C, CanCopy>::first;
|
using list_impl<C, CanCopy>::first;
|
||||||
using list_impl<C, CanCopy>::last;
|
using list_impl<C, CanCopy>::last;
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,9 @@ void current_utc_time (struct timespec *ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// Gets the current time in ms from epoch
|
// Gets the current time in ns from epoch
|
||||||
|
|
||||||
static int64_t ms_time ()
|
static int64_t ns_time ()
|
||||||
{
|
{
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
|
||||||
|
|
@ -94,24 +94,27 @@ static int64_t ms_time ()
|
||||||
clock_get_time(cclock, &mts);
|
clock_get_time(cclock, &mts);
|
||||||
mach_port_deallocate(mach_task_self(), cclock);
|
mach_port_deallocate(mach_task_self(), cclock);
|
||||||
|
|
||||||
return int64_t (mts.tv_sec) * 1000 + int64_t (0.5 + mts.tv_nsec / 1.0e6);
|
return int64_t (mts.tv_sec) * 1000000000 + int64_t (mts.tv_nsec);
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
FILETIME ft;
|
static LARGE_INTEGER freq = { 0 };
|
||||||
GetSystemTimeAsFileTime (&ft);
|
|
||||||
|
|
||||||
uint64_t t = (uint64_t (ft.dwHighDateTime) << (sizeof (ft.dwHighDateTime) * 8)) | uint64_t (ft.dwLowDateTime);
|
if (freq.QuadPart == 0) {
|
||||||
t -= ft_to_epoch_offset;
|
QueryPerformanceFrequency (&freq);
|
||||||
|
tl_assert (freq.QuadPart > 0);
|
||||||
|
}
|
||||||
|
|
||||||
// FILETIME uses 100ns resolution, hence divide by 10000 to get ms:
|
LARGE_INTEGER qpc;
|
||||||
return int64_t (t / 10000);
|
QueryPerformanceCounter (&qpc);
|
||||||
|
|
||||||
|
return int64_t (double (qpc.QuadPart) / double (freq.QuadPart) * 1e9 + 0.5);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
timespec ts;
|
timespec ts;
|
||||||
clock_gettime (CLOCK_REALTIME, &ts);
|
clock_gettime (CLOCK_REALTIME, &ts);
|
||||||
return int64_t (ts.tv_sec) * 1000 + int64_t (0.5 + ts.tv_nsec / 1.0e6);
|
return int64_t (ts.tv_sec) * 1000000000 + int64_t (ts.tv_nsec);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -120,8 +123,8 @@ static int64_t ms_time ()
|
||||||
// Implementation of Timer
|
// Implementation of Timer
|
||||||
|
|
||||||
Timer::Timer ()
|
Timer::Timer ()
|
||||||
: m_user_ms (0), m_sys_ms (0), m_wall_ms (0),
|
: m_user_ms (0), m_sys_ms (0), m_wall_ns (0),
|
||||||
m_user_ms_res (0), m_sys_ms_res (0), m_wall_ms_res (0)
|
m_user_ms_res (0), m_sys_ms_res (0), m_wall_ns_res (0)
|
||||||
{
|
{
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +145,7 @@ Timer::start ()
|
||||||
m_sys_ms += (timer_t) ((clks.tms_stime + clks.tms_cstime) * clk2msec + 0.5);
|
m_sys_ms += (timer_t) ((clks.tms_stime + clks.tms_cstime) * clk2msec + 0.5);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_wall_ms += ms_time ();
|
m_wall_ns += ns_time ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -150,15 +153,15 @@ Timer::stop ()
|
||||||
{
|
{
|
||||||
m_user_ms = -m_user_ms;
|
m_user_ms = -m_user_ms;
|
||||||
m_sys_ms = -m_sys_ms;
|
m_sys_ms = -m_sys_ms;
|
||||||
m_wall_ms = -m_wall_ms;
|
m_wall_ns = -m_wall_ns;
|
||||||
start ();
|
start ();
|
||||||
|
|
||||||
m_user_ms_res = m_user_ms;
|
m_user_ms_res = m_user_ms;
|
||||||
m_sys_ms_res = m_sys_ms;
|
m_sys_ms_res = m_sys_ms;
|
||||||
m_wall_ms_res = m_wall_ms;
|
m_wall_ns_res = m_wall_ns;
|
||||||
m_user_ms = 0;
|
m_user_ms = 0;
|
||||||
m_sys_ms = 0;
|
m_sys_ms = 0;
|
||||||
m_wall_ms = 0;
|
m_wall_ns = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -166,20 +169,20 @@ Timer::take ()
|
||||||
{
|
{
|
||||||
timer_t user_ms = m_user_ms;
|
timer_t user_ms = m_user_ms;
|
||||||
timer_t sys_ms = m_sys_ms;
|
timer_t sys_ms = m_sys_ms;
|
||||||
timer_t wall_ms = m_wall_ms;
|
timer_t wall_ns = m_wall_ns;
|
||||||
|
|
||||||
m_user_ms = -m_user_ms;
|
m_user_ms = -m_user_ms;
|
||||||
m_sys_ms = -m_sys_ms;
|
m_sys_ms = -m_sys_ms;
|
||||||
m_wall_ms = -m_wall_ms;
|
m_wall_ns = -m_wall_ns;
|
||||||
start ();
|
start ();
|
||||||
|
|
||||||
m_user_ms_res = m_user_ms;
|
m_user_ms_res = m_user_ms;
|
||||||
m_sys_ms_res = m_sys_ms;
|
m_sys_ms_res = m_sys_ms;
|
||||||
m_wall_ms_res = m_wall_ms;
|
m_wall_ns_res = m_wall_ns;
|
||||||
|
|
||||||
m_user_ms = user_ms;
|
m_user_ms = user_ms;
|
||||||
m_sys_ms = sys_ms;
|
m_sys_ms = sys_ms;
|
||||||
m_wall_ms = wall_ms;
|
m_wall_ns = wall_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
|
@ -288,20 +291,20 @@ SelfTimer::report () const
|
||||||
|
|
||||||
Clock::Clock (double s)
|
Clock::Clock (double s)
|
||||||
{
|
{
|
||||||
m_clock_ms = s * 1000.0;
|
m_clock_ns = s * 1e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
Clock::seconds () const
|
Clock::seconds () const
|
||||||
{
|
{
|
||||||
return double (m_clock_ms) * 0.001;
|
return double (m_clock_ns) * 1e-9;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clock
|
Clock
|
||||||
Clock::current ()
|
Clock::current ()
|
||||||
{
|
{
|
||||||
Clock c;
|
Clock c;
|
||||||
c.m_clock_ms += ms_time ();
|
c.m_clock_ns += ns_time ();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double sec_wall () const
|
double sec_wall () const
|
||||||
{
|
{
|
||||||
return (double (m_wall_ms_res) * 0.001);
|
return (double (m_wall_ns_res) * 1e-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -101,8 +101,8 @@ public:
|
||||||
static size_t memory_size ();
|
static size_t memory_size ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
timer_t m_user_ms, m_sys_ms, m_wall_ms;
|
timer_t m_user_ms, m_sys_ms, m_wall_ns;
|
||||||
timer_t m_user_ms_res, m_sys_ms_res, m_wall_ms_res;
|
timer_t m_user_ms_res, m_sys_ms_res, m_wall_ns_res;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,7 +182,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor: construct a clock object pointing to an arbitrary value
|
* @brief Default constructor: construct a clock object pointing to an arbitrary value
|
||||||
*/
|
*/
|
||||||
Clock () : m_clock_ms (0)
|
Clock () : m_clock_ns (0)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +196,7 @@ public:
|
||||||
* @brief Copy constructor
|
* @brief Copy constructor
|
||||||
*/
|
*/
|
||||||
Clock (const Clock &d)
|
Clock (const Clock &d)
|
||||||
: m_clock_ms (d.m_clock_ms)
|
: m_clock_ns (d.m_clock_ns)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +206,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Clock &operator= (Clock d)
|
Clock &operator= (Clock d)
|
||||||
{
|
{
|
||||||
m_clock_ms = d.m_clock_ms;
|
m_clock_ns = d.m_clock_ns;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +215,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool operator== (Clock d) const
|
bool operator== (Clock d) const
|
||||||
{
|
{
|
||||||
return m_clock_ms == d.m_clock_ms;
|
return m_clock_ns == d.m_clock_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -231,7 +231,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool operator< (Clock d) const
|
bool operator< (Clock d) const
|
||||||
{
|
{
|
||||||
return m_clock_ms < d.m_clock_ms;
|
return m_clock_ns < d.m_clock_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -239,7 +239,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Clock &operator-= (Clock d)
|
Clock &operator-= (Clock d)
|
||||||
{
|
{
|
||||||
m_clock_ms -= d.m_clock_ms;
|
m_clock_ns -= d.m_clock_ns;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ public:
|
||||||
static Clock current ();
|
static Clock current ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
timer_t m_clock_ms;
|
timer_t m_clock_ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tl
|
} // namespace tl
|
||||||
|
|
|
||||||
|
|
@ -403,3 +403,70 @@ TEST(2_BasicNoCopy)
|
||||||
|
|
||||||
EXPECT_EQ (obj_count, size_t (0)); // mc2 gone as well
|
EXPECT_EQ (obj_count, size_t (0)); // mc2 gone as well
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(3_Insert)
|
||||||
|
{
|
||||||
|
obj_count = 0;
|
||||||
|
|
||||||
|
tl::list<MyClass1> l1;
|
||||||
|
tl::list<MyClass1>::iterator i1;
|
||||||
|
|
||||||
|
EXPECT_EQ (l1.empty (), true);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (0));
|
||||||
|
EXPECT_EQ (l2s (l1), "");
|
||||||
|
|
||||||
|
l1.push_back (MyClass1 (42));
|
||||||
|
EXPECT_EQ (l2s (l1), "42");
|
||||||
|
EXPECT_EQ (l1.size (), size_t (1));
|
||||||
|
|
||||||
|
i1 = l1.insert_before (l1.end (), MyClass1 (17));
|
||||||
|
EXPECT_EQ (l2s (l1), "42,17");
|
||||||
|
EXPECT_EQ (i1->n, 17);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (2));
|
||||||
|
|
||||||
|
i1 = l1.insert_before (i1, MyClass1 (11));
|
||||||
|
EXPECT_EQ (l2s (l1), "42,11,17");
|
||||||
|
EXPECT_EQ (i1->n, 11);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (3));
|
||||||
|
|
||||||
|
i1 = l1.insert (i1, MyClass1 (12));
|
||||||
|
EXPECT_EQ (l2s (l1), "42,11,12,17");
|
||||||
|
EXPECT_EQ (i1->n, 12);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (4));
|
||||||
|
|
||||||
|
MyClass1 arr[3] = { MyClass1 (1), MyClass1 (2), MyClass1 (3) };
|
||||||
|
|
||||||
|
i1 = l1.insert (i1, arr + 0, arr + 0);
|
||||||
|
EXPECT_EQ (l2s (l1), "42,11,12,17");
|
||||||
|
EXPECT_EQ (i1->n, 12);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (4));
|
||||||
|
|
||||||
|
i1 = l1.insert (i1, arr + 0, arr + 3);
|
||||||
|
EXPECT_EQ (l2s (l1), "42,11,12,1,2,3,17");
|
||||||
|
EXPECT_EQ (i1->n, 1);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (7));
|
||||||
|
|
||||||
|
l1.clear ();
|
||||||
|
l1.push_back (MyClass1 (42));
|
||||||
|
i1 = l1.insert_before (l1.end (), MyClass1 (17));
|
||||||
|
EXPECT_EQ (l2s (l1), "42,17");
|
||||||
|
EXPECT_EQ (i1->n, 17);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (2));
|
||||||
|
|
||||||
|
i1 = l1.insert_before (i1, arr + 0, arr + 0);
|
||||||
|
EXPECT_EQ (l2s (l1), "42,17");
|
||||||
|
EXPECT_EQ (i1->n, 17);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (2));
|
||||||
|
|
||||||
|
i1 = l1.insert_before (i1, arr + 0, arr + 3);
|
||||||
|
EXPECT_EQ (l2s (l1), "42,1,2,3,17");
|
||||||
|
EXPECT_EQ (i1->n, 1);
|
||||||
|
EXPECT_EQ (l1.size (), size_t (5));
|
||||||
|
|
||||||
|
// test erase range
|
||||||
|
l1.erase (i1, l1.end ());
|
||||||
|
EXPECT_EQ (l2s (l1), "42");
|
||||||
|
EXPECT_EQ (l1.size (), size_t (1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue