Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

more/gen/ring.h

Go to the documentation of this file.
00001 //  Copyright (C) 2001  Petter Urkedal (petter.urkedal@matfys.lth.se)
00002 //
00003 //  This file is free software; you can redistribute it and/or modify
00004 //  it under the terms of the GNU General Public License as published by
00005 //  the Free Software Foundation; either version 2 of the License, or
00006 //  (at your option) any later version.
00007 //
00008 //  This file is distributed in the hope that it will be useful,
00009 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 //  GNU General Public License for more details.
00012 //
00013 //  You should have received a copy of the GNU General Public License
00014 //  along with this program; if not, write to the Free Software
00015 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00016 //
00017 //  As a special exception, you may use this file as part of a free
00018 //  software library without restriction.  Specifically, if other files
00019 //  instantiate templates or use macros or inline functions from this
00020 //  file, or you compile this file and link it with other files to
00021 //  produce an executable, this file does not by itself cause the
00022 //  resulting executable to be covered by the GNU General Public
00023 //  License.  This exception does not however invalidate any other
00024 //  reasons why the executable file might be covered by the GNU General
00025 //  Public License.
00026 //
00027 //  $Id: ring.h,v 1.1 2002/05/30 18:01:37 petter_urkedal Exp $
00028 
00029 
00030 #ifndef MORE_GEN_RING_H
00031 #define MORE_GEN_RING_H
00032 
00033 #include <more/gen/memory.h>
00034 #include <stdexcept>
00035 #include <iterator>
00036 
00037 
00038 namespace more {
00039 namespace gen {
00040 
00041   /** \class ring ring.h more/ring.h
00042    *
00043    *  A ring is a collection of object which are bidirectionally
00044    *  linked into a ring.  That is, a ring is like a list, but with
00045    *  the last element connected to the first.  One of the nodes is
00046    *  called the principal node.  This is the only node directly
00047    *  accessible, and is analogous to both the \c begin() and \c end()
00048    *  of other containers.
00049    *
00050    *  \image html ring_ring.png
00051    *  \image latex ring_ring.eps
00052    *  A ring of numbers from 0 to 7.
00053    *
00054    *  Note that there is no half-open range of iterators which span
00055    *  the whole ring.  There are ranges which excludes one element,
00056    *  and there are pairs of half-open ranges which together span the
00057    *  ring.
00058    *
00059    *  One way to look at it is too see [\c it, \c it) as an ambiguous
00060    *  range which is empty or spans the whole ring.  Inspired by this
00061    *  idea you can iterate over all nodes by skipping the first
00062    *  ``<tt>it != it_past_the_end'' test, as in
00063    *
00064    *  \code
00065    *  if (!r.empty()) {
00066    *      iterator it = r.principal();
00067    *      do some_code(it); while (++it != r.principal());
00068    *  }
00069    *  \endcode
00070    */
00071   template< typename T, typename Alloc = more::gen::allocator<T> >
00072     struct ring {
00073         //@{
00074         /** The standard container types. */
00075         typedef T value_type;
00076         typedef Alloc allocator_type;
00077         typedef typename allocator_type::pointer pointer;
00078         typedef typename allocator_type::const_pointer const_pointer;
00079         typedef typename allocator_type::reference reference;
00080         typedef typename allocator_type::const_reference const_reference;
00081         typedef typename allocator_type::size_type size_type;
00082         typedef typename allocator_type::difference_type difference_type;
00083         //@}
00084 
00085       private:
00086         struct node {
00087             node() {}
00088             node(T const& v) : value(v) {}
00089             node(node const& x) : value(x.value) {}
00090 
00091             node* prev;
00092             node* next;
00093             T value;
00094         };
00095 
00096         typedef typename allocator_type::template rebind<node>::other
00097                 real_allocator_type;
00098 
00099       public:
00100         /** A bidirectional iterator. */
00101         struct iterator
00102         {
00103             typedef std::ptrdiff_t difference_type;
00104             typedef T value_type;
00105             typedef value_type& reference;
00106             typedef value_type* pointer;
00107             typedef std::bidirectional_iterator_tag iterator_category;
00108 
00109             iterator() {}
00110             iterator(iterator const& it) : x(it.x) {}
00111             explicit iterator(node* x_) : x(x_) {}
00112             iterator& operator++() { x = x->next; return *this; }
00113             iterator operator++(int) {
00114                 iterator tmp = *this;
00115                 ++*this;
00116                 return tmp;
00117             }
00118             iterator& operator--() { x = x->prev; return *this; }
00119             iterator operator--(int) {
00120                 iterator tmp = *this;
00121                 --*this;
00122                 return tmp;
00123             }
00124             bool operator==(iterator const& rhs) const {
00125                 return x = rhs.x;
00126             }
00127             bool operator!=(iterator const& rhs) const {
00128                 return x != rhs.x;
00129             }
00130             iterator& operator=(iterator const& rhs) {
00131                 x = rhs.x;
00132                 return *this;
00133             }
00134             reference operator*() { return x->value; }
00135             pointer operator->() { return &x->value; } // XXX allocator
00136           private:
00137             node* x;
00138             friend class ring;
00139         };
00140 
00141         /** Yet another bidirectional iterator, but this one's got
00142          **  const values. */
00143         struct const_iterator
00144         {
00145             typedef std::ptrdiff_t difference_type;
00146             typedef T const value_type;
00147             typedef value_type const& reference;
00148             typedef value_type const* pointer;
00149             typedef std::bidirectional_iterator_tag iterator_category;
00150 
00151             const_iterator() {}
00152             const_iterator(const_iterator const& it) : x(it.x) {}
00153             const_iterator(iterator const& it) : x(it.x) {}
00154             explicit const_iterator(node const* x_) : x(x_) {}
00155             const_iterator& operator++() { x = x->next; return *this; }
00156             const_iterator operator++(int) {
00157                 const_iterator tmp = *this;
00158                 ++*this;
00159                 return tmp;
00160             }
00161             const_iterator& operator--() { x = x->prev; return *this; }
00162             const_iterator operator--(int) {
00163                 const_iterator tmp = *this;
00164                 --*this;
00165                 return tmp;
00166             }
00167             bool operator==(const_iterator const& rhs) const {
00168                 return x = rhs.x;
00169             }
00170             bool operator!=(const_iterator const& rhs) const {
00171                 return x != rhs.x;
00172             }
00173             const_iterator& operator=(const_iterator const& rhs) {
00174                 x = rhs.x;
00175                 return *this;
00176             }
00177             reference operator*() { return x->value; }
00178             pointer operator->() { return &x->value; } // XXX allocator
00179           private:
00180             node const* x;
00181             friend class ring;
00182         };
00183 
00184 
00185         /** Construct an empty continer, which becomes a ring if you
00186          *  insert an element. */
00187         ring() : a_node(0), m_size(0) {}
00188 
00189         /** Construct a deep copy of \a x. */
00190         ring(ring const& r)
00191             : alloc(r.alloc), a_node(0), m_size(r.m_size) {
00192             if (r.size()) {
00193                 const_iterator it = r.principal();
00194                 while (--it != r.principal())
00195                     push_front(*it);
00196                 push_front(*it);
00197             }
00198         }
00199 
00200         /** Destruct. */
00201         ~ring() { clear(); }
00202 
00203         /** Assign a deep copy of \a x. */
00204         ring& operator=(ring const& x) {
00205             this->~ring();
00206             new(this) ring(x);
00207             return *this;
00208         }
00209 
00210         /** Number of members of the ring. */
00211         size_type size() const { return m_size; }
00212 
00213         /** Returns true if the container contains no node. */
00214         bool empty() const { return m_size == 0; }
00215 
00216         /** Returns an iterator to the principal node. */
00217         iterator principal() {
00218 #ifndef MORE_NDEBUG
00219             if (!a_node)
00220                 throw std::logic_error(
00221                     "A ring with no nodes has no valid iterator.");
00222 #endif
00223             return iterator(a_node);
00224         }
00225 
00226         /** Returns an iterator to the principal node. */
00227         const_iterator principal() const {
00228 #ifndef MORE_NDEBUG
00229             if (!a_node)
00230                 throw std::logic_error(
00231                     "A ring with no nodes has no valid iterator.");
00232 #endif
00233             return const_iterator(a_node);
00234         }
00235 
00236 //      reverse_iterator rprincipal() {
00237 // #ifndef MORE_NDEBUG
00238 //          if (!a_node)
00239 //              throw std::logic_error(
00240 //                  "A ring with no nodes has no valid iterator.");
00241 // #endif
00242 //          return reverse_iterator(a_node);
00243 //      }
00244 
00245         /** Erase all nodes in the ring. */
00246         void clear() {
00247             m_size = 0;
00248             node* x = a_node;
00249             if (x)
00250                 for(;;) {
00251                     node* y = x->next;
00252                     alloc.destroy(x);
00253                     alloc.deallocate(x, 1);
00254                     if (y == a_node) break;
00255                     x = y;
00256                 }
00257         }
00258 
00259         /** Erase the node at \a it.
00260          *
00261          *  \return an iterator to the next element if the container
00262          *  is non-empty after the operation, otherwise an invalid
00263          *  iterator.
00264          */
00265         iterator erase(iterator it) {
00266             --m_size;
00267             node* y = it.x->next;
00268             y->prev = it.x->prev;
00269             it.x->prev->next = y;
00270             if (it.x == a_node) {
00271                 if (y == a_node)
00272                     a_node = 0;
00273                 else
00274                     a_node = y;
00275             }
00276             alloc.destroy(it.x);
00277             alloc.deallocate(it.x, 1);
00278             return iterator(y);
00279         }
00280 
00281         /** Insert \a val in front of \a it. */
00282         iterator insert(iterator it, value_type const& val) {
00283             ++m_size;
00284             node* x = alloc.allocate(1);
00285             a.construct(x, node(val));
00286             x->next = it.x;
00287             x->prev = it.x->prev;
00288             it.x->prev->next = x;
00289             it.x->prev = x;
00290             return iterator(x);
00291         }
00292 
00293         /** Insert a default constructed object in front of \a it.
00294          *  \pre The allocator is extended to support default construction.
00295          */
00296         iterator insert(iterator it) {
00297             ++m_size;
00298             node* x = alloc.allocate(1);
00299             alloc.construct(x);
00300             x->next = it.x;
00301             x->prev = it.x->prev;
00302             it.x->prev->next = x;
00303             it.x->prev = x;
00304             return iterator(x);
00305         }
00306 
00307         /** Insert \a val in before the principal and make it the new
00308          *  principal.  If the ring is empty, set the principal to \a
00309          *  val. */
00310         void push_front(value_type const& val) {
00311             ++m_size;
00312             node* x = alloc.allocate(1);
00313             alloc.construct(x, node(val));
00314             if (a_node) {
00315                 x->prev = a_node->prev;
00316                 x->next = a_node;
00317                 x->prev->next = x;
00318                 a_node->prev = x;
00319             }
00320             else {
00321                 x->next = x;
00322                 x->prev = x;
00323             }
00324             a_node = x;
00325         }
00326 
00327         /** Insert a default constructed object before the principal
00328          *  and make it the new principal.
00329          *  \pre The allocator is extended to support default construction.
00330          */
00331         void push_front() {
00332             ++m_size;
00333             node* x = alloc.allocate(1);
00334             alloc.construct(x);
00335             if (a_node) {
00336                 x->prev = a_node->prev;
00337                 x->next = a_node;
00338                 x->prev->next = x;
00339                 a_node->prev = x;
00340             }
00341             else {
00342                 x->next = x;
00343                 x->prev = x;
00344             }
00345             a_node = x;
00346         }
00347 
00348         /** Insert \a val after the principal and make it the new
00349          *  principal.  If the ring is empty, set the principal to \a
00350          *  val. */
00351         void push_back(value_type const& val) {
00352             ++m_size;
00353             node* x = alloc.allocate(1);
00354             alloc.construct(x, node(val));
00355             if (a_node) {
00356                 x->prev = a_node;
00357                 x->next = a_node->next;
00358                 x->next->prev = x;
00359                 a_node->next = x;
00360             }
00361             else {
00362                 x->next = x;
00363                 x->prev = x;
00364             }
00365             a_node = x;
00366         }
00367 
00368         /** Insert a default constructed object after the principal
00369          *  and make it the new principal.
00370          *  \pre The allocator is extended to support default construction.
00371          */
00372         void push_back() {
00373             ++m_size;
00374             node* x = alloc.allocate(1);
00375             alloc.construct(x);
00376             if (a_node) {
00377                 x->prev = a_node;
00378                 x->next = a_node->next;
00379                 x->next->prev = x;
00380                 a_node->next = x;
00381             }
00382             else {
00383                 x->next = x;
00384                 x->prev = x;
00385             }
00386             a_node = x;
00387         }
00388 
00389         /** Pop the principal node off the ring, and make the node
00390          *  after it the new principal. */
00391         void pop_front() { erase(iterator(a_node)); }
00392 
00393         /** Pop the principal node off the ring, and make the node
00394          *  before it the new principal. */
00395         void pop_back() {
00396             erase(iterator(a_node));
00397             if (a_node) a_node = a_node->prev;
00398         }
00399 
00400         /** Make the node after the principal node the next
00401          *  principal. (Counterclockwise is usually taken as the
00402          *  positive direction of rotation.)
00403          *  \pre The ring is not empty.
00404          */
00405         void rotate_counterclockwise() {
00406 #ifndef MORE_NDEBUG
00407             if (!a_node)
00408                 throw std::logic_error("No ring to rotate.");
00409 #endif
00410             a_node = a_node->next;
00411         }
00412 
00413         /** Make the node before the principal node the next principal.
00414          *  \pre The ring is not empty.
00415          */
00416         void rotate_clockwise() {
00417 #ifndef MORE_NDEBUG
00418             if (!a_node)
00419                 throw std::logic_error("No ring to rotate.");
00420 #endif
00421             a_node = a_node->prev;
00422         }
00423 
00424         /** Return the allocator. */
00425         allocator_type get_allocator() const { return alloc; }
00426 
00427       private:
00428         real_allocator_type alloc;
00429         node* a_node;
00430         size_type m_size;
00431     };
00432 }} // more::gen
00433 
00434 #endif

Generated on Sat Sep 7 19:11:14 2002 for more with Doxygen 1.2.13.1. Doxygen 1.2.13.1 is written and copyright 1997-2002 by Dimitri van Heesch.