mirror of https://github.com/KLayout/klayout.git
Added an intrinsic linked list implementation.
This commit is contained in:
parent
509de593e6
commit
923e4075da
|
|
@ -42,7 +42,8 @@ SOURCES = \
|
|||
tlDeferredExecution.cc \
|
||||
tlUri.cc \
|
||||
tlLongInt.cc \
|
||||
tlUniqueId.cc
|
||||
tlUniqueId.cc \
|
||||
tlList.cc
|
||||
|
||||
HEADERS = \
|
||||
tlAlgorithm.h \
|
||||
|
|
@ -94,7 +95,8 @@ HEADERS = \
|
|||
tlDeferredExecution.h \
|
||||
tlUri.h \
|
||||
tlLongInt.h \
|
||||
tlUniqueId.h
|
||||
tlUniqueId.h \
|
||||
tlList.h
|
||||
|
||||
equals(HAVE_CURL, "1") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 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 "tlList.h"
|
||||
|
||||
// .. nothing yet ..
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 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_tlList
|
||||
#define HDR_tlList
|
||||
|
||||
#include "tlAssert.h"
|
||||
#include "tlTypeTraits.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
template <class C, class CanCopy> class list_impl;
|
||||
|
||||
/**
|
||||
* @brief A base class for objects that can be kept in the linked list
|
||||
*/
|
||||
template <class C>
|
||||
class list_node
|
||||
{
|
||||
public:
|
||||
list_node () : mp_next (0), mp_prev (0), m_owned (true) { }
|
||||
list_node (const list_node &) : mp_next (0), mp_prev (0), m_owned (true) { }
|
||||
list_node &operator= (const list_node &) { }
|
||||
|
||||
~list_node ()
|
||||
{
|
||||
unlink ();
|
||||
}
|
||||
|
||||
C *next ()
|
||||
{
|
||||
tl_assert (mp_next);
|
||||
return static_cast<C *> (mp_next->mp_next == 0 ? 0 : mp_next);
|
||||
}
|
||||
|
||||
const C *next () const
|
||||
{
|
||||
tl_assert (mp_next);
|
||||
return static_cast<const C *> (mp_next->mp_next == 0 ? 0 : mp_next);
|
||||
}
|
||||
|
||||
C *prev ()
|
||||
{
|
||||
tl_assert (mp_prev);
|
||||
return static_cast<C *> (mp_prev->mp_prev == 0 ? 0 : mp_prev);
|
||||
}
|
||||
|
||||
const C *prev () const
|
||||
{
|
||||
tl_assert (mp_prev);
|
||||
return static_cast<const C *> (mp_prev->mp_prev == 0 ? 0 : mp_prev);
|
||||
}
|
||||
|
||||
C *self ()
|
||||
{
|
||||
return static_cast<C *> (this);
|
||||
}
|
||||
|
||||
const C *self () const
|
||||
{
|
||||
return static_cast<const C *> (this);
|
||||
}
|
||||
|
||||
void unlink ()
|
||||
{
|
||||
if (mp_prev) {
|
||||
tl_assert (mp_prev->mp_next == this);
|
||||
mp_prev->mp_next = mp_next;
|
||||
}
|
||||
if (mp_next) {
|
||||
tl_assert (mp_next->mp_prev == this);
|
||||
mp_next->mp_prev = mp_prev;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Type, class CanCopy> friend class list_impl;
|
||||
template <class Type> friend class list;
|
||||
template <class Type> friend class list_iterator;
|
||||
template <class Type> friend class reverse_list_iterator;
|
||||
|
||||
list_node *mp_next, *mp_prev;
|
||||
bool m_owned;
|
||||
};
|
||||
|
||||
template <class C>
|
||||
class list_impl<C, tl::false_tag>
|
||||
{
|
||||
public:
|
||||
list_impl () : m_head (), m_back ()
|
||||
{
|
||||
m_head.mp_next = &m_back;
|
||||
m_back.mp_prev = &m_head;
|
||||
}
|
||||
|
||||
list_impl (const list_impl &) { tl_assert (false); }
|
||||
list_impl &operator= (const list_impl &) { tl_assert (false); }
|
||||
|
||||
~list_impl ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
while (! empty ()) {
|
||||
if (first ()->m_owned) {
|
||||
delete first ();
|
||||
} else {
|
||||
first ()->unlink ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool empty () const
|
||||
{
|
||||
return m_head.mp_next == &m_back;
|
||||
}
|
||||
|
||||
C *first ()
|
||||
{
|
||||
return ! empty () ? static_cast<C *> (m_head.mp_next) : 0;
|
||||
}
|
||||
|
||||
const C *first () const
|
||||
{
|
||||
return ! empty () ? static_cast<C *> (m_head.mp_next) : 0;
|
||||
}
|
||||
|
||||
C *last ()
|
||||
{
|
||||
return ! empty () ? static_cast<C *> (m_back.mp_prev) : 0;
|
||||
}
|
||||
|
||||
const C *last () const
|
||||
{
|
||||
return ! empty () ? static_cast<C *> (m_back.mp_prev) : 0;
|
||||
}
|
||||
|
||||
void pop_back ()
|
||||
{
|
||||
delete last ();
|
||||
}
|
||||
|
||||
void pop_front ()
|
||||
{
|
||||
delete first ();
|
||||
}
|
||||
|
||||
void insert (C *after, C *new_obj)
|
||||
{
|
||||
insert_impl (after, new_obj, true);
|
||||
}
|
||||
|
||||
void insert_before (C *before, C *new_obj)
|
||||
{
|
||||
insert_before_impl (before, new_obj, true);
|
||||
}
|
||||
|
||||
void push_back (C *new_obj)
|
||||
{
|
||||
push_back_impl (new_obj, true);
|
||||
}
|
||||
|
||||
void push_front (C *new_obj)
|
||||
{
|
||||
push_front_impl (new_obj, true);
|
||||
}
|
||||
|
||||
void insert (C *after, C &new_obj)
|
||||
{
|
||||
insert_impl (after, new_obj, false);
|
||||
}
|
||||
|
||||
void insert_before (C *before, C &new_obj)
|
||||
{
|
||||
insert_before_impl (before, new_obj, false);
|
||||
}
|
||||
|
||||
void push_back (C &new_obj)
|
||||
{
|
||||
push_back_impl (new_obj, false);
|
||||
}
|
||||
|
||||
void push_front (C &new_obj)
|
||||
{
|
||||
push_front_impl (new_obj, false);
|
||||
}
|
||||
|
||||
size_t size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (const C *p = first (); p; p = p->next ()) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
protected:
|
||||
list_node<C> &head ()
|
||||
{
|
||||
return m_head;
|
||||
}
|
||||
|
||||
const list_node<C> &head () const
|
||||
{
|
||||
return m_head;
|
||||
}
|
||||
|
||||
list_node<C> &back ()
|
||||
{
|
||||
return m_back;
|
||||
}
|
||||
|
||||
const list_node<C> &back () const
|
||||
{
|
||||
return m_back;
|
||||
}
|
||||
|
||||
private:
|
||||
list_node<C> m_head, m_back;
|
||||
|
||||
void insert_impl (C *after, C *new_obj, bool owned)
|
||||
{
|
||||
list_node<C> *after_node = after;
|
||||
if (! after) {
|
||||
after_node = &m_head;
|
||||
} else {
|
||||
after_node->m_owned = owned;
|
||||
}
|
||||
|
||||
new_obj->mp_next = after_node->mp_next;
|
||||
after_node->mp_next = new_obj;
|
||||
new_obj->mp_prev = after_node;
|
||||
new_obj->mp_next->mp_prev = new_obj;
|
||||
}
|
||||
|
||||
void insert_before_impl (C *before, C *new_obj, bool owned)
|
||||
{
|
||||
list_node<C> *before_node = before;
|
||||
if (! before) {
|
||||
before_node = &m_back;
|
||||
} else {
|
||||
before_node->m_owned = owned;
|
||||
}
|
||||
|
||||
new_obj->mp_prev = before_node->mp_prev;
|
||||
before_node->mp_prev = new_obj;
|
||||
new_obj->mp_next = before_node;
|
||||
new_obj->mp_prev->mp_next = new_obj;
|
||||
}
|
||||
|
||||
void push_back_impl (C *new_obj, bool owned)
|
||||
{
|
||||
insert_before_impl (0, new_obj, owned);
|
||||
}
|
||||
|
||||
void push_front_impl (C *new_obj, bool owned)
|
||||
{
|
||||
insert_impl (0, new_obj, owned);
|
||||
}
|
||||
};
|
||||
|
||||
template <class C>
|
||||
class list_impl<C, tl::true_tag>
|
||||
: public list_impl<C, tl::false_tag>
|
||||
{
|
||||
public:
|
||||
using list_impl<C, tl::false_tag>::insert;
|
||||
using list_impl<C, tl::false_tag>::push_back;
|
||||
using list_impl<C, tl::false_tag>::pop_back;
|
||||
using list_impl<C, tl::false_tag>::insert_before;
|
||||
using list_impl<C, tl::false_tag>::push_front;
|
||||
using list_impl<C, tl::false_tag>::pop_front;
|
||||
|
||||
list_impl () { }
|
||||
|
||||
list_impl (const list_impl &other)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
list_impl &operator= (const list_impl &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
list_impl<C, tl::false_tag>::clear ();
|
||||
for (const C *p = other.first (); p; p = p->next ()) {
|
||||
push_back (*p);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void insert (C *after, const C &obj)
|
||||
{
|
||||
insert (after, new C (obj));
|
||||
}
|
||||
|
||||
void insert_before (C *before, const C &obj)
|
||||
{
|
||||
insert_before (before, new C (obj));
|
||||
}
|
||||
|
||||
void push_back (const C &obj)
|
||||
{
|
||||
insert_before (0, new C (obj));
|
||||
}
|
||||
|
||||
void push_front (const C &obj)
|
||||
{
|
||||
insert (0, new C (obj));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* In contrast to std::list this implementation is based on derivation from
|
||||
* a common base class (list_node<C> where C is the type that needs to be
|
||||
* put into the list.
|
||||
*
|
||||
* The advantage of this approach is that the elements can unregister them
|
||||
* selves upon delete, there are no iterators involved in insert and delete
|
||||
* operations and each object knows it's followers and predecessors.
|
||||
*
|
||||
* @code
|
||||
* class MyClass : public tl::list_node<MyClass> { ... };
|
||||
*
|
||||
* tl::list<MyClass> list;
|
||||
* list.push_back (new MyClass ());
|
||||
*/
|
||||
template <class C>
|
||||
class list
|
||||
: public list_impl<C, typename tl::type_traits<C>::has_copy_constructor>
|
||||
{
|
||||
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;
|
||||
|
||||
using list_impl<C, typename tl::type_traits<C>::has_copy_constructor>::first;
|
||||
using list_impl<C, typename tl::type_traits<C>::has_copy_constructor>::last;
|
||||
using list_impl<C, typename tl::type_traits<C>::has_copy_constructor>::head;
|
||||
using list_impl<C, typename tl::type_traits<C>::has_copy_constructor>::back;
|
||||
|
||||
list () { }
|
||||
list (const list &other) : list_impl<C, typename tl::type_traits<C>::has_copy_constructor> (other) { }
|
||||
|
||||
list &operator= (const list &other)
|
||||
{
|
||||
list_impl<C, typename tl::type_traits<C>::has_copy_constructor>::operator= (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin ()
|
||||
{
|
||||
return iterator (static_cast <C *> (head ().mp_next));
|
||||
}
|
||||
|
||||
iterator end ()
|
||||
{
|
||||
return iterator (static_cast <C *> (&back ()));
|
||||
}
|
||||
|
||||
const_iterator begin () const
|
||||
{
|
||||
return const_iterator (static_cast <const C *> (head ().mp_next));
|
||||
}
|
||||
|
||||
const_iterator end () const
|
||||
{
|
||||
return const_iterator (static_cast <const C *> (&back ()));
|
||||
}
|
||||
|
||||
reverse_iterator rbegin ()
|
||||
{
|
||||
return reverse_iterator (static_cast <C *> (back ().mp_prev));
|
||||
}
|
||||
|
||||
reverse_iterator rend ()
|
||||
{
|
||||
return reverse_iterator (static_cast <C *> (&head ()));
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin () const
|
||||
{
|
||||
return const_reverse_iterator (static_cast <const C *> (back ().mp_prev));
|
||||
}
|
||||
|
||||
const_reverse_iterator rend () const
|
||||
{
|
||||
return const_reverse_iterator (static_cast <const C *> (&head ()));
|
||||
}
|
||||
|
||||
bool operator== (const list &other) const
|
||||
{
|
||||
const C *i1 = first ();
|
||||
const C *i2 = other.first ();
|
||||
while (i1 && i2) {
|
||||
if (! (*i1 == *i2)) {
|
||||
return false;
|
||||
}
|
||||
i1 = i1->next ();
|
||||
i2 = i2->next ();
|
||||
}
|
||||
return (i1 == 0 && i2 == 0);
|
||||
}
|
||||
|
||||
bool operator!= (const list &other) const
|
||||
{
|
||||
return !operator== (other);
|
||||
}
|
||||
|
||||
bool operator< (const list &other) const
|
||||
{
|
||||
const C *i1 = first ();
|
||||
const C *i2 = other.first ();
|
||||
while (i1 && i2) {
|
||||
if (! (*i1 == *i2)) {
|
||||
return *i1 < *i2;
|
||||
}
|
||||
i1 = i1->next ();
|
||||
i2 = i2->next ();
|
||||
}
|
||||
return ((i1 == 0) > (i2 == 0));
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 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 "tlList.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlString.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MyClass1 : public tl::list_node<MyClass1>
|
||||
{
|
||||
MyClass1 (int _n) : n (_n) { }
|
||||
int n;
|
||||
bool operator== (const MyClass1 &other) const { return n == other.n; }
|
||||
bool operator< (const MyClass1 &other) const { return n < other.n; }
|
||||
};
|
||||
|
||||
struct MyClass2 : public tl::list_node<MyClass2>
|
||||
{
|
||||
MyClass2 (int _n) : n (_n) { }
|
||||
int n;
|
||||
public:
|
||||
MyClass2 (const MyClass2 &other);
|
||||
MyClass2 &operator= (const MyClass2 &other);
|
||||
bool operator== (const MyClass2 &other) const { return n == other.n; }
|
||||
bool operator< (const MyClass2 &other) const { return n < other.n; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
template <>
|
||||
struct type_traits<MyClass2> : public tl::type_traits<void>
|
||||
{
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
};
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2s (const tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<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 l2sr (const tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::const_reverse_iterator i = l.rbegin (); i != l.rend (); ++i) {
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2sm (const tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::const_iterator i = l.end (); i != l.begin (); ) {
|
||||
--i;
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2srm (const tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::const_reverse_iterator i = l.rend (); i != l.rbegin (); ) {
|
||||
--i;
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2s_nc (tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::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 l2sr_nc (tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::reverse_iterator i = l.rbegin (); i != l.rend (); ++i) {
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2sm_nc (tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::iterator i = l.end (); i != l.begin (); ) {
|
||||
--i;
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static std::string l2srm_nc (tl::list<C> &l)
|
||||
{
|
||||
std::string x;
|
||||
for (typename tl::list<C>::reverse_iterator i = l.rend (); i != l.rbegin (); ) {
|
||||
--i;
|
||||
if (!x.empty ()) {
|
||||
x += ",";
|
||||
}
|
||||
x += tl::to_string (i->n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
TEST(1_Basic)
|
||||
{
|
||||
tl::list<MyClass1> l1, l2;
|
||||
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
EXPECT_EQ (l2sr (l1), "");
|
||||
|
||||
l1.push_back (new MyClass1 (17));
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "17");
|
||||
EXPECT_EQ (l2sr (l1), "17");
|
||||
|
||||
l1.push_back (MyClass1 (42));
|
||||
l2 = l1;
|
||||
tl::list<MyClass1> l3 (l2);
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (2));
|
||||
EXPECT_EQ (l2s (l1), "17,42");
|
||||
EXPECT_EQ (l2sr (l1), "42,17");
|
||||
|
||||
delete l1.first ();
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "42");
|
||||
EXPECT_EQ (l2sr (l1), "42");
|
||||
|
||||
l1.clear ();
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
EXPECT_EQ (l2sr (l1), "");
|
||||
|
||||
EXPECT_EQ (l2s (l2), "17,42");
|
||||
EXPECT_EQ (l2sr (l2), "42,17");
|
||||
l2.pop_back ();
|
||||
EXPECT_EQ (l2s (l2), "17");
|
||||
EXPECT_EQ (l2sr (l2), "17");
|
||||
|
||||
l3.push_back (new MyClass1 (2));
|
||||
l3.push_front (new MyClass1 (1));
|
||||
EXPECT_EQ (l2s (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2srm (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2sm (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2sr (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2s_nc (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2srm_nc (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2sm_nc (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2sr_nc (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l3.size (), size_t (4));
|
||||
|
||||
l3.pop_back ();
|
||||
EXPECT_EQ (l2s (l3), "1,17,42");
|
||||
EXPECT_EQ (l2sr (l3), "42,17,1");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
MyClass1 *c1;
|
||||
c1 = l3.first ();
|
||||
EXPECT_EQ (c1->n, 1);
|
||||
c1 = c1->next ();
|
||||
EXPECT_EQ (c1->n, 17);
|
||||
c1 = c1->next ();
|
||||
EXPECT_EQ (c1->n, 42);
|
||||
EXPECT_EQ (c1->next (), 0);
|
||||
|
||||
c1 = l3.last ();
|
||||
EXPECT_EQ (c1->n, 42);
|
||||
c1 = c1->prev ();
|
||||
EXPECT_EQ (c1->n, 17);
|
||||
c1 = c1->prev ();
|
||||
EXPECT_EQ (c1->n, 1);
|
||||
EXPECT_EQ (c1->prev (), 0);
|
||||
|
||||
l3.pop_front ();
|
||||
EXPECT_EQ (l2s (l3), "17,42");
|
||||
EXPECT_EQ (l2sr (l3), "42,17");
|
||||
EXPECT_EQ (l3.size (), size_t (2));
|
||||
|
||||
l3.push_back (new MyClass1 (1));
|
||||
EXPECT_EQ (l2s (l3), "17,42,1");
|
||||
EXPECT_EQ (l2sr (l3), "1,42,17");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
c1 = l3.first ()->next ();
|
||||
delete c1;
|
||||
EXPECT_EQ (l2s (l3), "17,1");
|
||||
EXPECT_EQ (l2sr (l3), "1,17");
|
||||
EXPECT_EQ (l3.size (), size_t (2));
|
||||
}
|
||||
|
||||
TEST(2_BasicNoCopy)
|
||||
{
|
||||
tl::list<MyClass2> l1, l2, l3;
|
||||
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
EXPECT_EQ (l2sr (l1), "");
|
||||
|
||||
l1.push_back (new MyClass2 (17));
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "17");
|
||||
EXPECT_EQ (l2sr (l1), "17");
|
||||
|
||||
l1.push_back (new MyClass2 (42));
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (2));
|
||||
EXPECT_EQ (l2s (l1), "17,42");
|
||||
EXPECT_EQ (l2sr (l1), "42,17");
|
||||
|
||||
delete l1.first ();
|
||||
EXPECT_EQ (l1.empty (), false);
|
||||
EXPECT_EQ (l1.size (), size_t (1));
|
||||
EXPECT_EQ (l2s (l1), "42");
|
||||
EXPECT_EQ (l2sr (l1), "42");
|
||||
|
||||
l1.clear ();
|
||||
EXPECT_EQ (l1.empty (), true);
|
||||
EXPECT_EQ (l1.size (), size_t (0));
|
||||
EXPECT_EQ (l2s (l1), "");
|
||||
EXPECT_EQ (l2sr (l1), "");
|
||||
|
||||
l2.push_back (new MyClass2 (17));
|
||||
l2.push_back (new MyClass2 (42));
|
||||
|
||||
EXPECT_EQ (l2s (l2), "17,42");
|
||||
EXPECT_EQ (l2sr (l2), "42,17");
|
||||
l2.pop_back ();
|
||||
EXPECT_EQ (l2s (l2), "17");
|
||||
EXPECT_EQ (l2sr (l2), "17");
|
||||
|
||||
EXPECT_EQ (l2 == l3, false);
|
||||
EXPECT_EQ (l2 != l3, true);
|
||||
EXPECT_EQ (l2 < l3, false);
|
||||
|
||||
l3.push_back (new MyClass2 (17));
|
||||
EXPECT_EQ (l2 == l3, true);
|
||||
EXPECT_EQ (l2 != l3, false);
|
||||
EXPECT_EQ (l2 < l3, false);
|
||||
|
||||
l3.push_back (new MyClass2 (42));
|
||||
EXPECT_EQ (l2 == l3, false);
|
||||
EXPECT_EQ (l2 != l3, true);
|
||||
EXPECT_EQ (l2 < l3, true);
|
||||
|
||||
l3.push_back (new MyClass2 (2));
|
||||
l3.push_front (new MyClass2 (1));
|
||||
EXPECT_EQ (l2 == l3, false);
|
||||
EXPECT_EQ (l2 != l3, true);
|
||||
EXPECT_EQ (l2 < l3, false);
|
||||
|
||||
EXPECT_EQ (l2s (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2srm (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2sm (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2sr (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2s_nc (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2srm_nc (l3), "1,17,42,2");
|
||||
EXPECT_EQ (l2sm_nc (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l2sr_nc (l3), "2,42,17,1");
|
||||
EXPECT_EQ (l3.size (), size_t (4));
|
||||
|
||||
l3.pop_back ();
|
||||
EXPECT_EQ (l2s (l3), "1,17,42");
|
||||
EXPECT_EQ (l2sr (l3), "42,17,1");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
MyClass2 *c1;
|
||||
c1 = l3.first ();
|
||||
EXPECT_EQ (c1->n, 1);
|
||||
c1 = c1->next ();
|
||||
EXPECT_EQ (c1->n, 17);
|
||||
c1 = c1->next ();
|
||||
EXPECT_EQ (c1->n, 42);
|
||||
EXPECT_EQ (c1->next (), 0);
|
||||
|
||||
c1 = l3.last ();
|
||||
EXPECT_EQ (c1->n, 42);
|
||||
c1 = c1->prev ();
|
||||
EXPECT_EQ (c1->n, 17);
|
||||
c1 = c1->prev ();
|
||||
EXPECT_EQ (c1->n, 1);
|
||||
EXPECT_EQ (c1->prev (), 0);
|
||||
|
||||
l3.pop_front ();
|
||||
EXPECT_EQ (l2s (l3), "17,42");
|
||||
EXPECT_EQ (l2sr (l3), "42,17");
|
||||
EXPECT_EQ (l3.size (), size_t (2));
|
||||
|
||||
l3.push_back (new MyClass2 (1));
|
||||
EXPECT_EQ (l2s (l3), "17,42,1");
|
||||
EXPECT_EQ (l2sr (l3), "1,42,17");
|
||||
EXPECT_EQ (l3.size (), size_t (3));
|
||||
|
||||
c1 = l3.first ()->next ();
|
||||
delete c1;
|
||||
EXPECT_EQ (l2s (l3), "17,1");
|
||||
EXPECT_EQ (l2sr (l3), "1,17");
|
||||
EXPECT_EQ (l3.size (), size_t (2));
|
||||
}
|
||||
|
|
@ -35,7 +35,8 @@ SOURCES = \
|
|||
tlHttpStream.cc \
|
||||
tlInt128Support.cc \
|
||||
tlLongInt.cc \
|
||||
tlUniqueIdTests.cc
|
||||
tlUniqueIdTests.cc \
|
||||
tlListTests.cc
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue