G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsSortedVector.h
Go to the documentation of this file.
1 
15 #pragma once
16 
17 //#include <vector>
18 //#include <algorithm> // For lower_bound
19 
20 #ifndef TORCH_VERSION
21 namespace std
22 {
23 
24 template<typename T1, typename T2>
25 std::ostream& operator << ( std::ostream& os,
26  const std::pair<T1,T2>& rhs )
27 {
28  os << rhs.first << ", " << rhs.second;
29  return os;
30 }
31 
32 }//namespace std
33 #endif
34 
35 namespace gismo {
36 
108 template<class T, class _A = std::allocator<T> >
109 class gsSortedVector : public std::vector<T, _A>
110 {
111  typedef std::vector<T,_A> inherited;
112 
113 public:
114  typedef typename std::vector<T>::const_iterator const_iterator;
115  typedef typename std::vector<T>::iterator iterator;
116 
117 public:
118 
119 //
120  gsSortedVector( )
121  : std::vector<T, _A>( ), m_bSorted(true) { }
122 
123  gsSortedVector( typename std::vector<T>::const_iterator start
124  , typename std::vector<T>::const_iterator end)
125  : std::vector<T, _A>(start,end), m_bSorted(0) { };
126 
127 
128 //
129  //-------------------------------------------------------------------//
130  // SetSorted() //
131  //-------------------------------------------------------------------//
132  // I didn't want to override every constructor to set this
133  // member variable, so this function is publicly accessible.
134  // You should call SetSorted( true ) right after construction.
135  // TO DO: if you feel like it... derive all constructors to avoid
136  // the need for this. There are 4 last time I checked.
137  //-------------------------------------------------------------------//
138  void SetSorted( bool bSorted = true ) { m_bSorted = bSorted; }
139 
140  //-------------------------------------------------------------------//
141  // sort() //
142  //-------------------------------------------------------------------//
143  // This function sorts the data as needed. Call it after repeated calls to
144  // push_unsorted(), or just let other members call it for you on next access.
145  // It calls std::sort(), which defaults to using operator<() for
146  // comparisons.
147  //-------------------------------------------------------------------//
148  void sort()
149  {
150  if ( !m_bSorted )
151  {
152  std::sort( inherited::begin(), inherited::end() );
153  SetSorted();
154  }
155  }
156 
157  bool bContains( const T& t ) const
158  {
159  if ( !m_bSorted )
160  gsWarn<<"gsSortedVector is not sorted, bContains("<<t<<")"
161  << "is not guaranteed to be correct.\n";
162 
163  return std::binary_search( inherited::begin(), inherited::end(), t );
164  }
165 
166  typename std::vector<T>::iterator lower_bound_it( const T& key )
167  {
168  if ( !m_bSorted )
169  sort();
170 
171  typename std::vector<T>::iterator it = std::lower_bound( inherited::begin(), inherited::end(), key );
172  return it;
173  }
174 
175  /*const*/ T* lower_bound_ptr( const T& key )
176  {
177  typename std::vector<T>::iterator it = lower_bound_it( key );
178 
179  if (it==inherited::end())
180  return 0;
181 
182  /*const*/ T* t = &(*it);
183  return t;
184  }
185 
186 
187  //-------------------------------------------------------------------//
188  // find_it_or_fail() //
189  //-------------------------------------------------------------------//
190  // This function takes the given object and determines if there is
191  // a match in the vector. It returns an iterator to the actual
192  // object in the vector, if found. Otherwise returns std::vector::end().
193  //
194  // This is the function you want to use most of the time
195  // (or the predicate version if you are using object pointers).
196  //
197  // USAGE: it makes most sense to use this function if you have
198  // an object with a key, other member variables, and operator<()
199  // that uses the key to test for equality. You then set up a dummy
200  // "search" object with the key set to the search value, call the
201  // function, and use the result to extract the additional information
202  // from the object.
203  //-------------------------------------------------------------------//
204  typename std::vector<T>::iterator find_it_or_fail( const T& key )
205  {
206  typename std::vector<T>::iterator it = lower_bound_it( key );
207 
208  if ( it != inherited::end() )
209 
210  // lower_bound() does not necessarily indicate a successful search.
211  // The iterator points to the object where an insertion
212  // should take place. We check that result to see if we actually
213  // had an exact match.
214 
215  // NOTE: This is how the STL determines equality using only operator()<.
216  // Two comparisons, ugg, but it is a nice little trick.
217  if( !((*it)<key) && !(key<(*it)) )
218 
219  return it;
220 
221  return inherited::end();
222  }
223 
224  typename std::vector<T>::const_iterator find_it_or_fail( const T& key ) const
225  {
226  typename std::vector<T>::const_iterator it =
227  std::lower_bound( inherited::begin(), inherited::end(), key );
228 
229  if ( it != inherited::end() )
230  if( !((*it)<key) && !(key<(*it)) )
231  return it;
232 
233  return inherited::end();
234  }
235 
236  //-------------------------------------------------------------------//
237  // find_ptr_or_fail() //
238  //-------------------------------------------------------------------//
239  // A variation of find_it_or_fail() that provides a pointer to result.
240  //-------------------------------------------------------------------//
241  T* find_ptr_or_fail( const T& key )
242  {
243  typename std::vector<T>::iterator it = find_it_or_fail( key );
244  if ( it != inherited::end() )
245  return &(*it);
246 
247  return 0;
248  }
249 
250  // Same as find_it_or_fail but return an index instead of an iterator
251  size_t getIndex(const T& key ) const
252  {
253  return find_it_or_fail(key) - inherited::begin();
254  }
255 
256  //-------------------------------------------------------------------//
257  // push_sorted() //
258  //-------------------------------------------------------------------//
259  // This is used to insert into a vector that always remains sorted.
260  // Because we have a sorted vector, finding the insertion location
261  // with std::lower_bound() is relatively cheap.
262  //
263  // If you have multiple insertions, consider
264  // using push_unsorted() for each, then calling sort().
265  //-------------------------------------------------------------------//
266  void push_sorted( const T& t )
267  {
268  if ( !m_bSorted )
269  {
270  sort();
271  }
272 
273  // Insert at "lower_bound" (the proper sorted location).
274  inherited::insert( std::lower_bound( inherited::begin(), inherited::end(), t ), t );
275  }
276 
277  // Same as push_sorted but only inserts the element if it does not exist already
278  void push_sorted_unique( const T& t )
279  {
280  if ( !m_bSorted )
281  {
282  sort();
283  }
284 
285  // iterator itr// Assumes sorted in ascending order
286  // = std::lower_bound(vec.begin(), vec.end(), e, std::greater<C>() );
287  iterator pos = std::lower_bound(inherited::begin(), inherited::end(), t );
288 
289  if ( pos == inherited::end() || *pos != t )// If not found
290  inherited::insert(pos, t);
291 
292  }
293 
294  //-------------------------------------------------------------------//
295  // push_unsorted() //
296  //-------------------------------------------------------------------//
297  // This is similar to push_back(), but in addition, it sets the
298  // unsorted flag.
299  //-------------------------------------------------------------------//
300  void push_unsorted( const T& t )
301  {
302  SetSorted( false );
303  this->push_back(t);
304  }
305 
306  size_t uniqueSize() const
307  {
308  if ( inherited::begin() == inherited::end() )
309  return 0;
310 
311  if ( !m_bSorted )
312  gsWarn<<"gsSortedVector is not sorted, uniqueSize()"
313  << "is not guaranteed to be correct.\n";
314 
315  size_t cnt = 1;
316  for (const_iterator it = inherited::begin()+1; it != inherited::end(); ++it)
317  if ( *(it-1) != *(it) ) ++cnt;
318 
319  return cnt;
320  }
321 
322  //-------------------------------------------------------------------//
323  // operator=() //
324  //-------------------------------------------------------------------//
325  // This allows us to set the gsSortedVector from a std::vector.
326  //-------------------------------------------------------------------//
327  gsSortedVector<T>& operator=(std::vector<T> v)
328  {
329  v.swap(*this);
330  sort();
331  return *this;
332  }
333 
334  // CALLS WHERE YOU PROVIDE THE FUNCTOR OR FUNCTION POINTER
335  // If you need to use a predicate sort function, ALWAYS use these methods
336  // instead of the non-functor versions.
337  // NOTE: UPDATE THIS when C++0x polymorphic function wrappers are available.
338  template<class _Pr> inline
339  void sort( _Pr pr )
340  {
341  if ( !m_bSorted )
342  {
343  std::sort( inherited::begin(), inherited::end(), pr );
344  SetSorted();
345  }
346  }
347  template<class _Pr> inline
348  typename std::vector<T>::iterator lower_bound_it( const T& key, _Pr pr )
349  {
350  if ( !m_bSorted )
351  {
352  std::sort( inherited::begin(), inherited::end(), pr );
353  SetSorted();
354  }
355  typename std::vector<T>::iterator it = std::lower_bound( inherited::begin(), inherited::end(), key, pr );
356  return it;
357  }
358 
359  template<class _Pr> inline
360  /*const*/ T* lower_bound_ptr( const T& key, _Pr pr )
361  {
362  typename std::vector<T>::iterator it = lower_bound_it( key, pr );
363 
364  if (it==inherited::end())
365  return 0;
366 
367  /*const*/ T* t = &(*it);
368  return t;
369  }
370 
371  template<class _Pr> inline
372  void push_sorted( const T& t, _Pr pr )
373  {
374  if ( !m_bSorted )
375  {
376  std::sort( inherited::begin(), inherited::end(), pr );
377  SetSorted();
378  }
379 
380  // Insert at "lower_bound" (the proper sorted location).
381  insert( std::lower_bound( inherited::begin(), inherited::end(), t, pr ), t );
382  }
383 
384  template<class _Pr> inline
385  typename std::vector<T>::iterator find_it_or_fail( const T& key, _Pr pr )
386  {
387  typename std::vector<T>::iterator it = lower_bound_it( key, pr );
388 
389  if ( it != inherited::end() )
390  // NOTE: We have to apply this using the predicate function, be careful...
391  if (!(pr((*it), key)) && !(pr(key,(*it))))
392  return it;
393 
394  return inherited::end();
395  }
396 
397  template<class _Pr> inline
398  T* find_ptr_or_fail( const T& key, _Pr pr )
399  {
400  typename std::vector<T>::iterator it = find_it_or_fail( key, pr );
401  if ( it != inherited::end() )
402  return &(*it);
403 
404  return 0;
405  }
406 
407 protected:
408  bool m_bSorted;
409 
410 private:
411 
412  // to do
413  //void push_back( const T& t);
414 
415 };
416 
417 
418 } //namespace gismo
419 
This class is derived from std::vector, and adds sort tracking.
Definition: gsSortedVector.h:109
std::ostream & operator<<(std::ostream &os, const _expr< E > &b)
Stream operator for expressions.
Definition: gsExpressions.h:382
#define gsWarn
Definition: gsDebug.h:50