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