From 923e4075da9f135e1bdb1a84ae454975b7859625 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 31 Dec 2018 15:25:45 +0100 Subject: [PATCH] Added an intrinsic linked list implementation. --- src/tl/tl/tl.pro | 6 +- src/tl/tl/tlList.cc | 25 ++ src/tl/tl/tlList.h | 523 +++++++++++++++++++++++++++++++ src/tl/unit_tests/tlListTests.cc | 369 ++++++++++++++++++++++ src/tl/unit_tests/unit_tests.pro | 3 +- 5 files changed, 923 insertions(+), 3 deletions(-) create mode 100644 src/tl/tl/tlList.cc create mode 100644 src/tl/tl/tlList.h create mode 100644 src/tl/unit_tests/tlListTests.cc diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index 3805807d8..850bced12 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -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") { diff --git a/src/tl/tl/tlList.cc b/src/tl/tl/tlList.cc new file mode 100644 index 000000000..fa9c84732 --- /dev/null +++ b/src/tl/tl/tlList.cc @@ -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 .. diff --git a/src/tl/tl/tlList.h b/src/tl/tl/tlList.h new file mode 100644 index 000000000..226b89ff7 --- /dev/null +++ b/src/tl/tl/tlList.h @@ -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 + +namespace tl +{ + +template class list_impl; + +/** + * @brief A base class for objects that can be kept in the linked list + */ +template +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 (mp_next->mp_next == 0 ? 0 : mp_next); + } + + const C *next () const + { + tl_assert (mp_next); + return static_cast (mp_next->mp_next == 0 ? 0 : mp_next); + } + + C *prev () + { + tl_assert (mp_prev); + return static_cast (mp_prev->mp_prev == 0 ? 0 : mp_prev); + } + + const C *prev () const + { + tl_assert (mp_prev); + return static_cast (mp_prev->mp_prev == 0 ? 0 : mp_prev); + } + + C *self () + { + return static_cast (this); + } + + const C *self () const + { + return static_cast (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 friend class list_impl; + template friend class list; + template friend class list_iterator; + template friend class reverse_list_iterator; + + list_node *mp_next, *mp_prev; + bool m_owned; +}; + +template +class list_impl +{ +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 (m_head.mp_next) : 0; + } + + const C *first () const + { + return ! empty () ? static_cast (m_head.mp_next) : 0; + } + + C *last () + { + return ! empty () ? static_cast (m_back.mp_prev) : 0; + } + + const C *last () const + { + return ! empty () ? static_cast (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 &head () + { + return m_head; + } + + const list_node &head () const + { + return m_head; + } + + list_node &back () + { + return m_back; + } + + const list_node &back () const + { + return m_back; + } + +private: + list_node m_head, m_back; + + void insert_impl (C *after, C *new_obj, bool owned) + { + list_node *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 *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 list_impl + : public list_impl +{ +public: + using list_impl::insert; + using list_impl::push_back; + using list_impl::pop_back; + using list_impl::insert_before; + using list_impl::push_front; + using list_impl::pop_front; + + list_impl () { } + + list_impl (const list_impl &other) + { + operator= (other); + } + + list_impl &operator= (const list_impl &other) + { + if (this != &other) { + list_impl::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 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 (mp_p->mp_next); return *this; } + list_iterator operator-- () { mp_p = static_cast (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 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 (mp_p->mp_prev); return *this; } + reverse_list_iterator operator-- () { mp_p = static_cast (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 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 { ... }; + * + * tl::list list; + * list.push_back (new MyClass ()); + */ +template +class list + : public list_impl::has_copy_constructor> +{ +public: + typedef list_iterator iterator; + typedef list_iterator const_iterator; + typedef reverse_list_iterator reverse_iterator; + typedef reverse_list_iterator const_reverse_iterator; + + typedef C value_type; + + using list_impl::has_copy_constructor>::first; + using list_impl::has_copy_constructor>::last; + using list_impl::has_copy_constructor>::head; + using list_impl::has_copy_constructor>::back; + + list () { } + list (const list &other) : list_impl::has_copy_constructor> (other) { } + + list &operator= (const list &other) + { + list_impl::has_copy_constructor>::operator= (other); + return *this; + } + + iterator begin () + { + return iterator (static_cast (head ().mp_next)); + } + + iterator end () + { + return iterator (static_cast (&back ())); + } + + const_iterator begin () const + { + return const_iterator (static_cast (head ().mp_next)); + } + + const_iterator end () const + { + return const_iterator (static_cast (&back ())); + } + + reverse_iterator rbegin () + { + return reverse_iterator (static_cast (back ().mp_prev)); + } + + reverse_iterator rend () + { + return reverse_iterator (static_cast (&head ())); + } + + const_reverse_iterator rbegin () const + { + return const_reverse_iterator (static_cast (back ().mp_prev)); + } + + const_reverse_iterator rend () const + { + return const_reverse_iterator (static_cast (&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 diff --git a/src/tl/unit_tests/tlListTests.cc b/src/tl/unit_tests/tlListTests.cc new file mode 100644 index 000000000..f098aaa7c --- /dev/null +++ b/src/tl/unit_tests/tlListTests.cc @@ -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 (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 (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 : public tl::type_traits + { + typedef tl::false_tag has_copy_constructor; + }; +} + +template +static std::string l2s (const tl::list &l) +{ + std::string x; + for (typename tl::list::const_iterator i = l.begin (); i != l.end (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2sr (const tl::list &l) +{ + std::string x; + for (typename tl::list::const_reverse_iterator i = l.rbegin (); i != l.rend (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2sm (const tl::list &l) +{ + std::string x; + for (typename tl::list::const_iterator i = l.end (); i != l.begin (); ) { + --i; + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2srm (const tl::list &l) +{ + std::string x; + for (typename tl::list::const_reverse_iterator i = l.rend (); i != l.rbegin (); ) { + --i; + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2s_nc (tl::list &l) +{ + std::string x; + for (typename tl::list::iterator i = l.begin (); i != l.end (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2sr_nc (tl::list &l) +{ + std::string x; + for (typename tl::list::reverse_iterator i = l.rbegin (); i != l.rend (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2sm_nc (tl::list &l) +{ + std::string x; + for (typename tl::list::iterator i = l.end (); i != l.begin (); ) { + --i; + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2srm_nc (tl::list &l) +{ + std::string x; + for (typename tl::list::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 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 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 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)); +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index f10fc4e70..bd1680b9f 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -35,7 +35,8 @@ SOURCES = \ tlHttpStream.cc \ tlInt128Support.cc \ tlLongInt.cc \ - tlUniqueIdTests.cc + tlUniqueIdTests.cc \ + tlListTests.cc !equals(HAVE_QT, "0") {