Merge pull request #1855 from KLayout/issue-1853

Issue 1853 (slow Cell#write any Layout#write with huge polygons)
This commit is contained in:
Matthias Köfferlein 2024-09-16 23:24:08 +02:00 committed by GitHub
commit ff708186ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 430 additions and 148 deletions

View File

@ -23,6 +23,7 @@
#include "dbPolygonGenerators.h"
#include "tlTimer.h"
#include <vector>
#include <deque>
@ -51,18 +52,18 @@ struct PGPoint
class PGPolyContour
{
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::iterator iterator;
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)
: 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_next = d.m_next;
m_last = d.m_last;
m_size = d.m_size;
}
return *this;
}
@ -86,14 +88,45 @@ public:
db::Point &front () { return m_contour.front (); }
const db::Point &back () const { 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 pop_back () { m_contour.pop_back (); }
void pop_front () { m_contour.pop_front (); }
iterator erase (iterator i) { return m_contour.erase (i); }
iterator insert (iterator i, const db::Point &p) { return m_contour.insert (i, p); }
void push_back (const db::Point &p)
{
m_contour.push_back (p);
++m_size;
}
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 (); }
size_t size () const { return m_contour.size (); }
size_t size () const { return m_size; }
void last (long n)
{
@ -127,23 +160,37 @@ public:
void clear ()
{
m_size = 0;
m_next = -1;
m_last = -1;
m_contour.clear ();
}
void erase (iterator from, iterator to)
void erase (iterator from, iterator to)
{
m_size -= std::distance (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>
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
size_t index_at = at - m_contour.begin ();
m_contour.insert (at, from, to);
return m_contour.begin () + index_at;
#else
return m_contour.insert (at, from, to);
#endif
}
private:
@ -151,10 +198,46 @@ private:
bool m_is_hole;
long m_next;
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;
}
class PGContourList
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
{
public:
PGContourList ()
@ -487,7 +570,7 @@ void PolygonGenerator::eliminate_hole ()
tl_assert (cprev.size () >= 2);
// 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::Point pprev (xprev, m_y);
@ -497,7 +580,7 @@ void PolygonGenerator::eliminate_hole ()
cc.is_hole (false);
cc.push_back (c.front ());
cc.push_back (c.begin ()[1]);
cc.push_back (*(c.begin () + 1));
if (pprev != cc.back ()) {
cc.push_back (pprev);
}
@ -506,7 +589,7 @@ void PolygonGenerator::eliminate_hole ()
}
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.insert (cprev.end (), c.end () - 2, c.end ());
@ -597,7 +680,7 @@ PolygonGenerator::join_contours (db::Coord x)
tl_assert (cprev.size () >= 2);
// 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::Point pprev (xprev, m_y);
@ -605,13 +688,13 @@ PolygonGenerator::join_contours (db::Coord x)
tl_assert (c2.size () >= 2);
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 ();
}
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 ();
} else {
cprev.push_front (cprev.back ());
@ -621,7 +704,7 @@ PolygonGenerator::join_contours (db::Coord x)
} else {
cprev.insert (cprev.end (), c1.begin (), c1.end ());
cprev.splice (cprev.end (), c1);
cprev.is_hole (false);
mp_contours->join (iprev, i1);
@ -666,9 +749,11 @@ PolygonGenerator::join_contours (db::Coord x)
// remove c1 from list of contours, join with c2
if (c2.is_hole ()) {
c2.insert (c2.end (), c1.begin () + 1, c1.end ());
c1.pop_front ();
c2.splice (c2.end (), c1);
} else {
c2.insert (c2.begin (), c1.begin (), c1.end () - 1);
c1.pop_back ();
c2.splice (c2.begin (), c1);
}
mp_contours->join (i2, i1);
@ -685,9 +770,11 @@ PolygonGenerator::join_contours (db::Coord x)
// remove c1 from list of contours, join with c2
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 {
c1.insert (c1.begin (), c2.begin (), c2.end () - 1);
c2.pop_back ();
c1.splice (c1.begin (), c2);
}
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
// cut lines collinear with contour edges
eprev = db::Edge (ins[-2], ins[-1]);
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (ins[-2], ins[-1]), m_y));
eprev = db::Edge (*(ins - 2), *(ins - 1));
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (*(ins - 2), *(ins - 1)), m_y));
#else
// 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);
// remove collinear edges along the cut line
ins[-1] = pprev;
while (ins - cprev.begin () > 1 && ins[-2].y () == m_y && ins[-1].y () == m_y) {
*(ins - 1) = pprev;
while (ins - 1 != cprev.begin () && (ins - 2)->y () == m_y && (ins - 1)->y () == m_y) {
ins = cprev.erase (ins - 1);
}
if ((c1.begin () + 1)->y () == m_y) {
ins = cprev.insert (ins, c1.begin () + 1, c1.end ());
ins += c1.size () - 1;
ins = ins + (c1.size () - 1);
} else {
ins = cprev.insert (ins, c1.begin (), c1.end ());
ins += c1.size ();
ins = ins + c1.size ();
}
ins = cprev.insert (ins, pprev);

View File

@ -109,16 +109,130 @@ private:
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>
class list_impl<C, false>
{
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 ()
{
m_head.mp_next = &m_back;
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 &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)
{
std::swap (m_head.mp_next, other.m_head.mp_next);
@ -196,14 +322,24 @@ public:
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)
@ -216,14 +352,24 @@ public:
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)
@ -269,7 +415,7 @@ protected:
private:
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;
if (! after) {
@ -281,9 +427,11 @@ private:
after_node->mp_next = new_obj;
new_obj->mp_prev = after_node;
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;
if (! before) {
@ -295,6 +443,8 @@ private:
before_node->mp_prev = new_obj;
new_obj->mp_next = before_node;
new_obj->mp_prev->mp_next = new_obj;
return new_obj;
}
void push_back_impl (C *new_obj, bool owned)
@ -313,6 +463,11 @@ class list_impl<C, true>
: public list_impl<C, false>
{
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>::push_back;
using list_impl<C, false>::pop_back;
@ -339,14 +494,52 @@ public:
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)
@ -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
*
@ -448,12 +575,10 @@ class list
: public list_impl<C, CanCopy>
{
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;
typedef typename list_impl<C, CanCopy>::iterator iterator;
typedef typename list_impl<C, CanCopy>::const_iterator const_iterator;
typedef typename list_impl<C, CanCopy>::reverse_iterator reverse_iterator;
typedef typename list_impl<C, CanCopy>::const_reverse_iterator const_reverse_iterator;
using list_impl<C, CanCopy>::first;
using list_impl<C, CanCopy>::last;

View File

@ -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__)
@ -94,24 +94,27 @@ static int64_t ms_time ()
clock_get_time(cclock, &mts);
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)
FILETIME ft;
GetSystemTimeAsFileTime (&ft);
static LARGE_INTEGER freq = { 0 };
uint64_t t = (uint64_t (ft.dwHighDateTime) << (sizeof (ft.dwHighDateTime) * 8)) | uint64_t (ft.dwLowDateTime);
t -= ft_to_epoch_offset;
if (freq.QuadPart == 0) {
QueryPerformanceFrequency (&freq);
tl_assert (freq.QuadPart > 0);
}
// FILETIME uses 100ns resolution, hence divide by 10000 to get ms:
return int64_t (t / 10000);
LARGE_INTEGER qpc;
QueryPerformanceCounter (&qpc);
return int64_t (double (qpc.QuadPart) / double (freq.QuadPart) * 1e9 + 0.5);
#else
timespec 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
}
@ -120,8 +123,8 @@ static int64_t ms_time ()
// Implementation of Timer
Timer::Timer ()
: m_user_ms (0), m_sys_ms (0), m_wall_ms (0),
m_user_ms_res (0), m_sys_ms_res (0), m_wall_ms_res (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_ns_res (0)
{
// ..
}
@ -142,7 +145,7 @@ Timer::start ()
m_sys_ms += (timer_t) ((clks.tms_stime + clks.tms_cstime) * clk2msec + 0.5);
#endif
m_wall_ms += ms_time ();
m_wall_ns += ns_time ();
}
void
@ -150,15 +153,15 @@ Timer::stop ()
{
m_user_ms = -m_user_ms;
m_sys_ms = -m_sys_ms;
m_wall_ms = -m_wall_ms;
m_wall_ns = -m_wall_ns;
start ();
m_user_ms_res = m_user_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_sys_ms = 0;
m_wall_ms = 0;
m_wall_ns = 0;
}
void
@ -166,20 +169,20 @@ Timer::take ()
{
timer_t user_ms = m_user_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_sys_ms = -m_sys_ms;
m_wall_ms = -m_wall_ms;
m_wall_ns = -m_wall_ns;
start ();
m_user_ms_res = m_user_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_sys_ms = sys_ms;
m_wall_ms = wall_ms;
m_wall_ns = wall_ns;
}
size_t
@ -288,20 +291,20 @@ SelfTimer::report () const
Clock::Clock (double s)
{
m_clock_ms = s * 1000.0;
m_clock_ns = s * 1e9;
}
double
Clock::seconds () const
{
return double (m_clock_ms) * 0.001;
return double (m_clock_ns) * 1e-9;
}
Clock
Clock::current ()
{
Clock c;
c.m_clock_ms += ms_time ();
c.m_clock_ns += ns_time ();
return c;
}

