OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
13Steve Karmesin
14Dakota Scientific Software
15February 1996
16
17A DomainMap holds a bunch of Domains of type Key in such a way that you
18can quickly look up which Keys's touch a given one and an object
19associated with that Key.
20
21Key must have the following operations defined:
22
23bool touches(const Key&, const Key&);
24Return true if the Keys touch, false if they don't.
25
26bool contains(const Key& l, const Key& r);
27Return true if l contains r, false otherwise.
28
29bool split(pair<const Key,const Key>&, const Key& k);
30Split one Key into two, and return a boolean for success.
31
32split and containes need to have the following properties for
33consistent behavior:
34
351. If Key A is split into A1 and A2, then
36 contains(A,A1)==true and contains(A,A2)==true.
37
382. 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
413. If contains(A,B)==true and contains(B,C)==true then we must have
42 contains(A,C)==true.
43
44Each Key is associated with a T. We enter those Ts into the
45DomainMap and later pull out the ones that touch a given Key.
46
47touches(const Key&) must do two things:
481) It must be fast.
492) It must be right.
50
51"Fast" means that it has to be at worst linear in the number of hits,
52times 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
55given Key exactly once.
56
57This currently has very small subset of the capabilites of an STL map..
58It 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
70template < class Key, class T , class Touches, class Contains, class Split >
72{
73public:
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
91private:
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.
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.
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
222public:
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.
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;
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
511private:
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
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
value_type & operator*()
Definition: DomainMap.h:255
bool operator==(const iterator &rhs) const
Definition: DomainMap.h:245
iterator(Node *pp, typename Node::cont_type::iterator vv)
Definition: DomainMap.h:239
iterator & operator++()
Definition: DomainMap.h:262
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
value_type & operator*()
Definition: DomainMap.h:402
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
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