OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
DomainMap.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  *
7  * Visit http://people.web.psi.ch/adelmann/ for more details
8  *
9  ***************************************************************************/
10 
11 #ifndef DOMAIN_MAP_H
12 #define DOMAIN_MAP_H
13 
14 /***********************************************************************
15 
16 Steve Karmesin
17 Dakota Scientific Software
18 February 1996
19 
20 A DomainMap holds a bunch of Domains of type Key in such a way that you
21 can quickly look up which Keys's touch a given one and an object
22 associated with that Key.
23 
24 Key must have the following operations defined:
25 
26 bool touches(const Key&, const Key&);
27 Return true if the Keys touch, false if they don't.
28 
29 bool contains(const Key& l, const Key& r);
30 Return true if l contains r, false otherwise.
31 
32 bool split(pair<const Key,const Key>&, const Key& k);
33 Split one Key into two, and return a boolean for success.
34 
35 split and containes need to have the following properties for
36 consistent behavior:
37 
38 1. If Key A is split into A1 and A2, then
39  contains(A,A1)==true and contains(A,A2)==true.
40 
41 2. If Key A is split into A1 and A2, then there is no Key B
42  for which contains(A1,B) and contains(A2,B) are both true.
43 
44 3. If contains(A,B)==true and contains(B,C)==true then we must have
45  contains(A,C)==true.
46 
47 Each Key is associated with a T. We enter those Ts into the
48 DomainMap and later pull out the ones that touch a given Key.
49 
50 touches(const Key&) must do two things:
51 1) It must be fast.
52 2) It must be right.
53 
54 "Fast" means that it has to be at worst linear in the number of hits,
55 times a log of the total number of elements in the Map.
56 
57 "Right" means that it has to find all of the elements that touch the
58 given Key exactly once.
59 
60 This currently has very small subset of the capabilites of an STL map..
61 It should gradually get expanded to include as many as make sense.
62 
63 ***********************************************************************/
64 
65 // include files
66 #include "Utility/Pooled.h"
67 #include "Utility/PAssert.h"
68 
69 #include <list>
70 #include <iterator>
71 #include <utility>
72 #include <cstddef>
73 
74 template < class Key, class T , class Touches, class Contains, class Split >
75 class DomainMap
76 {
77 public:
79  typedef unsigned size_type;
80 
81  typedef Key key_type;
82  typedef T mapped_type;
83 
84  struct value_type {
85  Key first;
88  value_type(const Key& k, const T& t)
89  : first(k),
90  second(t){
91  }
92  };
93 
94 
95 private:
96  // A class for the nodes of the tree.
97  // Subclass from Pooled so that new and delete are fast.
98  // Not visible from outside of DomainMap
99  class Node : public Pooled<Node>
100  {
101  public:
102  typedef std::list<value_type> cont_type; // The type for the container
103  Key MyDomain; // This Node's Domain.
104  Node *Left,*Right; // Make this a binary tree.
105  Node *Parent; // Have this around for traversals.
106  cont_type cont; // The values in this Node.
107 
108  // Construct with the domain and the parent.
109  Node(const Key& d, Node* p=0) : MyDomain(d),Left(0),Right(0),Parent(p) {}
110  // When you die take you children with you.
111  ~Node() {
112  if (Left ) delete Left;
113  if (Right) delete Right;
114  }
115 
116  // Insert a pair<Key,T> into the tree.
117  // tjw: added noSplit flag 3/24/1998
118  //mwerks void insert(const value_type& d, bool noSplit=false);
120  // Insert a T into the tree.
121  // This isn't nearly as bad as it looks. It is just careful
122  // to not build any nodes it doesn't have to, and to minimize
123  // the number of times it calls split. There is some duplicated
124  // code here to keep the threading through the if statements smooth.
125  void insert(const value_type& d, bool noSplit=false) {
126 
127  Key left_domain; // When splitting a node, we'll need a spot
128  Key right_domain; // to store the left and right domains.
129 
130  // ----------------------------------------------------------------------
131  // tjw:
132  // First, make sure that the domain isn't of total extent 1, which will
133  // cause an assertion failure in split() functions like Index::split() in
134  // the code below. For this special case, just insert straightaway. Use
135  // the newly-added flag noSplit to request this; noSplit defaults to
136  // false, so no existing code should break:
137 
138  if (noSplit) {
139  cont.push_back(d);
140  return;
141  }
142 
143  // tjw.
144  //-----------------------------------------------------------------------
145 
146  if ( Left && Right ) {
147  // If they both exist already the algorithm is simple.
148  if ( Contains::test(Left->MyDomain,d.first) )
149  Left->insert(d);
150  else if ( Contains::test(Right->MyDomain,d.first) )
151  Right->insert(d);
152  else
153  cont.push_back(d);
154 
155  }
156  else if ( Left==0 && Right==0 ) {
157  // If neither exist, split and check.
158  if ( Split::test(left_domain, right_domain, MyDomain) ) {
159  if ( Contains::test(left_domain, d.first) ) {
160  // It is on the left. Build it and go.
161  Left = new Node( left_domain, this );
162  Left->insert(d);
163  }
164  else if ( Contains::test(right_domain, d.first) ) {
165  // It is on the right. Build it and go.
166  Right = new Node( right_domain, this );
167  Right->insert(d);
168  }
169  else {
170  // It is not in either. Put it here.
171  cont.push_back(d);
172  }
173  }
174  else {
175  // Couldn't split. Put it here.
176  cont.push_back(d);
177  }
178 
179  }
180  else if ( Right ) {
181  // Only the one on the right exists already. Check it first.
182  if ( Contains::test(Right->MyDomain, d.first) ) {
183  // It is there, go down.
184  Right->insert(d);
185  }
186  else {
187  // Not on the right. Check the left.
188  Split::test(left_domain, right_domain, MyDomain);
189  if ( Contains::test(left_domain,d.first) ) {
190  // It is there. Build the left and drop into it.
191  Left = new Node( left_domain, this );
192  Left->insert(d);
193  }
194  else {
195  // Not there either. Keep it here.
196  cont.push_back(d);
197  }
198  }
199 
200  }
201  else if ( Left ) {
202  // Only the one on the left exists already. Check it first.
203  if ( Contains::test(Left->MyDomain, d.first) ) {
204  // It is there. Drop into it.
205  Left->insert(d);
206  }
207  else {
208  // It isn't on the left. Split to see if it is on the right.
209  Split::test(left_domain,right_domain,MyDomain);
210  if ( Contains::test(right_domain,d.first) ) {
211  // It is there. Build it and drop into it.
212  Right = new Node( right_domain, this );
213  Right->insert(d);
214  }
215  else {
216  // Not on the right either. Keep it here.
217  cont.push_back(d);
218  }
219  }
220  }
221  }
222 
223  };
224 
225  friend class Node;
226 
227 public:
228 
229  // forward declaration of const_iterator
230  class const_iterator;
231 
232  // Forward iterator.
233  // It could be bidirectional but I'm to lazy to add operator--().
234  class iterator {
235  friend class DomainMap<Key,T,Touches,Contains,Split>;
236  friend class const_iterator;
237 
238  public:
239 
240  // Null ctor initializes p to zero so we can tell it is null.
241  iterator() : p(0) { }
242 
243  // Create one with the two pointers it needs.
245  : p(pp), v(vv)
246  {
247  }
248 
249  // equality just tests each element.
250  bool operator==(const iterator& rhs) const
251  {
252  return (p==rhs.p)&&((p==0)||(v==rhs.v));
253  }
254  bool operator!=(const iterator& rhs) const
255  {
256  return !(*this == rhs);
257  }
258 
259  // Get the current one.
261  {
262  PAssert(p != 0);
263  return *v;
264  }
265 
266  // Increment the iterator.
267  iterator& operator++() { op_pp(); return *this; }
268 
269  //mwerks private:
270  //mwerks void op_pp();
272  // Increment an iterator.
273  void op_pp()
274  {
275 
276 
277 
278  PAssert(p != 0);
279  // First try to increment inside this node.
280  if ( (++v) == p->cont.end() ) {
281  // If that one is at its end, go to the next node.
282  do {
283  // First look right.
284  if ( p->Right ) {
285  // If it is there, go there and then all the way left.
286  p = p->Right;
287  while ( p->Left )
288  p = p->Left;
289  }
290  else {
291  // If there is no right, go up until you can go right.
292  Node *y = p->Parent; // DomainMap<Key,T,Touches,Contains,Split>::Node *y;
293  while (y && (p==y->Right)) {
294  p = y;
295  y = y->Parent;
296  }
297  p = y;
298  }
299  // If the node found has nothing in it, keep looking.
300  } while (p && ((v=p->cont.begin())==p->cont.end()));
301  }
302  }
303  Node *p; // Which Node are we in.
304  typename Node::cont_type::iterator v; // Within that node where are we.
305  };
306 
307  // const_iterator: like iterator, but does return by value
309  friend class DomainMap<Key,T,Touches,Contains,Split>;
310 
311  public:
312  // Null ctor initializes p to zero so we can tell it is null.
313  const_iterator() : p(0) {}
314 
315  // Create one with the two pointers it needs.
317  : p(pp), v(vv) {}
318 
319  // Create a const_iterator from an iterator
320  const_iterator(const iterator& iter) : p(iter.p), v(iter.v) {}
321 
322  // equality just tests each element.
323  bool operator==(const const_iterator& rhs) const
324  {
325  return (p==rhs.p)&&((p==0)||(v==rhs.v));
326  }
327  bool operator!=(const const_iterator& rhs) const
328  {
329  return !(*this == rhs);
330  }
331 
332  // Get the current one.
334  {
335  PAssert(p != 0);
336  return *v;
337  }
338 
339  // Increment the iterator.
340  const_iterator& operator++() { op_pp(); return *this; }
341 
342  private:
343  //mwerks void op_pp();
345  // Increment a const_iterator.
346  void op_pp()
347  {
348 
349 
350 
351  PAssert(p != 0);
352  // First try to increment inside this node.
353  if ( (++v) == p->cont.end() ) {
354  // If that one is at its end, go to the next node.
355  do {
356  // First look right.
357  if ( p->Right ) {
358  // If it is there, go there and then all the way left.
359  p = p->Right;
360  while ( p->Left )
361  p = p->Left;
362  }
363  else {
364  // If there is no right, go up until you can go right.
365  // DomainMap<Key,T,Touches,Contains,Split>::Node *y = p->Parent;
366  Node *y = p->Parent;
367  while (y && (p==y->Right)) {
368  p = y;
369  y = y->Parent;
370  }
371  p = y;
372  }
373  // If the node found has nothing in it, keep looking.
374  } while (p && ((v=p->cont.begin())==p->cont.end()));
375  }
376  }
377  Node *p; // Which Node are we in.
378  typename Node::cont_type::iterator v; // Within that node where are we.
379  };
380 
381  // Touch iterator.
382  // Given a Key find all those that touch it.
384  friend class DomainMap<Key,T,Touches,Contains,Split>;
385  public:
386 
387  typedef std::forward_iterator_tag iterator_category;
389  typedef typename DomainMap_t::value_type *pointer;
391  typedef ptrdiff_t difference_type;
392 
393  // Null ctor initializes p to zero so we can tell it is null.
394  touch_iterator() : p(0) { }
395 
396  // equality just tests each element.
397  bool operator==(const touch_iterator& rhs) const
398  {
399  return (p==rhs.p)&&((p==0)||(v==rhs.v));
400  }
401  bool operator!=(const touch_iterator& rhs) const
402  {
403  return !(*this == rhs);
404  }
405 
406  // Get the current one.
408  {
409  PAssert(p != 0);
410  return *v;
411  }
412 
414  {
415  PAssert(p != 0);
416  return &(*v);
417  }
418 
419  // Convert to a regular iterator.
420  operator iterator()
421  {
422  return iterator(p,v);
423  }
424 
425  // Increment the iterator.
426  touch_iterator& operator++() { op_pp(); return *this; }
427 
428  private:
429  //mwerks void op_pp();
431  // Increment a touch iterator.
432  void op_pp()
433  {
434 
435 
436 
437  PAssert(p != 0);
438 
439  // Try to find one inside this node.
440  while ( (++v) != p->cont.end() )
441  if ( Touches::test(TouchThis,(*v).first) )
442  return; // Found one! Return it.
443 
444  do {
445  // Not here. Look through the tree.
446  // First look right.
447  // DomainMap<Key,T,Touches,Contains,Split>::Node *y = p->Right;
448  Node *y = p->Right;
449  if ( y && Touches::test(TouchThis,y->MyDomain) ) {
450  // If it is there and we touch it, go there and then left.
451  p = y;
452  for (y=y->Left; y && Touches::test(TouchThis,y->MyDomain); y=y->Left )
453  p = y;
454  }
455  else {
456  // If there is no right, go up until you can go right.
457  // No need to test for touching on the way up because we
458  // would not be here if the parent didn't touch.
459  for (y=p->Parent; y && (p==y->Right); y=y->Parent)
460  p = y;
461  p = y;
462  }
463  // Point to the beginning of the T's in this node.
464  if (p) {
465  for ( v = p->cont.begin() ; v != p->cont.end() ; ++v )
466  if ( Touches::test(TouchThis,(*v).first) )
467  return; // Found one! Return it.
468  }
469 
470  } while (p);
471 
472  }
473  Node *p; // Which Node are we in.
474  typename Node::cont_type::iterator v; // Within that node where are we.
475  Key TouchThis; // The Key that is being touched.
476  };
477 
478  // Create an DomainMap with a Key that has the bounding box
479  // of the whole domain. It should be true that all of the Keys
480  // inserted into the DomainMap are contained in the
481  // original Key. This bounding box is enough to determine
482  // how the recursive bisection proceeds.
483  DomainMap(const Key& d)
484  : Root(new Node(d)), Size(0)
485  {
486  }
487 
489  : Root(0), Size(0)
490  {
491  }
492 
493  // Copy ctor and assign do deep copies.
496 
497  // When you die take the tree with you.
498  ~DomainMap() { delete Root; }
499 
500  // Iterators to count over all the elements.
501  iterator begin() { return Leftmost; }
502  iterator end() { return iterator(); }
504  const_iterator end() const { return const_iterator(); }
505 
506  // Add a pair<Key,T> to it.
507  // tjw: added noSplit flag 3/24/1998
508  void insert(const value_type& d, bool noSplit=false);
509 
510  // Find the range that touches a given T.
511  std::pair<touch_iterator,touch_iterator> touch_range(const Key& t) const;
512 
513  // return how many we have.
514  size_type size() const { return Size; }
515 
516 private:
517 
518  friend class iterator;
519  friend class const_iterator;
520  friend class touch_iterator;
521 
525 
528  unsigned Size;
529 
530  // Add a pair<Key,T> to it without updating leftmost.
532  {
533  Root->insert(d);
534  Size += 1;
535  }
536  // Reset the pointer to the first one.
537  void update_leftmost();
538 };
539 
541 
542 #include "DomainMap/DomainMap.hpp"
543 
544 #endif // DOMAIN_MAP_H
545 
546 /***************************************************************************
547  * $RCSfile: DomainMap.h,v $ $Author: adelmann $
548  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:25 $
549  * IPPL_VERSION_ID: $Id: DomainMap.h,v 1.1.1.1 2003/01/23 07:40:25 adelmann Exp $
550  ***************************************************************************/
Node::cont_type::iterator v
Definition: DomainMap.h:474
void operator=(const DomainMap< Key, T, Touches, Contains, Split > &)
Definition: DomainMap.hpp:169
std::list< value_type > cont_type
Definition: DomainMap.h:102
bool operator==(const iterator &rhs) const
Definition: DomainMap.h:250
std::forward_iterator_tag iterator_category
Definition: DomainMap.h:387
value_type operator*() const
Definition: DomainMap.h:333
Node(const Key &d, Node *p=0)
Definition: DomainMap.h:109
Definition: rbendmap.h:8
~DomainMap()
Definition: DomainMap.h:498
Contains contains
Definition: DomainMap.h:523
unsigned Size
Definition: DomainMap.h:528
DomainMap< Key, T, Touches, Contains, Split > DomainMap_t
Definition: DomainMap.h:78
const_iterator begin() const
Definition: DomainMap.h:503
const_iterator & operator++()
Definition: DomainMap.h:340
bool operator==(const const_iterator &rhs) const
Definition: DomainMap.h:323
unsigned size_type
Definition: DomainMap.h:79
iterator end()
Definition: DomainMap.h:502
DomainMap_t::value_type * pointer
Definition: DomainMap.h:389
static bool test(const NDIndex< Dim > &a, const NDIndex< Dim > &b)
Definition: NDIndex.h:274
const_iterator(Node *pp, typename Node::cont_type::iterator vv)
Definition: DomainMap.h:316
void insert(const value_type &d, bool noSplit=false)
Definition: DomainMap.hpp:43
void insert(const value_type &d, bool noSplit=false)
Definition: DomainMap.h:125
DomainMap_t::value_type value_type
Definition: DomainMap.h:388
Node::cont_type::iterator v
Definition: DomainMap.h:378
T mapped_type
Definition: DomainMap.h:82
bool operator!=(const iterator &rhs) const
Definition: DomainMap.h:254
value_type * operator->()
Definition: DomainMap.h:413
DomainMap_t::value_type & reference
Definition: DomainMap.h:390
friend class const_iterator
Definition: DomainMap.h:519
iterator begin()
Definition: DomainMap.h:501
iterator(Node *pp, typename Node::cont_type::iterator vv)
Definition: DomainMap.h:244
friend class iterator
Definition: DomainMap.h:518
const_iterator(const iterator &iter)
Definition: DomainMap.h:320
value_type(const Key &k, const T &t)
Definition: DomainMap.h:88
std::pair< touch_iterator, touch_iterator > touch_range(const Key &t) const
Definition: DomainMap.hpp:103
DomainMap(const Key &d)
Definition: DomainMap.h:483
touch_iterator & operator++()
Definition: DomainMap.h:426
static bool test(NDIndex< Dim > &l, NDIndex< Dim > &r, const NDIndex< Dim > &a)
Definition: NDIndex.h:296
void insert_noupdate(const value_type &d)
Definition: DomainMap.h:531
T * value_type(const SliceIterator< T > &)
value_type & operator*()
Definition: DomainMap.h:407
Node::cont_type::iterator v
Definition: DomainMap.h:304
bool operator!=(const const_iterator &rhs) const
Definition: DomainMap.h:327
Node * Root
Definition: DomainMap.h:526
Split split
Definition: DomainMap.h:524
value_type & operator*()
Definition: DomainMap.h:260
#define PAssert(c)
Definition: PAssert.h:117
bool operator==(const touch_iterator &rhs) const
Definition: DomainMap.h:397
Definition: Pooled.h:20
iterator Leftmost
Definition: DomainMap.h:527
std::string::iterator iterator
Definition: MSLang.h:16
const_iterator end() const
Definition: DomainMap.h:504
size_type size() const
Definition: DomainMap.h:514
cont_type cont
Definition: DomainMap.h:106
iterator & operator++()
Definition: DomainMap.h:267
bool operator!=(const touch_iterator &rhs) const
Definition: DomainMap.h:401
void update_leftmost()
Definition: DomainMap.hpp:63
Definition: NDIndex.h:292
Key key_type
Definition: DomainMap.h:81
static bool test(const NDIndex< Dim > &a, const NDIndex< Dim > &b)
Definition: NDIndex.h:285
Touches touches
Definition: DomainMap.h:522