Flow123d
sys_vector.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  * @file
26  * @brief Vector classes to support both Iterator, index and Id access and creating co-located vectors.
27  *
28  * @todo Implement co-located vector class that takes reference of the original Vector and
29  * is of the same size. FullIterator should have method for accessing elements in the original vector.
30  */
31 #ifndef SYS_VECTOR_HH_
32 #define SYS_VECTOR_HH_
33 
34 #include <vector>
35 #include <map>
36 #include "global_defs.h"
37 #include "system.hh"
38 
39 // OPEN NAME SPACE "flow"
40 namespace flow {
41 
42 /**
43  * @brief Iterator that keeps also reference to its container. Safer and provides indexes.
44  *
45  * Full iterator into a Vector<T> container. It makes
46  * an envelop around std:vector<T>::iterator, but stores also reference of
47  * the container it points into. Consequently FullIter can return index.
48  * The container has to be provided when FullIterator is created and this container can not be changed
49  * during the life of the variable. This is intentional since more safe.
50  *
51  * This class is larger then normal pointer i.e. Iter type and therefore is questionable
52  * to use it in the large arrays. To this and you can use Iter and later convert it to FullIter
53  * providing the container It points into.
54  *
55  */
56 
57 template <class Cont>
59 {
60 public:
61  /// Constructor to make uninitialized FullIterator for a container.
62  FullIterator(Cont &cont_par)
63  : cont(cont_par),
64  iter(cont_par.storage.end()) {}
65 
66  /// Constructor to make FullIterator from container and its std::vector iterator.
67  /// Mainly for internal use.
68  FullIterator(const Cont &cont_par,const typename Cont::iterator it)
69  : cont(cont_par),
70  iter(it) {}
71 
72  /// Constructor to make FullIterator from container and Iter i.e. T*
73  FullIterator(Cont &cont_par,const typename Cont::Iter it)
74  : cont(cont_par)
75  {
76  if (it == NULL) iter = cont_par.storage.end();
77  else iter = cont_par.storage.begin() + cont.index(it);
78  }
79 
80  /// Check validity of FullIterator.
81  inline bool is_valid()
82  { return this->iter != this->cont.storage.end(); }
83 
84  /**
85  * Get index of FullIterator in its container.
86  * Return invalid index -1 for undefined iterator.
87  */
88  inline int index() const
89  { if (this->iter != this->cont.storage.end()) return this->iter - cont.storage.begin();
90  else return (-1);
91  }
92 
93  /// Get reference to the container of the FullIterator.
94  inline Cont &container()
95  { return cont; }
96 
97  /// Assign operator. In debugging version check that containers of both FullIterator match.
98  inline FullIterator & operator =(const FullIterator &orig)
99  {
100  // container.storage.begin() == orig.container.storage.begin()
101  ASSERT( (&(this->cont) == &(orig.cont)),"Can not change container of FulIter.\n");
102  this->iter=orig.iter;
103  return (*this);
104  }
105 
106  /// Type cast to Iter i.e. standard pointer.
107  inline operator typename Cont::Iter () const
108  { return &(*(this->iter)); }
109 
110  /// * dereference operator
111  inline typename Cont::ElementType & operator *() const
112  { return *(this->iter); }
113 
114  /// -> dereference operator
115  inline typename Cont::ElementType * operator ->() const
116  { return &(*(this->iter)); }
117 
118  inline FullIterator &operator += (const int shift)
119  { this->iter+=shift; return (*this); }
120 
121  inline FullIterator &operator -= (const int shift)
122  { this->iter-=shift; return (*this); }
123 
124  /// Comparison of two FullIterator.
125  inline bool operator == (const FullIterator &it) const
126  { return ( &(this->cont) == &(it.cont)) && (this->iter == it.iter); }
127 
128  inline bool operator != (const FullIterator &it) const
129  { return ( &(this->cont) != &(it.cont)) || (this->iter != it.iter) ; }
130 
131  /// Prefix. Advance operator.
133  {
134  ASSERT( iter != cont.storage.end(), "Can not advance iterator at the end.\n");
135  ++(this->iter); return *this;
136  }
137 
138  /// Postfix. Should not be used since involves iterator copy.
139  inline FullIterator operator ++ (int);
140  //{
141  // //xprinf(Warn, "Postfix advance opeartor should")
142  // ASSERT( iter==storage.end(), "Can not advance iterator at the end.\n");
143  // FullIterator x(*this); this->iter++; return x;
144  //}
145 
146  /// Prefix. Advance to previous operator.
148  {
149  ASSERT( iter != cont.storage.begin(), "Can not advance iterator to previous of begin().\n");
150  this->iter--; return *this;
151  }
152 
153  /// Postfix. Should not be used since involves iterator copy.
154  inline FullIterator operator -- (int);
155  //{
156  // //xprinf(Warn, "Postfix advance opeartor should")
157  // ASSERT( iter==storage.begin(), "Can not advance iterator to previous of begin().\n");
158  // FullIterator x(*this); this->iter--; return x;
159  //}
160 
161  // + - opeartors is better to define outside if we ever allow them.
162 protected:
163  /// We have here reference to the container of the iterator. So, an instance of this class can not change the container.
164  const Cont &cont;
165  // Conatainer iterator.
166  typename Cont :: iterator iter;
167 };
168 
169 /**
170  * Small extension of the class FullIterator<Cont>. Provides id() method to get id number of the iterator.
171  * In contrast to FullIterator<> this is templated only by the element type of the container which is always VectorId<T>.
172  */
173 template <class T>
174 class VectorId;
175 
176 template <class T>
177 class FullIteratorId : public FullIterator< VectorId<T> > {
178 public:
179  /// Constructor. Just call base class.
181  : FullIterator<VectorId<T> >(cont) {}
182  /// Constructor. Just call base class.
184  : FullIterator< VectorId<T> >(cont, it) {}
185  /// Constructor. Just call base class.
187  : FullIterator< VectorId<T> >(cont, it) {}
188  /// Returns id of the iterator. See VectorId documentation.
189  inline int id()
190  { return this->cont.id_storage[ this->index() ]; }
191 };
192 
193 
194 
195 /**
196  * @brief Envelop over std::vector, use enhanced iterators.
197  *
198  * Differences compared to std::vector.
199  *
200  * -# Implement only subset of std::vector methods.
201  *
202  * -# iterator Iter - which is nothing else then T *. This we use since it can be initializeted to NULL as universal "non valid value".
203  * for iterators one has to comapre to std::vector.end(), but the container is not always at hand.
204  * This should be used in complex mesh structures to save space.
205  *
206  * -# iterator FullIter - this is standard iterator which contains also reference to the containre it points to. Then it has more
207  * save "non valid value" method. Can be constructer from Iter and a container. You can get the index of this iterator.
208  * This is meant to be use as local variable.
209  * Using this instead of standard iterators It provides function to get index of an iterator
210  *
211  * -# Provides method to get index of a pointer i.e. Iter.
212  *
213  * -# add_item can be used to add a new element and get reference to it so that it can be initialized
214  * Useful even for T be class since when creating a new element the default constructor is called
215  * which can not fill it with values.
216  *
217  * <b> Developer note: </b>
218  *
219  * It appears very dangerous to combine reallocating std::vectors with iterators implemented as pointers.
220  * Indeed, when vector array is reallocated old pointers become invalid. One possibility is to strictly
221  * distinguish crating of the array and later creating references into it. Another is to implement iterators by indexes
222  * which means also to use only FullIterators.
223  */
224 
225 template <class T>
226 class Vector
227 {
228 public:
229  /// We have to export template type for FullIteraror.
230  typedef T ElementType;
231  /// Default iterator for this class.
232  typedef T * Iter;
233  /// For compatibility with std::algorithms we provide also standard iterators.
234  /// Theoretically it should work also with Iter. Test that if you need it.
237  /// Type of FullIterator that should be used to iterate through this container.
239 
240 
241  /// Construct with reserve the space. Includes default constructor.
242  Vector(unsigned int size = 0) : storage(0)
243  {this->reserve(size);}
244 
245  /**
246  * Add a new element into the container. Return iterator to it.
247  * Provides a way to add new element to the container and get an iterator to set its values.
248  * This way we need not copy a new element.
249  */
251  {
252  storage.resize( storage.size() + 1 );
253  return FullIter( *this, storage.begin() + storage.size() - 1 );
254  }
255 
256  /**
257  * For given pointer returns the index of the element in the Vector. The first element has zero index.
258  */
259  inline unsigned int index(Iter pointer) const
260  {
261  ASSERT( pointer >= &(storage.front()) && pointer <= &(storage.back()),
262  "Wrong pointer %d to obtain its index (%d, %d).\n",pointer, &(storage.front()), &(storage.back()));
263  return ( pointer - &(storage.front()) );
264  }
265 
266  /// Returns FullFullIterer of the first element.
267  inline FullIter begin()
268  { return FullIter( *this, storage.begin() ); }
269 
270  /// Returns FullFullIterer of the fictions past the end element.
271  inline FullIter end()
272  { return FullIter( *this, storage.end() ); }
273 
274  /// Returns size of the container. This is independent of the allocated space.
275  inline unsigned int size() const
276  { return storage.size(); }
277 
278  /// Returns size of the container. This is independent of the allocated space.
279  inline void resize(const unsigned int size)
280  { storage.resize(size); }
281 
282 
283  /// Gets reference to the element specified by index.
284  inline T & operator[](unsigned int idx)
285  {
286  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
287  return storage[idx];
288  }
289 
290  /// Gets reference to the element specified by index.
291  inline const T & operator[](unsigned int idx) const
292  {
293  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
294  return storage[idx];
295  }
296 
297 
298  /// Gets iterator of the element specified by index.
299  inline FullIter operator()(unsigned int idx)
300  {
301  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
302  return FullIter( *this, begin()+idx );
303  }
304 
305 
306  /// Reallocates the container space.
307  inline void reserve(unsigned int size)
308  {
309  ASSERT( size >= this->size(), "Vector can not be reallocated into space %d smaller then its size %d\n",size,this->size());
310  storage.reserve(size);
311  }
312 
313  /// Alternative way to make FullIterer form Iter. This way you need not write
314  /// the full FullIter type to call the constructor. Then the result can be assigned to
315  /// suitable local FullIter variable.
317  { return FullIter(*this, it); }
318 
319  /// Since storage is direct member it is deallocated by its own destructor.
320  virtual ~Vector() {}
321 
322 protected:
323  /// Underlying vector container.
325 
326  friend class FullIterator< Vector<T> >;
327 };
328 
329 
330 /**
331  * @brief Small extension of Vector<T> container with support to Id numbers.
332  *
333  * This stores Id numbers of added elements
334  * and can latter access elements by id. An Id can be any integer number that only has to be unique
335  * for every element in the container. In particular Id numbers are need not to be continuous neither keep the ordering of the elements.
336  * Main application is to keep Id numbers from input, which are only necessary to amke correct references during input and possibly to
337  * generate consistent output. Id numbers are useless for calculations.
338  *
339  * <b> Developer Note: </b>
340  *
341  * I have tried to make one common base class VectorBase which
342  * should have storage member and implements basic operations with it.
343  * But I can not make it to return FullIterator which has to be initialized
344  * with reference to the container so not VectorBase but some of its descendants.
345  * Only way seems to construct FullIterator by any pointer which could be type cast
346  * to the type of the container which is template parameter of FullIter.
347  * But such constructor should be used only by VectorXXX classes, but we can not make
348  * VectorBase<T, It> friend for any T and any It.
349  * However all this seems to be too complicated and ugly so I and up with lot of repetitive code
350  * in implementation of VectorXXX classes.
351  *
352  */
353 
354 
355 
356 template <class T>
357 class VectorId
358 {
359 public:
360  /// We have to export template type for FullIteraror.
361  typedef T ElementType;
362  /// Default iterator for this class.
363  typedef T * Iter;
364  /// For compatibility with std::algorithms we provide also standard iterators.
365  /// theoreticaly it should work also with Iter. Test that if you need it.
368  /// Type of FullIterator that should be used to iterate through this container.
370 
371  /// Construct with reserve the space. Includes default constructor.
372  VectorId(unsigned int size = 0) : storage(0), id_storage(0)
373  {this->reserve(size);}
374 
375  /**
376  * Adds a new element into the container. Return iterator to it to set vales of the new element.
377  * This way we need not copy a new element. You are forced to set the id when adding a new element.
378  */
380  {
381  ASSERT( id_map.find(id) == id_map.end(), "Can not add item with id number %d since it already exists.", id);
382  id_storage.push_back(id);
383  //DBGMSG("Push id: %d\n",id);
384  id_map[id]=this->size();
385 
386  this->storage.resize( this->storage.size() + 1 );
387  return FullIter( *this, this->storage.begin() + this->storage.size() - 1 );
388  }
389 
390 
391  /**
392  * For given pointer returns the index of the element in the Vector. The first element has zero index.
393  */
394  inline unsigned int index(const T * pointer) const
395  {
396  ASSERT( pointer >= &(storage.front()) && pointer <= &(storage.back()),
397  "Wrong pointer %p to obtain its index (%p, %p).\n",pointer, &(storage.front()), &(storage.back()));
398  return ( pointer - &(storage.front()) );
399  }
400 
401  /// Returns FullFullIterer of the first element.
402  /// Do not try to set these as const methods. Such has to produce const iterators
403  /// which requires const anlaogy of FullIter - really ugly
404  inline FullIter begin()
405  { return FullIter( *this, storage.begin() ); }
406 
407  /// Returns FullFullIterer of the fictions past the end element.
408  inline FullIter end()
409  { return FullIter( *this, storage.end() ); }
410 
411  /// Returns size of the container. This is independent of the allocated space.
412  inline unsigned int size() const
413  { return storage.size(); }
414 
415  /// Gets reference to the element specified by index.
416  inline T & operator[](unsigned int idx)
417  {
418  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
419  return storage[idx];
420  }
421 
422 
423  /// Gets reference to the element specified by index.
424  inline const T & operator[](unsigned int idx) const
425  {
426  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
427  return storage[idx];
428  }
429 
430 
431  /// Gets iterator of the element specified by index.
432  inline FullIter operator()(unsigned int idx)
433  {
434  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
435  return FullIter( *this, begin()+idx );
436  }
437 
438  /// Gets iterator of the element specified by index.
439  inline const Iter operator()(unsigned int idx) const
440  {
441  ASSERT( idx < this->size(), "Index %d outside of Vector of size %d\n",idx, this->size());
442  return Iter( &(storage[idx]) );
443  }
444 
445 
446  /// Alternative way to make FullFullIterer form FullIterer. This way you need not write
447  /// the full FullFullIterer typename to call the constructor. Then the result can be assigned to
448  /// suitable local FullFullIterer variable.
450  { return FullIter(*this, it); }
451 
452  /**
453  * Returns FullIter of the element with given id. This is implemented by std::map which use balanced trees and ensure access in O(nlog n) time.
454  */
455  inline FullIter find_id(const int id)
456  {
457  map<int,unsigned int>::iterator iter = id_map.find(id);
458  if ( iter == id_map.end() ) {
459  return FullIter(*this, this->storage.end());
460  } else
461  return FullIter(*this, this->storage.begin() + iter->second);
462  }
463 
464  /**
465  * Returns FullIter of the element with given id. This is implemented by std::map which use balanced trees and ensure access in O(nlog n) time.
466  */
467  inline const T * find_id(const int id) const
468  {
470  if ( iter == id_map.end() ) {
471  return &(*(this->storage.end()));
472  } else
473  return &(*(this->storage.begin() + iter->second));
474  }
475 
476  /** Returns Id of the element given by pointer i.e. Iter. FullIter i.e. FullIteratorId<T>
477  * provides its own method for the same.
478  */
479  inline int get_id(const T * it) const
480  {
481  return *(id_storage.begin() + this->index(it));
482  }
483 
484  inline int get_id(int idx) const
485  {
486  return *(id_storage.begin() + idx);
487  }
488 
489  /// Reallocates the container space.
490  inline void reserve(unsigned int size)
491  {
492  ASSERT( size >= this->size(), "Vector can not be reallocated into space %d smaller then its size %d\n",size,this->size());
493  storage.reserve(size);
494  id_storage.reserve(size);
495  }
496 
497  /// Since storage is direct member it is deallocated by its own destructor.
498  virtual ~VectorId() {}
499 
500 
501 private:
502  /// Underlying vector container.
504 
505  std::vector<int> id_storage; ///< Space to save id numbers.
506  std::map<int, unsigned int> id_map; ///< Maps id numbers to indexes into storage vector.
507 
508  friend class FullIterator< VectorId<T> >;
509  friend class FullIteratorId<T>;
510 };
511 
512 
513 
514 // CLOSE NAME SPACE "flow"
515 }
516 
517 
518 #endif /* SYS_VECTOR_HH_ */