dune-grid  2.2.1
utility/persistentcontainer.hh
Go to the documentation of this file.
1 #ifndef DUNE_PERSISTENTCONTAINER_HH
2 #define DUNE_PERSISTENTCONTAINER_HH
3 
4 #include <cassert>
5 #include <map>
6 #include <vector>
7 
8 #include <dune/common/misc.hh>
9 #include <dune/common/forloop.hh>
11 
12 namespace Dune
13 {
42  template < class Grid, class Data, class Allocator=std::allocator<Data> >
44 
48  template <class Grid, class Index, class Vector>
50  {
51  public:
52  typedef typename Vector::value_type Data;
53  typedef Grid GridType;
54  protected:
55  const int codim_;
56  const Index& index_;
57  const double overEstimate_;
58  Vector data_;
59 
60  public:
62  typedef typename GridType :: template Codim< 0 > :: Entity ElementType;
63 
65  typedef typename Vector :: iterator Iterator ;
67  typedef typename Vector :: const_iterator ConstIterator ;
68 
70  // store data on entities of given codim using index to store data in vector.
71  // The overEstimate parameter can be used to allocate more memory than
72  // required to store the data.
73  PersistentContainerVector( const GridType& grid, const int codim,
74  const Index& index,
75  const double overEstimate,
76  const typename Vector::allocator_type &allocator )
77  : codim_( codim )
78  , index_( index )
79  , overEstimate_( overEstimate ) // this is not yet the right approach - will be revised
80  , data_( index.size( codim ), Data(), allocator )
81  {
82  }
83 
86  : codim_( other.codim_ )
87  , index_( other.index_ )
88  , overEstimate_( other.overEstimate_ )
89  , data_( other.data_ )
90  {}
91 
93  const Index& index()
94  {
95  return index_;
96  }
97 
99  template <class Entity>
100  Data& operator [] (const Entity& entity )
101  {
102  assert( Entity :: codimension == codim_ );
103  assert( (typename Index::IndexType) index_.index( entity ) < (typename Index::IndexType) data_.size() );
104  return data_[ index_.index( entity ) ];
105  }
106 
108  template <class Entity>
109  const Data& operator [] (const Entity& entity ) const
110  {
111  assert( Entity :: codimension == codim_ );
112  assert( (typename Index::IndexType) index_.index( entity ) < (typename Index::IndexType) data_.size() );
113  return data_[ index_.index( entity ) ];
114  }
115 
117  Data& operator () (const ElementType& element, const int subEntity )
118  {
119  assert( (typename Index::IndexType) index_.subIndex( element, subEntity, codim_ ) < (typename Index::IndexType) data_.size() );
120  return data_[ index_.subIndex( element, subEntity, codim_ ) ];
121  }
122 
124  const Data& operator () (const ElementType& element, const int subEntity ) const
125  {
126  assert( (typename Index::IndexType) index_.subIndex( element, subEntity, codim_ ) < (typename Index::IndexType) data_.size() );
127  return data_[ index_.subIndex( element, subEntity, codim_ ) ];
128  }
129 
132  {
133  return data_.begin();
134  }
135 
138  {
139  return data_.begin();
140  }
141 
144  {
145  return data_.end();
146  }
147 
150  {
151  return data_.end();
152  }
153 
155  size_t size() const { return data_.size(); }
156 
158  void reserve( ) // need a better name
159  {
160  if( (typename Index::IndexType) index_.size( codim_ ) > (typename Index::IndexType) data_.size() )
161  update( );
162  }
163 
165  void clear( )
166  {
167  // clear all entries
168  data_.clear();
169  // resize with new default value
170  const size_t newSize = index_.size( codim_ );
171  data_.resize( newSize, Data() );
172  }
173 
175  void update( )
176  { // this could be more sophisticated (although std::vector is not stupid and
177  // overestimated on its own...
178  const size_t newSize = index_.size( codim_ );
179  if (newSize < data_.capacity())
180  data_.resize(newSize, Data() );
181  else
182  {
183  data_.reserve(newSize*overEstimate_);
184  data_.resize(newSize, Data() );
185  }
186  }
187  };
188 
192  template <class Grid, class Id, class Map>
194  {
196 
197  protected:
198  typedef typename Map :: mapped_type Data;
199  typedef typename Id :: IdType IdType;
200  typedef Grid GridType;
201  const GridType& grid_;
202  const int codim_;
203  const Id& id_;
204  mutable Map data_;
205 
206  typedef typename Map :: iterator iterator ;
207  typedef typename Map :: const_iterator const_iterator ;
208 
209  template <class D, class IteratorType >
210  struct DataExtractor ;
211 
212  // Data type for iterator
213  template <class D>
214  struct DataExtractor< D, iterator >
215  {
216  typedef D Type ;
217  };
218 
219  // Data type for const iterator
220  template <class D>
222  {
223  typedef const D Type ;
224  };
225 
226  template <class IteratorType>
228  {
229  IteratorType it_;
230  public:
231  // get correct data type (const or non-const)
233 
234  MyIterator(const IteratorType& it) : it_( it ) {}
235  MyIterator(const MyIterator& other) : it_( other.it_ ) {}
236 
237  bool operator == (const MyIterator& other) const { return it_ == other.it_; }
238  bool operator != (const MyIterator& other) const { return it_ != other.it_; }
239 
241  {
242  ++it_;
243  return *this;
244  }
245  value_type& operator * () { return (*it_).second; }
246  value_type* operator -> () { return &((*it_).second); }
248  {
249  it_ = other.it_;
250  return *this;
251  }
252  };
253 
254  template< int codim , bool gridHasCodim >
256  {
257  static void apply ( ThisType &container, const Data& value , const int myCodim)
258  {
259  if( codim == myCodim )
260  container.template adaptCodim< codim > ( value );
261  }
262  };
263 
264  template< int codim >
265  struct AdaptCodimBase< codim, false >
266  {
267  static void apply ( ThisType &container, const Data& value , const int myCodim)
268  {
269  }
270  };
271 
272  template< int codim >
273  struct AdaptCodim
274  : public AdaptCodimBase< codim, Capabilities :: hasEntity < GridType, codim > :: v >
275  {
276  };
277 
278  public:
279  typedef typename GridType :: template Codim< 0 > :: Entity ElementType;
280  typedef MyIterator< iterator > Iterator;
281  typedef MyIterator< const_iterator > ConstIterator;
282 
284  //
285  // Container is to be used to store data on entities of given codim using id to store data in map.
286  PersistentContainerMap( const GridType& grid, const int codim, const Id& id,
287  const typename Map::key_compare& comp,
288  const typename Map::allocator_type &allocator )
289  : grid_( grid )
290  , codim_( codim )
291  , id_( id )
292  , data_(comp,allocator)
293  {
294  }
296  // unordered_map the constructor taking only an allocator is not available that is
297  // why this constructor is added)
298  //
299  // Container is to be used to store data on entities of given codim using id to store data in map.
300  PersistentContainerMap( const GridType& grid, const int codim, const Id& id)
301  : grid_( grid )
302  , codim_( codim )
303  , id_( id )
304  , data_()
305  {
306  }
307 
310  : grid_( other.grid_ )
311  , codim_( other.codim_ )
312  , id_( other.id_ )
313  , data_( other.data_ )
314  {}
315 
317  template <class Entity>
318  Data& operator [] (const Entity& entity )
319  {
320  assert( Entity :: codimension == codim_ );
321  return data_[ id_.id( entity ) ];
322  }
323 
325  template <class Entity>
326  const Data& operator [] (const Entity& entity ) const
327  {
328  assert( Entity :: codimension == codim_ );
329  return data_[ id_.id( entity ) ];
330  }
331 
333  Data& operator () (const ElementType& element, const int subEntity )
334  {
335  return data_[ id_.subId( element, subEntity, codim_ ) ];
336  }
337 
339  const Data& operator () (const ElementType& element, const int subEntity ) const
340  {
341  return data_[ id_.subId( element, subEntity, codim_ ) ];
342  }
343 
346  {
347  return Iterator( data_.begin() );
348  }
349 
352  {
353  return ConstIterator( data_.begin() );
354  }
355 
358  {
359  return Iterator( data_.end() );
360  }
361 
364  {
365  return ConstIterator( data_.end() );
366  }
367 
369  size_t size() const { return data_.size(); }
370 
372  void reserve()
373  {
374  }
375 
377  void clear( )
378  {
379  data_.clear();
380  }
381 
383  void update( )
384  { // this version could be implemented differently by only compressing
385  update( Data() );
386  }
387  protected:
389  void update( const Data& value )
390  {
391  // loop over all codimensions (needed to make codim_ static)
392  ForLoop< AdaptCodim, 0, GridType :: dimension > :: apply( *this, value, codim_ );
393  }
394 
395  template <int codim>
396  void adaptCodim( const Data& value )
397  {
398  assert( codim_ == codim );
399  // create empty map and swap it with current map (no need to copy twice)
400  Map oldData;
401  std::swap( oldData, data_ );
402 
403  const iterator olddataend = oldData.end();
404  typedef typename GridType :: template Codim< codim > :: LevelIterator LevelIterator ;
405  typedef typename LevelIterator :: Entity Entity;
406  for(int l = 0; l <= grid_.maxLevel(); ++ l)
407  {
408  const LevelIterator endit = grid_.template lend< codim > ( l );
409  for( LevelIterator it = grid_.template lbegin< codim > ( l ); it != endit; ++ it )
410  {
411  const Entity& entity = * it ;
412  const IdType id = id_.id( entity );
413  Data& data = data_[ id ];
414  iterator entry = oldData.find( id );
415  if( entry != olddataend )
416  data = (*entry).second;
417  }
418  }
419  }
420  };
421 
422  // PersistentContainer (default is to use PersistentContainerMap)
423  // -------------------
424  template < class Grid, class Data, class Allocator>
425  class PersistentContainer
426  : public PersistentContainerMap< Grid, typename Grid::Traits::LocalIdSet,
427  std::map<const typename Grid::Traits::LocalIdSet::IdType, Data,
428  std::less<const typename Grid::Traits::LocalIdSet::IdType>,
429  typename Allocator::template rebind<typename Grid::Traits::LocalIdSet::IdType>::other > >
430  {
431  public:
432  typedef Grid GridType;
433  protected:
434  typedef typename Grid::Traits::LocalIdSet IdSet;
435  typedef typename IdSet::IdType IdType;
436  typedef typename Allocator::template rebind<IdType>::other IdAllocator;
437  typedef std::map<const IdType, Data, std::less<const IdType>,
440 
441  public:
444  PersistentContainer ( const GridType &grid, const int codim, const Allocator &allocator=Allocator() )
445  : BaseType( grid, codim, grid.localIdSet(), std::less<const IdType>(), allocator )
446  {}
447  };
448 
449 #if 0 // the following implementation can be used for a grid providing a hash for the id type
450 #include <unordered_map>
451  template < class MyGrid, class Data, class Allocator >
452  class PersistentContainer
453  : public PersistentContainerMap< MyGrid, typename MyGrid::Traits::LocalIdSet,
454  std::unordered_map<const typename MyGrid::Traits::LocalIdSet::IdType, Data,
455  std::hash<typename MyGrid::Traits::LocalIdSet::IdType>,
456  std::equal_to<const typename MyGrid::Traits::LocalIdSet::IdType>, Allocator> >
457  {
458  typedef MyGrid GridType;
459  typedef typename GridType::Traits::LocalIdSet IdSet;
460  typedef typename IdSet::IdType IdType;
461  typedef std::unordered_map<const IdType, Data, std::hash<IdType>, std::equal_to<const IdType>, Allocator> Map;
462  typedef PersistentContainerMap< GridType, IdSet, Map > BaseType;
463 
464  public:
470  PersistentContainer ( const GridType &grid, const int codim, const Allocator &allocator=Allocator() )
471  : BaseType( grid, codim, grid.localIdSet() )
472  {}
473  };
474 #endif
475 } // end namespace Dune
476 
477 #endif // end DUNE_PERSISTENTCONTAINER_HH