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