interreality.org [VOS]
[Home] [About]
[Screenshots]
[Download]
[News]
[Community]
[Documentation] [Manual]
[Bugs & Requests] [Wiki]

/home/tetron/hack/vos/libs/vos/vutil/iterator.hh

Go to the documentation of this file.
00001 /*
00002 
00003     This file is part of the Virtual Object System of
00004     the Interreality project (http://interreality.org).
00005 
00006     Copyright (C) 2001-2003 Peter Amstutz
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Lesser General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012 
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Lesser General Public License for more details.
00017 
00018     You should have received a copy of the GNU Lesser General Public
00019     License along with this library; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00021 
00022     Peter Amstutz <http://www.interreality.org>
00023 */
00024 
00025 #ifndef _VUTIL_ITERATOR_HH_
00026 #define _VUTIL_ITERATOR_HH_
00027 
00028 #include <iostream>
00029 #include <deque>
00030 #include <stdexcept>
00031 #include <vector>
00032 
00033 /** @file
00034     Defines VOS iterator base class
00035 */
00036 namespace VUtil {
00037     /** @ingroup libvutil
00038         Used by the Iterator template to free the elements of the
00039         iterator.  Must be specialized for each subclass of Iterator.
00040      */
00041     template<class T> inline void iteratorReleaseItem(T*)
00042     {
00043     }
00044 
00045     /** @class Iterator iterator.hh vos/vos/iterator.hh
00046         @ingroup libvutil
00047 
00048         Template base class for iterators in VOS.  Subclasses dervived
00049         from Iterator are returned by various methods in VOS.  Unlike
00050         some iterator patterns (such as STL iterators), this Iterator
00051         class does not iterate over the data structure directly.
00052         Instead it copies the data of interest (using operator=) into
00053         a temporary std::vector of elements.  The reason for doing
00054         this is to avoid concurrency conditions: another thread
00055         changing the underlying data structure does not invalidate the
00056         iterator, nor is the calling thread required to lock the
00057         underlying data structure for any longer than the time
00058         required to make a copy.  Conversely this means that an
00059         iterator can be out of date, so an iterator should not be
00060         stored for extended periods.
00061 
00062         The underlying std::vector is reference counted and may be
00063         shared among iterators so an iterator may be efficiently
00064         copied using the copy constructor or Iterator::operator=().
00065         Please also note that the iterator class itself is not
00066         threadsafe!  If you must share it with another thread, make a
00067         copy.
00068 
00069         Typical iterator usage looks like this:
00070         @code
00071         for(ChildListIterator cli = getChildren(); cli.hasMore(); cli++)
00072         {
00073           std::cout << (*cli)->getChild()->getURLst() << std::endl;
00074         }
00075         @endcode
00076     */
00077     template<class T> class Iterator
00078     {
00079     protected:
00080         std::vector<T>* items;
00081         typedef typename std::vector<T>::size_type size_type;
00082         size_type pos;
00083         int* refcount;
00084 
00085     public:
00086         /** Constructor.  Produces an empty iterator. */
00087         Iterator() {
00088             pos = 0;
00089             items = new std::vector<T>();
00090             refcount = new int;
00091             *refcount = 1;
00092         }
00093 
00094         /** Constructor.  Copies the state of the iterator.  The
00095             underlying std::vector is shared and reference counted, so
00096             this an efficient operation.
00097         */
00098         Iterator(const Iterator& b) : items(b.items),
00099                                       pos(b.pos),
00100                                       refcount(b.refcount)
00101             {
00102                 (*refcount)++;
00103             }
00104 
00105         /** Destructor. Destroys the underlying std::vector if we're
00106             the last ones to be using it.
00107          */
00108         ~Iterator() {
00109             if(--(*refcount) == 0) {
00110                 for(size_type i = 0; i < (*items).size(); i++) {
00111                     iteratorReleaseItem<T>(&((*items)[i]));
00112                 }
00113                 delete refcount;
00114                 delete items;
00115                 refcount = 0;
00116             }
00117         }
00118 
00119         /** Increment our current position */
00120         void operator++() { if(pos < items->size()) pos++; }
00121 
00122         /** Decrement our current position */
00123         void operator--() { if(pos > 0) pos--; }
00124 
00125         /** Increment our current position */
00126         void operator++(int) { if(pos < items->size()) pos++; }
00127 
00128         /** Decrement our current position */
00129         void operator--(int) { if(pos > 0) pos--; }
00130 
00131         /** Copies the state of the iterator.  The underlying
00132             std::vector is shared and reference counted, so this an
00133             efficient operation.
00134         */
00135         void operator=(const Iterator<T>& i) {
00136             if(--(*refcount) == 0) {
00137                 for(size_type i = 0; i < (*items).size(); i++) {
00138                     iteratorReleaseItem<T>(&((*items)[i]));
00139                 }
00140                 delete refcount;
00141                 delete items;
00142                 refcount = 0;
00143             }
00144 
00145             refcount = i.refcount;
00146             pos = i.pos;
00147             items = i.items;
00148             (*refcount)++;
00149         }
00150 
00151         /** @return true if there are valid elements remaining in the
00152             iterator (including the current one)
00153         */
00154         bool hasMore() { return (pos < items->size()); }
00155 
00156         /** @return true if the iterator is at the starting position  */
00157         bool atStart() { return (pos == 0); }
00158 
00159         /** sets the iterator to the starting position  */
00160         void reset() { pos = 0; }
00161 
00162         /** @return total number of elements in the iterator */
00163         size_type size() { return items->size(); }
00164 
00165         /** @return number of elements still left, including the
00166             current element
00167         */
00168         size_type remaining() { return (items->size() - pos); };
00169 
00170         /** Set the position of the iterator */
00171         void setPos(size_type p) {
00172                 if(p > items->size()) {
00173                         if(items->size() == 0) p = 0;
00174                         else p = items->size() - 1;
00175                 }
00176                 pos = p;
00177         }
00178 
00179         /** @return true if the supplied element exists in the list,
00180             as tested using operator==.  This is a simple linear
00181             search.
00182         */
00183         bool hasItem(T i) {
00184             for(size_type n = 0; n < items->size(); n++) {
00185                 if((*items)[n] == i) return true;
00186             }
00187             return false;
00188         }
00189     };
00190 }
00191 
00192 #endif