/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