Return-Path: Delivered-To: apmail-incubator-qpid-commits-archive@locus.apache.org Received: (qmail 96778 invoked from network); 19 Feb 2008 22:34:15 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 19 Feb 2008 22:34:15 -0000 Received: (qmail 94578 invoked by uid 500); 19 Feb 2008 22:34:09 -0000 Delivered-To: apmail-incubator-qpid-commits-archive@incubator.apache.org Received: (qmail 94568 invoked by uid 500); 19 Feb 2008 22:34:09 -0000 Mailing-List: contact qpid-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: qpid-dev@incubator.apache.org Delivered-To: mailing list qpid-commits@incubator.apache.org Received: (qmail 94559 invoked by uid 99); 19 Feb 2008 22:34:09 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 19 Feb 2008 14:34:09 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 19 Feb 2008 22:33:37 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 231F51A9832; Tue, 19 Feb 2008 14:33:46 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r629253 - in /incubator/qpid/trunk/qpid/cpp/src: Makefile.am qpid/IList.h qpid/ISList.h qpid/pointer_to_other.h tests/IList.cpp tests/ISList.cpp tests/Makefile.am Date: Tue, 19 Feb 2008 22:33:32 -0000 To: qpid-commits@incubator.apache.org From: aconway@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080219223346.231F51A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: aconway Date: Tue Feb 19 14:33:29 2008 New Revision: 629253 URL: http://svn.apache.org/viewvc?rev=629253&view=rev Log: STL-style intrsive linked lists, single (ISList) and double (IList) Added: incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h (with props) incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h (with props) incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp (with props) Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am incubator/qpid/trunk/qpid/cpp/src/qpid/IList.h incubator/qpid/trunk/qpid/cpp/src/tests/IList.cpp incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/Makefile.am?rev=629253&r1=629252&r2=629253&view=diff ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/Makefile.am (original) +++ incubator/qpid/trunk/qpid/cpp/src/Makefile.am Tue Feb 19 14:33:29 2008 @@ -145,7 +145,9 @@ qpid/log/Options.cpp \ qpid/log/Selector.cpp \ qpid/log/Statement.cpp \ - qpid/IList.h + qpid/IList.h \ + qpid/ISList.h \ + qpid/pointer_to_other.h libqpidbroker_la_LIBADD = libqpidcommon.la -lboost_iostreams libqpidbroker_la_SOURCES = \ Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/IList.h URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/IList.h?rev=629253&r1=629252&r2=629253&view=diff ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/qpid/IList.h (original) +++ incubator/qpid/trunk/qpid/cpp/src/qpid/IList.h Tue Feb 19 14:33:29 2008 @@ -22,170 +22,174 @@ * */ -#include -#include -#include -#include +#include "ISList.h" namespace qpid { -template class IList; +template class IList; -/** - * Base class providing links for a node in an IList. - * - * Derived classes can inheirt multiple IListNode bases provided each - * has a unique value for N. This allows objects to be linked in - * multiple independent lists. For example: - * - * @code - * class Foo : public IListNode<0>, public IListNode<1> {}; - * IList - uses the 0 links - * IList - uses the 1 links - *@endcode - * - *@param T The derived class. - *@param N ID for multiple inheritance. +/** Base class for values (nodes) in an IList. + *@param raw or smart-pointer type to use for the "next" pointer. + * Using a smart pointer like shared_ptr or intrusive_ptr + * will automate memory management. */ -template class IListNode : public virtual RefCounted { - intrusive_ptr prev; - intrusive_ptr next; - void insert(IListNode*); - void erase(); - virtual T* self() const { // Virutal so anchor can hide. - return boost::polymorphic_downcast(const_cast(this)); - } - friend class IList; +template class IListNode { public: - typedef IList IListType; + typedef Pointer pointer; + typedef typename Pointee::type NodeType; + typedef typename pointer_to_other::type const_pointer; - IListNode(IListNode* p=0) : prev(p), next(p) {} - T* getNext() { return next ? next->self() : 0; } - T* getPrev() { return prev ? prev->self() : 0; } - const T* getNext() const { return next ? next->self() : 0; } - const T* getPrev() const { return prev ? prev->self() : 0; } + protected: + IListNode() : prev() {} + IListNode(const IListNode&) {} // Don't copy next/prev pointers + + pointer getNext() { return next; } + const_pointer getNext() const { return next; } + pointer getPrev() { return prev; } + const_pointer getPrev() const { return prev; } + + private: + pointer prev, next; + friend class IList; }; + /** - * Intrusive doubly linked list of reference counted nodes. + * Intrusive doubly-linked list. + * + * Provides bidirectional iterator and constant time insertion + * at front and back. + * + * The list itself performs no memory management. Use a smart pointer + * as the pointer type (e.g. intrusive_ptr, shared_ptr) for automated + * memory management. + * + * Unlike standard containers insert(), push_front() and push_back() + * take const pointer& rather than const value_type&. + * + * Iterators can be converted to the pointer type. + * + * Noncopyable - intrusively linked nodes cannot be shared between + * lists. Does provide swap() * - *@param T must inherit from IListNode - *@param N Identifies which links to use. @see IListNode. + * @param Node value type for the list, must derive from ISListNode<>. */ -template class IList { - private: - typedef IListNode Node; - - template - class Iterator : - public boost::iterator_facade, R, boost::bidirectional_traversal_tag> - { - Node* ptr; // Iterators do not own their pointees. - void increment() { assert(ptr); ptr = ptr->next.get(); } - void decrement() { assert(ptr); ptr = ptr->prev.get(); } - R& dereference() const { assert(ptr); return *boost::polymorphic_downcast(ptr); } - bool equal(const Iterator& x) const { return ptr == x.ptr; } - - Node* cast(const Node* p) { return const_cast(p); } - explicit Iterator(const Node* p=0) : ptr(cast(p)) {} - explicit Iterator(const T* p=0) : ptr(cast(p)) {} - - friend class boost::iterator_core_access; - friend class IList; - - public: - template Iterator(const Iterator& x) : ptr(x.ptr) {} - }; - +template class IList { + template class Iterator; public: - IList() {} - ~IList() { clear(); anchor.erase(); } - typedef size_t size_type; - typedef T value_type; - /// pointer type is an intrusive_ptr - typedef intrusive_ptr pointer; - /// pointer type is an intrusive_ptr - typedef intrusive_ptr const_pointer; + typedef Node value_type; + typedef typename Node::pointer pointer; + typedef typename Node::const_pointer const_pointer; typedef value_type& reference; typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; typedef Iterator iterator; typedef Iterator const_iterator; - iterator begin() { return iterator(anchor.next.get()); } - iterator end() { return iterator(&anchor); } - const_iterator begin() const { return const_iterator(anchor.next.get()); } - const_iterator end() const { return const_iterator(&anchor); } - /// Iterator to the last element or end() if empty - iterator last() { return iterator(anchor.prev.get()); } - /// Iterator to the last element or end() if empty - const_iterator last() const { return const_iterator(anchor.prev.get()); } - - /// Note: takes a non-const reference, unlike standard containers. - void insert(iterator pos, reference x) { x.Node::insert(pos.ptr); } - void insert(iterator pos, pointer x) { x->Node::insert(pos.ptr); } - void erase(iterator pos) { pos.ptr->erase(); } - void swap(IList &x) { anchor.swap(x.anchor); } - - reference back() { assert(!empty()); return *last(); } - const_reference back() const { assert(!empty()); return *last(); } - void pop_back() { assert(!empty()); erase(last()); } - /// Note: takes a non-const reference, unlike standard containers. - void push_back(reference x) { insert(end(), x); } - void push_back(pointer x) { insert(end(), x); } - - reference front() { assert(!empty()); return *begin(); } - const_reference front() const { assert(!empty()); return *begin(); } - void pop_front() { assert(!empty()); erase(begin()); } - /// Note: takes a non-const reference, unlike standard containers. - void push_front(reference x) { insert(begin(), x); } - void push_front(pointer x) { insert(begin(), x); } + IList() : begin_(), last_() {} + + iterator begin() { return begin_; } + const_iterator begin() const { return begin_; } + iterator end() { return 0; } + const_iterator end() const { return 0; } bool empty() const { return begin() == end(); } - void clear() { while (!empty()) { pop_front(); } } size_type size() const { - size_type s=0; - for (const_iterator i = begin(); i != end(); ++i) ++s; + int s = 0; + for (const_iterator i=begin(); i != end(); ++i) + ++s; return s; } + + void swap(IList &x) { swap(begin_, x.begin_); swap(last_, x.last_); } + + iterator insert(iterator i, const pointer& p) { + if (empty()) { + begin_ = last_ = p; + insert(0, p, 0); + } + else if (i) { + insert(i->prev, p, i); + if (i == begin_) --begin_; + } + else { + insert(last_, p, 0) ; + last_ = p; + } + return p; + } - iterator erase(iterator from, iterator to) { - while(from != to) erase(from); + void erase(iterator i) { + if (begin_ == last_) + begin_ = last_ = 0; + else { + if (i == begin_) ++begin_; + else i->prev->next = i->next; + if (i == last_) --last_; + else i->next->prev = i->prev; + } + i->prev = i->next = pointer(0); } + void erase(iterator i, iterator j) { while(i != j) erase(i); } + void clear() { while (!empty()) { erase(begin()); } } + + reference front() { return *begin(); } + const_reference front() const { return *begin(); } + void push_front(const pointer& p) { insert(begin(), p); } + void pop_front() { erase(begin()); } + + /** Iterator to the last element in the list. */ + iterator last() { return last_; } + const_iterator last() const { return last_; } + + reference back() { return *last(); } + const_reference back() const { return *last(); } + void push_back(const pointer& p) { insert(end(), p); } + void pop_back() { erase(last()); } + private: - // The list is circular and always contains an anchor node. - // end() points to the anchor, anchor.next is the first - // iterator, anchor.prev is the last iterator. - - struct Anchor : public Node { - Anchor() : Node(this) {} - // Suppress refcounting for the anchor node. - void release() const {} - // Hide anchor from public get functions. - T* self() const { return 0; } - } anchor; -}; + void insert(pointer a, pointer b, pointer c) { + b->prev = a; + if (a) a->next = b; + b->next = c; + if (c) c->prev = b; + } + + template + class Iterator : public boost::iterator_facade< + Iterator, T, boost::bidirectional_traversal_tag> + { + public: + Iterator() : ptr() {}; + + template Iterator( + const Iterator& i, + typename boost::enable_if_convertible::type* = 0 + ) : ptr(i.ptr) {} + + operator pointer() { return ptr; } + operator const_pointer() const { return ptr; } + + private: + friend class boost::iterator_core_access; + + Iterator(const_pointer p) : ptr(const_cast(p)) {}; -template -void IListNode::insert(IListNode* node) { - assert(!next && !prev); // Not already in a list. - assert(node); - assert(node->next && node->prev); - next=node; - prev=node->prev; - prev->next = this; - next->prev = this; -} - -template -void IListNode::erase() { - assert(prev && next); - intrusive_ptr save(this); // Protect till exit. - prev->next = next; - next->prev = prev; - prev = next = 0; -} + T& dereference() const { return *ptr; } + void increment() { ptr = ptr->next; } + void decrement() { ptr = ptr->prev; } + bool equal(const Iterator& x) const { return ptr == x.ptr; } + + pointer ptr; + + friend class IList; + }; + + iterator begin_, last_; +}; } // namespace qpid Added: incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h?rev=629253&view=auto ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h (added) +++ incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h Tue Feb 19 14:33:29 2008 @@ -0,0 +1,176 @@ +#ifndef QPID_ISLIST_H +#define QPID_ISLIST_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include +#include +#include "pointer_to_other.h" + +namespace qpid { + +template struct Pointee { + typedef typename Pointer::element_type type; +}; + +template struct Pointee { + typedef T type; +}; + +template class ISList; +template class IList; + +/** Base class for values (nodes) in an ISList. + *@param raw or smart-pointer type to use for the "next" pointer. + * Using a smart pointer like shared_ptr or intrusive_ptr + * will automate memory management. + */ +template class ISListNode { + public: + typedef Pointer pointer; + typedef typename Pointee::type NodeType; + typedef typename pointer_to_other::type const_pointer; + + protected: + ISListNode() : next() {} + ISListNode(const ISListNode&) {} // Don't copy the next pointer. + + pointer getNext() { return next; } + const_pointer getNext() const { return next; } + + private: + pointer next; + friend class ISList; +}; + + +/** + * Intrusive singly-linked list. + * + * Provides forward iterator, constant time insertion and constant + * time pop_front (but not pop_back) so makes a good queue + * implementation. + * + * Unlike standard containers insert(), push_front() and push_back() + * take const pointer& rather than const value_type&. + * + * Iterators can be converted to pointers. + * + * Noncopyable - intrusively linked nodes cannot be shared. + * + * @param Node value type for the list, must derive from ISListNode. + */ +template class ISList : private boost::noncopyable { + template class Iterator; + public: + typedef Node value_type; + typedef typename Node::pointer pointer; + typedef typename Node::const_pointer const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef Iterator iterator; + typedef Iterator const_iterator; + + ISList() : first(pointer()), end_(&first) {} + + iterator begin() { return iterator(&first); } + const_iterator begin() const { return const_iterator(&first); } + iterator end() { return end_; } + const_iterator end() const { return end_; } + + bool empty() const { return begin() == end(); } + + size_type size() const { + int s = 0; + for (const_iterator i=begin(); i != end(); ++i) + ++s; + return s; + } + + void swap(ISList &x) { swap(first, x.first); swap(end_, x.end_); } + + /** Unlike standard containers, insert takes a const pointer&, not a + * const value_type&. The value is not copied, only linked into the list. + */ + iterator insert(iterator i, const pointer& p) { + p->next = *(i.pptr); + *(i.pptr) = p; + if (i==end_) ++end_; + return i; + } + + void erase(iterator i) { + if (&i->next == end_.pptr) + end_ = i; + *(i.pptr) = (**(i.pptr)).next; + } + + void erase(iterator i, iterator j) { while(i != j) erase(i); } + void clear() { while (!empty()) { erase(begin()); } } + + reference front() { return *begin(); } + const_reference front() const { return *begin(); } + void pop_front() { erase(begin()); } + void push_front(pointer x) { insert(begin(), x); } + + void push_back(pointer x) { insert(end(), x); } + + private: + template + class Iterator : public boost::iterator_facade < + Iterator, T, boost::forward_traversal_tag> + { + public: + Iterator() {}; + + template Iterator( + const Iterator& i, + typename boost::enable_if_convertible::type* = 0 + ) : pptr(i.pptr) {} + + operator pointer() { return *pptr; } + operator const_pointer() const { return *pptr; } + + private: + friend class boost::iterator_core_access; + + Iterator(const pointer* pp) : pptr(const_cast(pp)) {}; + + T& dereference() const { return **pptr; } + void increment() { pptr = &(**pptr).next; } + bool equal(const Iterator& x) const { return pptr == x.pptr; } + + pointer* pptr; + + friend class ISList; + }; + + private: + pointer first; + iterator end_; +}; + +} // namespace qpid + +#endif /*!QPID_ISLIST_H*/ Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/ISList.h ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h?rev=629253&view=auto ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h (added) +++ incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h Tue Feb 19 14:33:29 2008 @@ -0,0 +1,62 @@ +#ifndef QPID_POINTERTOOTHER_H +#define QPID_POINTERTOOTHER_H + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +namespace qpid { + +// Defines the same pointer type (raw or smart) to another pointee type + +template +struct pointer_to_other; + +template class Sp> +struct pointer_to_other< Sp, U > + { + typedef Sp type; + }; + +template class Sp> +struct pointer_to_other< Sp, U > + { + typedef Sp type; + }; + +template class Sp> +struct pointer_to_other< Sp, U > + { + typedef Sp type; + }; + +template +struct pointer_to_other< T*, U > +{ + typedef U* type; +}; + +} // namespace qpid + + + +#endif /*!QPID_POINTERTOOTHER_H*/ Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/qpid/trunk/qpid/cpp/src/qpid/pointer_to_other.h ------------------------------------------------------------------------------ svn:keywords = Rev Date Modified: incubator/qpid/trunk/qpid/cpp/src/tests/IList.cpp URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/IList.cpp?rev=629253&r1=629252&r2=629253&view=diff ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/tests/IList.cpp (original) +++ incubator/qpid/trunk/qpid/cpp/src/tests/IList.cpp Tue Feb 19 14:33:29 2008 @@ -1,240 +1,163 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ - - +#include "qpid/IList.h" #include "unit_test.h" #include "test_tools.h" -#include "qpid/IList.h" #include #include +QPID_AUTO_TEST_SUITE(IListTestSuite) + using namespace qpid; using namespace std; using boost::assign::list_of; -// Comparison, op== for ILists and sequences of intrusive_ptr -// in qpid namespace to satisfy template lookup rules -namespace qpid { -template bool operator==(const IList& a, const S& b) { return seqEqual(a, b); } -template std::ostream& operator<<(std::ostream& o, const IList& l) { return seqPrint(o, l); } -} - -QPID_AUTO_TEST_SUITE(IListTestSuite) - -template bool operator==(const T& v, const intrusive_ptr& p) { return v==*p; } - -struct TestNode { - static int instances; - char id; - TestNode(char i) : id(i) { ++instances; } - ~TestNode() { --instances; } - bool operator==(const TestNode& x) const { return this == &x; } - bool operator==(const TestNode* x) const { return this == x; } -}; -int TestNode::instances = 0; -ostream& operator<<(ostream& o, const TestNode& n) { return o << n.id; } +// Comparison, op== and << for ILists in qpid namespace for template lookup. -struct SingleNode : public TestNode, public IListNode { - SingleNode(char i) : TestNode(i) {} -}; -typedef IList TestList; +template bool operator==(const IList& a, const S& b) { return seqEqual(a, b); } +template ostream& operator<<(std::ostream& o, const IList& l) { return seqPrint(o, l); } +template +ostream& operator<<(ostream& o, typename IList::iterator i) { + return i? o << "(nil)" : o << *i; +} -struct Fixture { - intrusive_ptr a, b, c, d; - Fixture() : a(new SingleNode('a')), - b(new SingleNode('b')), - c(new SingleNode('c')), - d(new SingleNode('d')) - { - BOOST_CHECK_EQUAL(4, TestNode::instances); - } +struct IListFixture { + struct Node : public IListNode { + char value; + Node(char c) { value=c; } + bool operator==(const Node& n) const { return value == n.value; } + }; + typedef IList List; + Node a, b, c, d, e; + IListFixture() :a('a'),b('b'),c('c'),d('d'),e('e') {} }; -BOOST_AUTO_TEST_CASE(TestFixture) { - { Fixture f; } - BOOST_CHECK_EQUAL(0, TestNode::instances); -} +ostream& operator<<(ostream& o, const IListFixture::Node& n) { return o << n.value; } -BOOST_FIXTURE_TEST_CASE(TestSingleList, Fixture) { - TestList l; - BOOST_CHECK_EQUAL(0u, l.size()); +BOOST_FIXTURE_TEST_CASE(IList_default_ctor, IListFixture) { + List l; BOOST_CHECK(l.empty()); + BOOST_CHECK(l.begin() == l.end()); + BOOST_CHECK_EQUAL(0u, l.size()); +} - l.push_back(*a); +BOOST_FIXTURE_TEST_CASE(IList_push_front, IListFixture) { + List l; + l.push_front(&a); BOOST_CHECK_EQUAL(1u, l.size()); - BOOST_CHECK(!l.empty()); BOOST_CHECK_EQUAL(l, list_of(a)); + l.push_front(&b); + BOOST_CHECK_EQUAL(2u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(b)(a)); +} - TestList::iterator i = l.begin(); - BOOST_CHECK_EQUAL(*i, *a); - - l.push_back(*b); +BOOST_FIXTURE_TEST_CASE(IList_push_back, IListFixture) { + List l; + l.push_back(&a); + BOOST_CHECK_EQUAL(1u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(a)); + l.push_back(&b); BOOST_CHECK_EQUAL(2u, l.size()); BOOST_CHECK_EQUAL(l, list_of(a)(b)); - BOOST_CHECK_EQUAL(*i, *a); // Iterator not invalidated - BOOST_CHECK_EQUAL(l.front(), *a); - BOOST_CHECK_EQUAL(l.back(), *b); - - l.push_front(*c); - BOOST_CHECK_EQUAL(3u, l.size()); - BOOST_CHECK_EQUAL(l, list_of(c)(a)(b)); - BOOST_CHECK_EQUAL(*i, *a); // Iterator not invalidated - - l.insert(i, *d); - BOOST_CHECK_EQUAL(4u, l.size()); - BOOST_CHECK_EQUAL(l, list_of(c)(d)(a)(b)); - BOOST_CHECK_EQUAL(*i, *a); +} - a = 0; // Not deleted yet, still in list. - BOOST_CHECK_EQUAL(4, SingleNode::instances); - l.erase(i); - BOOST_CHECK_EQUAL(3, SingleNode::instances); - BOOST_CHECK_EQUAL(l, list_of(c)(d)(b)); +BOOST_FIXTURE_TEST_CASE(IList_insert, IListFixture) { + List l; + List::iterator i(l.begin()); + i = l.insert(i, &a); + BOOST_CHECK_EQUAL(l, list_of(a)); + BOOST_CHECK(i == l.begin()); + i = l.insert(i, &b); + BOOST_CHECK_EQUAL(l, list_of(b)(a)); + BOOST_CHECK(i == l.begin()); + + i++; + BOOST_CHECK_EQUAL(*i, a); + i = l.insert(i, &c); + BOOST_CHECK_EQUAL(l, list_of(b)(c)(a)); + BOOST_CHECK_EQUAL(*i, c); + + i = l.insert(i, &d); + BOOST_CHECK_EQUAL(l, list_of(b)(d)(c)(a)); + BOOST_CHECK_EQUAL(*i, d); +} + +BOOST_FIXTURE_TEST_CASE(IList_iterator_test, IListFixture) { + List l; + l.push_back(&a); + l.push_back(&b); + + List::iterator i = l.begin(); + BOOST_CHECK_EQUAL(*i, a); + BOOST_CHECK_EQUAL(static_cast(i), &a); + List::const_iterator ci = i; + BOOST_CHECK_EQUAL(static_cast(ci), &a); + + i++; + BOOST_CHECK_EQUAL(*i, b); + BOOST_CHECK_EQUAL(static_cast(i), &b); + i++; + BOOST_CHECK(i == l.end()); +} + +BOOST_FIXTURE_TEST_CASE(IList_pop_front, IListFixture) { + List l; + l.push_back(&a); + l.push_back(&b); + BOOST_CHECK_EQUAL(l, list_of(a)(b)); l.pop_front(); - l.pop_back(); - c = 0; b = 0; - BOOST_CHECK_EQUAL(1, SingleNode::instances); - BOOST_CHECK_EQUAL(l, list_of(d)); + BOOST_CHECK_EQUAL(l, list_of(b)); + l.pop_front(); + BOOST_CHECK(l.empty()); +} +BOOST_FIXTURE_TEST_CASE(IList_pop_back, IListFixture) { + List l; + l.push_back(&a); + l.push_back(&b); + l.pop_back(); + BOOST_CHECK_EQUAL(l, list_of(a)); l.pop_back(); - BOOST_CHECK_EQUAL(0u, l.size()); BOOST_CHECK(l.empty()); } -BOOST_FIXTURE_TEST_CASE(TestIterator, Fixture) { - { - TestList l; - l.push_back(*a); - BOOST_CHECK(a->getNext() == 0); - BOOST_CHECK(a->getPrev() == 0); - l.push_back(*b); - BOOST_CHECK(a->getNext() == b.get()); - BOOST_CHECK(a->getPrev() == 0); - BOOST_CHECK(b->getNext() == 0); - BOOST_CHECK(b->getPrev() == a.get()); - l.push_back(*c); - BOOST_CHECK(b->getNext() == c.get()); - BOOST_CHECK(c->getPrev() == b.get()); - - TestList::iterator i = l.begin(); - BOOST_CHECK_EQUAL(*i, *a); - i++; - BOOST_CHECK_EQUAL(*i, *b); - i++; - BOOST_CHECK_EQUAL(*i, *c); - i++; - BOOST_CHECK(i == l.end()); - i--; - BOOST_CHECK_EQUAL(*i, *c); - i--; - BOOST_CHECK_EQUAL(*i, *b); - i--; - BOOST_CHECK_EQUAL(*i, *a); - } - a = b = c = d = 0; - BOOST_CHECK_EQUAL(0, TestNode::instances); -} - - -BOOST_AUTO_TEST_CASE(testEmptyDtor) { - TestList l; -} - -BOOST_FIXTURE_TEST_CASE(testOwnership, Fixture) { - { - TestList l2; - l2.push_back(*a); - l2.push_back(*b); - l2.push_back(*c); - l2.push_back(*d); - a = b = c = d = 0; - BOOST_CHECK_EQUAL(4, SingleNode::instances); - } - BOOST_CHECK_EQUAL(0, SingleNode::instances); -} - -struct MultiNode : public TestNode, - public IListNode, - public IListNode, - public IListNode -{ - MultiNode(char c) : TestNode(c) {} -}; +BOOST_FIXTURE_TEST_CASE(IList_erase, IListFixture) { + List l; + l.push_back(&a); + l.push_back(&b); + l.push_back(&c); -struct MultiFixture { - IList l0; - IList l1; - IList l2; - - intrusive_ptr a, b, c; - - MultiFixture() : a(new MultiNode('a')), - b(new MultiNode('b')), - c(new MultiNode('c')) - { - BOOST_CHECK_EQUAL(3, MultiNode::instances); - } - - void push_back_all(intrusive_ptr p) { - l0.push_back(*p); - l1.push_back(*p); - l2.push_back(*p); - } -}; + List::iterator i=l.begin(); + i++; + l.erase(i); + BOOST_CHECK_EQUAL(l, list_of(a)(c)); -BOOST_FIXTURE_TEST_CASE(TestMultiIList, MultiFixture) { - BOOST_CHECK_EQUAL(a->id, 'a'); - push_back_all(a); - push_back_all(b); - push_back_all(c); - - BOOST_CHECK_EQUAL(3, MultiNode::instances); - - l0.pop_front(); - l1.pop_back(); - IList::iterator i = l2.begin(); + i=l.begin(); i++; - l2.erase(i); - BOOST_CHECK_EQUAL(3, MultiNode::instances); - BOOST_CHECK_EQUAL(l0, list_of(b)(c)); - BOOST_CHECK_EQUAL(l1, list_of(a)(b)); - BOOST_CHECK_EQUAL(l2, list_of(a)(c)); - - l1.pop_front(); - l2.clear(); - BOOST_CHECK_EQUAL(l0, list_of(b)(c)); - BOOST_CHECK_EQUAL(l1, list_of(b)); - BOOST_CHECK(l2.empty()); - a = 0; - BOOST_CHECK_EQUAL(2, MultiNode::instances); // a gone - - l0.pop_back(); - l1.pop_front(); - BOOST_CHECK_EQUAL(l0, list_of(b)); - BOOST_CHECK(l1.empty()); - BOOST_CHECK(l2.empty()); - BOOST_CHECK_EQUAL(2, MultiNode::instances); // c gone - c = 0; - - l0.clear(); - b = 0; - BOOST_CHECK_EQUAL(0, MultiNode::instances); // all gone + l.erase(i); + BOOST_CHECK_EQUAL(l, list_of(a)); + + l.erase(l.begin()); + BOOST_CHECK(l.empty()); } QPID_AUTO_TEST_SUITE_END() Added: incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp?rev=629253&view=auto ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp (added) +++ incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp Tue Feb 19 14:33:29 2008 @@ -0,0 +1,207 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include "qpid/ISList.h" +#include "qpid/RefCounted.h" +#include "unit_test.h" +#include "test_tools.h" +#include +#include +#include + +QPID_AUTO_TEST_SUITE(ISListTestSuite) + +using namespace qpid; +using namespace std; +using boost::assign::list_of; + +// Comparison, op== and << for ILists in qpid namespace for template lookup. + +template bool operator==(const ISList& a, const S& b) { return seqEqual(a, b); } +template ostream& operator<<(std::ostream& o, const ISList& l) { return seqPrint(o, l); } +template +ostream& operator<<(ostream& o, typename ISList::iterator i) { + return i? o << "(nil)" : o << *i; +} + +struct NodeBase { + static int instances; + char value; + + NodeBase(char c) { value=c; ++instances; } + NodeBase(const NodeBase& n) { value=n.value; ++instances; } + ~NodeBase() { --instances; } + bool operator==(const NodeBase& n) const { return value == n.value; } +}; + +int NodeBase::instances = 0; + +ostream& operator<<(ostream& o, const NodeBase& n) { return o << n.value; } + +struct Fixture { + struct Node : public NodeBase, public ISListNode { + Node(char c) : NodeBase(c) {} + }; + typedef ISList List; + Node a, b, c, d, e; + List l; + Fixture() :a('a'),b('b'),c('c'),d('d'),e('e') {} +}; + +BOOST_FIXTURE_TEST_CASE(default_ctor, Fixture) { + BOOST_CHECK(l.empty()); + BOOST_CHECK(l.begin() == l.end()); + BOOST_CHECK_EQUAL(0u, l.size()); +} + +BOOST_FIXTURE_TEST_CASE(push_front, Fixture) { + l.push_front(&a); + BOOST_CHECK_EQUAL(1u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(a)); + l.push_front(&b); + BOOST_CHECK_EQUAL(2u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(b)(a)); +} + +BOOST_FIXTURE_TEST_CASE(push_back, Fixture) { + l.push_back(&a); + BOOST_CHECK_EQUAL(1u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(a)); + l.push_back(&b); + BOOST_CHECK_EQUAL(2u, l.size()); + BOOST_CHECK_EQUAL(l, list_of(a)(b)); +} + +BOOST_FIXTURE_TEST_CASE(insert, Fixture) { + List::iterator i(l.begin()); + i = l.insert(i, &a); + BOOST_CHECK_EQUAL(l, list_of(a)); + BOOST_CHECK(i == l.begin()); + + i = l.insert(i, &b); + BOOST_CHECK_EQUAL(l, list_of(b)(a)); + BOOST_CHECK(i == l.begin()); + + i++; + BOOST_CHECK_EQUAL(*i, a); + i = l.insert(i, &c); + BOOST_CHECK_EQUAL(l, list_of(b)(c)(a)); + BOOST_CHECK_EQUAL(*i, c); + + i = l.insert(i, &d); + BOOST_CHECK_EQUAL(l, list_of(b)(d)(c)(a)); + BOOST_CHECK_EQUAL(*i, d); +} + +BOOST_FIXTURE_TEST_CASE(iterator_test, Fixture) { + l.push_back(&a); + l.push_back(&b); + + List::iterator i = l.begin(); + BOOST_CHECK_EQUAL(*i, a); + BOOST_CHECK_EQUAL(static_cast(i), &a); + List::const_iterator ci = i; + BOOST_CHECK_EQUAL(static_cast(ci), &a); + + i++; + BOOST_CHECK_EQUAL(*i, b); + BOOST_CHECK_EQUAL(static_cast(i), &b); + i++; + BOOST_CHECK(i == l.end()); +} + +BOOST_FIXTURE_TEST_CASE(pop_front, Fixture) { + l.push_back(&a); + l.push_back(&b); + l.pop_front(); + BOOST_CHECK_EQUAL(l, list_of(b)); + l.pop_front(); + BOOST_CHECK(l.empty()); +} + +BOOST_FIXTURE_TEST_CASE(erase, Fixture) { + l.push_back(&a); + l.push_back(&b); + l.push_back(&c); + + List::iterator i=l.begin(); + i++; + l.erase(i); + BOOST_CHECK_EQUAL(l, list_of(a)(c)); + + i=l.begin(); + i++; + l.erase(i); + BOOST_CHECK_EQUAL(l, list_of(a)); + + l.erase(l.begin()); + BOOST_CHECK(l.empty()); +} + + +// ================ Test smart pointer types. + +template void smart_pointer_test() { + typedef typename Node::pointer pointer; + typedef ISList List; + List l; + + BOOST_CHECK_EQUAL(0, NodeBase::instances); + l.push_back(pointer(new Node())); + l.push_back(pointer(new Node())); + BOOST_CHECK_EQUAL(2, NodeBase::instances); // maintains a reference. + + pointer p = l.begin(); + l.pop_front(); + BOOST_CHECK_EQUAL(2, NodeBase::instances); // transfers ownership. + p = pointer(); + BOOST_CHECK_EQUAL(1, NodeBase::instances); + + l.clear(); + BOOST_CHECK_EQUAL(0, NodeBase::instances); + { // Dtor cleans up + List ll; + ll.push_back(pointer(new Node())); + BOOST_CHECK_EQUAL(1, NodeBase::instances); + } + BOOST_CHECK_EQUAL(0, NodeBase::instances); +} + +struct IntrusiveNode : public NodeBase, public RefCounted, + public ISListNode > +{ + IntrusiveNode() : NodeBase(0) {} +}; + + +BOOST_AUTO_TEST_CASE(intrusive_ptr_test) { + smart_pointer_test(); +} + + +struct SharedNode : public NodeBase, public ISListNode > { + SharedNode() : NodeBase(0) {} +}; + +BOOST_AUTO_TEST_CASE(shared_ptr_test) { + smart_pointer_test(); +} + +QPID_AUTO_TEST_SUITE_END() Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/ISList.cpp ------------------------------------------------------------------------------ svn:keywords = Rev Date Modified: incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am?rev=629253&r1=629252&r2=629253&view=diff ============================================================================== --- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original) +++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Tue Feb 19 14:33:29 2008 @@ -36,7 +36,7 @@ Url.cpp Uuid.cpp \ Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \ InlineVector.cpp \ - IList.cpp \ + ISList.cpp IList.cpp \ ClientSessionTest.cpp check_LTLIBRARIES += libshlibtest.la