View File

@ -92,7 +92,7 @@ public:
*/
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 ();
private:
timer_t m_user_ms, m_sys_ms, m_wall_ms;
timer_t m_user_ms_res, m_sys_ms_res, m_wall_ms_res;
timer_t m_user_ms, m_sys_ms, m_wall_ns;
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
*/
Clock () : m_clock_ms (0)
Clock () : m_clock_ns (0)
{
// .. nothing yet ..
}
@ -196,7 +196,7 @@ public:
* @brief Copy constructor
*/
Clock (const Clock &d)
: m_clock_ms (d.m_clock_ms)
: m_clock_ns (d.m_clock_ns)
{
// .. nothing yet ..
}
@ -206,7 +206,7 @@ public:
*/
Clock &operator= (Clock d)
{
m_clock_ms = d.m_clock_ms;
m_clock_ns = d.m_clock_ns;
return *this;
}
@ -215,7 +215,7 @@ public:
*/
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
{
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)
{
m_clock_ms -= d.m_clock_ms;
m_clock_ns -= d.m_clock_ns;
return *this;
}
@ -264,7 +264,7 @@ public:
static Clock current ();
private:
timer_t m_clock_ms;
timer_t m_clock_ns;
};
} // namespace tl

View File

@ -403,3 +403,70 @@ TEST(2_BasicNoCopy)
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));
}