Line data Source code
1 : /*
2 : * Copyright (c) 2009-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #ifndef __H__PCL__PCL_COMMUNICATION_STRUCTS__
34 : #define __H__PCL__PCL_COMMUNICATION_STRUCTS__
35 :
36 : #include <iterator>
37 : #include <vector>
38 : #include <list>
39 : #include <map>
40 : #include <algorithm>
41 : #include "common/util/smart_pointer.h"
42 : #include "common/util/binary_buffer.h"
43 : #include "common/error.h"
44 :
45 : namespace pcl
46 : {
47 :
48 : /// \addtogroup pcl
49 : /// \{
50 :
51 : ////////////////////////////////////////////////////////////////////////
52 : // type-traits
53 : /// associate internally used types with an external typename
54 : /**
55 : * By default it is assumed, that the external typename and the element
56 : * type used in interfaces match.
57 : *
58 : * You may specialize type_traits for your own types through template
59 : * specialization. Be sure to specialize them before you use any
60 : * pcl-classes with your type.
61 : */
62 : template <class TType>
63 : struct type_traits
64 : {
65 : typedef TType Elem; /// Type of interface elements
66 : };
67 :
68 :
69 : ////////////////////////////////////////////////////////////////////////
70 : // Interface Categories
71 : /// Interface tags allow to differentiate between interfaces with different features
72 : namespace interface_tags
73 : {
74 : /** Every interface has to feature this tag (at least indirectly - by tag-derivation).
75 : * This tag simply says that one may iterate over the elements of the
76 : * interface.
77 : *
78 : * Additionally you may receive the local_src_id. This id represents the
79 : * sender during local communication (communication on one process only).
80 : * Values < 0 mark the sender as invalid (during local communication).
81 : * The src-id is ignored during parallel communication. Instead pcl::ProcRank
82 : * is used.
83 : *
84 : * typedefs that have to be featured in such interfaces:
85 : * - category_tag
86 : * - iterator
87 : * - const_iterator
88 : * - Type
89 : * - Element
90 : *
91 : * Methods that have to be featured in such interfaces:
92 : * - iterator begin();
93 : * - iterator end();
94 : * - const_iterator begin() const;
95 : * - const_iterator end() const;
96 : * - Element& get_element(iterator iter);
97 : * - const Element& get_element(iterator iter) const;
98 : * - int get_target_proc();
99 : * - void swap(Interface& interface);
100 : */
101 : class basic_interface_tag {};
102 :
103 : /** The ordered_interface_tag derives from the basic_interface_tag.
104 : * Thus all classes and methods that may operate on interfaces
105 : * with the basic_interface_tag will operate on interfaces with
106 : * this tag, too.
107 : *
108 : * Interfaces with this category have to associated a local id with
109 : * each entry.
110 : *
111 : * Methods that have to be featured in such interfaces:
112 : * - get_local_id(iterator iter);
113 : */
114 : class ordered_interface_tag : public basic_interface_tag {};
115 : }// end of namespace interface_tags
116 :
117 :
118 : ////////////////////////////////////////////////////////////////////////
119 : // BasicInterface
120 : /// You may add elements to this interface and iterate over them
121 : /**
122 : * This interface type features a minimal set of methods that is
123 : * required to actually work with it.
124 : * You may add new elements, erase old ones and iterate through them.
125 : *
126 : * In order to access the associated element of an iterator you should
127 : * use get_element (not the * operator of the iterator). This increases
128 : * the flexibility of your code.
129 : *
130 : * You may specify a stl-container compatible type that is used to store.
131 : * the elements. Supported types are std::vector and std::list.
132 : *
133 : * TContainer defaults to std::vector. This is the best option if your
134 : * interface is mainly used static or grows, but is considerably slower
135 : * than std::list if you want to erase elements often.
136 : * For dynamic interfaces std::list may be the better option.
137 : */
138 : template <class TType,
139 : template <class T, class Alloc> class TContainer = std::vector,
140 : template <class T> class TAlloc = std::allocator>
141 : class BasicInterface
142 : {
143 : protected:
144 : typedef typename type_traits<TType>::Elem TElem;
145 : typedef TContainer<TElem, TAlloc<TElem> > ElemContainer;
146 :
147 : public:
148 : typedef interface_tags::basic_interface_tag category_tag;
149 :
150 : typedef TType Type;
151 : typedef typename type_traits<TType>::Elem Element;
152 : typedef typename ElemContainer::iterator iterator;
153 : typedef typename ElemContainer::const_iterator const_iterator;
154 :
155 : public:
156 : BasicInterface(int targetProc = -1) : m_size(0), m_targetProc(targetProc) {};
157 :
158 : inline iterator push_back(const Element& elem) {++m_size; return m_elements.insert(m_elements.end(), elem);}
159 : inline iterator erase(iterator iter) {--m_size; return m_elements.erase(iter);}
160 :
161 : inline iterator begin() {return m_elements.begin();}
162 : inline iterator end() {return m_elements.end();}
163 : inline const_iterator begin() const {return m_elements.begin();}
164 : inline const_iterator end() const {return m_elements.end();}
165 :
166 : inline Element& get_element(iterator iter) {return *iter;}
167 : inline const Element& get_element(const_iterator iter) const {return *iter;}
168 :
169 : /// returns the number of elements that are stored in the interface.
170 : inline size_t size() const {return m_size;}
171 : inline bool empty() const {return size() == 0;}
172 :
173 : int get_target_proc() const {return m_targetProc;}
174 :
175 : /// swaps the content of two interfaces.
176 : /** m_elements, m_size and m_targetProc are swapped.*/
177 : void swap(BasicInterface& interface)
178 : {
179 : using std::swap;
180 : m_elements.swap(interface.m_elements);
181 : swap(m_size, interface.m_size);
182 : swap(m_targetProc, interface.m_targetProc);
183 : }
184 :
185 : /// sort the entries in this interface.
186 : template <class TCompare>
187 : void sort(TCompare cmp)
188 : {
189 : using std::sort;
190 : m_elements.sort(cmp);
191 : }
192 :
193 : protected:
194 : ElemContainer m_elements;
195 : size_t m_size;
196 : int m_targetProc;
197 : };
198 :
199 : ////////////////////////////////////////////////////////////////////////
200 : // OrderedInterface
201 : /// You may add elements to this interface and iterate over them
202 : /** You may retrieve a localID for each element in the interface*/
203 : template <class TType,
204 : template <class T, class Alloc> class TContainer = std::vector,
205 : template <class T> class TAlloc = std::allocator>
206 : class OrderedInterface
207 : {
208 : protected:
209 : typedef typename type_traits<TType>::Elem TElem;
210 :
211 : struct InterfaceEntry
212 : {
213 : InterfaceEntry(TElem e, size_t locID) : elem(e), localID(locID) {}
214 :
215 : TElem elem;
216 : size_t localID;
217 : };
218 :
219 : template <class TElemCmp>
220 : struct InterfaceEntryCmp{
221 : InterfaceEntryCmp(TElemCmp elemCmp) : m_elemCmp(elemCmp) {}
222 : bool operator()(InterfaceEntry const& e1, InterfaceEntry const& e2)
223 : {return m_elemCmp(e1.elem, e2.elem);}
224 : TElemCmp m_elemCmp;
225 : };
226 :
227 : typedef TContainer<InterfaceEntry, TAlloc<InterfaceEntry> >
228 : ElemContainer;
229 :
230 : public:
231 : typedef TType Type;
232 : typedef typename type_traits<TType>::Elem Element;
233 :
234 : typedef interface_tags::ordered_interface_tag category_tag;
235 :
236 : typedef typename ElemContainer::iterator iterator;
237 : typedef typename ElemContainer::const_iterator const_iterator;
238 :
239 : public:
240 : OrderedInterface(int targetProc = -1) :
241 : m_size(0),
242 : m_targetProc(targetProc),
243 : m_idCounter(1) {}
244 :
245 : inline iterator push_back(const Element& elem)
246 : {
247 : ++m_size;
248 : return m_elements.insert(m_elements.end(),
249 : (InterfaceEntry(elem, get_free_id())));
250 : }
251 :
252 : /**
253 : * @brief Insert an element before the passed iterator.
254 : *
255 : * The insertion iterator is best determined using the find_insert_pos_sorted()
256 : * method designed for this purpose.
257 : *
258 : * @return iterator to inserted element
259 : * @note The method is intended for manipulation of the interface
260 : * after it has been ordered and only suited for a small
261 : * number of insertions (typically a single insertion).
262 : * For more insertions, consider push_back() and re-ordering.
263 : * @warning This method is highly experimental. Use with extreme caution!
264 : */
265 : inline iterator insert(const Element& elem, iterator insertBefore)
266 : {
267 : ++m_size;
268 :
269 : size_t startNumber = 0;
270 : if (insertBefore != end())
271 : startNumber = insertBefore->localID;
272 :
273 : iterator it = m_elements.insert(insertBefore, (InterfaceEntry(elem, get_free_id())));
274 :
275 : if (startNumber)
276 : {
277 : // we have to reset all local indices
278 : --startNumber;
279 : for (iterator iter = it; iter != m_elements.end(); ++iter)
280 : (*iter).localID = ++startNumber;
281 : }
282 :
283 : return it;
284 : }
285 :
286 : inline iterator erase(iterator iter)
287 : {
288 : --m_size;
289 : return m_elements.erase(iter);
290 : }
291 :
292 : inline iterator begin() {return m_elements.begin();}
293 : inline iterator end() {return m_elements.end();}
294 :
295 : inline const_iterator begin() const {return m_elements.begin();}
296 : inline const_iterator end() const {return m_elements.end();}
297 :
298 : inline Element& get_element(iterator iter) {return (*iter).elem;}
299 : inline size_t get_local_id(iterator iter) {return (*iter).localID;}
300 :
301 : inline const Element& get_element(const_iterator iter) const {return (*iter).elem;}
302 : inline size_t get_local_id(const_iterator iter) const {return (*iter).localID;}
303 :
304 :
305 : /// returns the number of elements that are stored in the interface.
306 0 : inline size_t size() const {return m_size;}
307 : inline bool empty() const {return size() == 0;}
308 :
309 : int get_target_proc() const {return m_targetProc;}
310 :
311 : /// returns true if iter1 < iter2.
312 : static inline bool cmp(iterator iter1, iterator iter2,
313 : const std::input_iterator_tag&)
314 : {
315 : return (*iter1).localID < (*iter2).localID;
316 : }
317 :
318 : /// swaps the content of two interfaces.
319 : /** m_elements, m_size, m_targetProc and m_idCounter are swapped.*/
320 : void swap(OrderedInterface& interface)
321 : {
322 : using std::swap;
323 : m_elements.swap(interface.m_elements);
324 : swap(m_size, interface.m_size);
325 : swap(m_targetProc, interface.m_targetProc);
326 : swap(m_idCounter, interface.m_idCounter);
327 : }
328 :
329 : /// sort the entries in this interface.
330 : template <class TCompare>
331 : void sort(TCompare cmp)
332 : {
333 : using std::sort;
334 : InterfaceEntryCmp<TCompare> ieCmp(cmp);
335 : m_elements.sort(ieCmp);
336 :
337 : // we have to reset all local indices
338 : m_idCounter = 1;
339 : for(iterator iter = m_elements.begin(); iter != m_elements.end(); ++iter)
340 : (*iter).localID = m_idCounter++;
341 : }
342 :
343 : /**
344 : * @brief find insertion position for an element to be inserted
345 : * @return iterator to insertion position if found; end-iterator otherwise
346 : * @warning This method implicitly requires the interface to be sorted
347 : * w.r.t. the passed compare object. If it is not, the position
348 : * might not be correct.
349 : */
350 : template <class TCompare>
351 : iterator find_insert_pos_sorted(const Element e, TCompare cmp)
352 : {
353 : InterfaceEntryCmp<TCompare> ieCmp(cmp);
354 : iterator it_begin = m_elements.begin();
355 : iterator it_end = m_elements.end();
356 : InterfaceEntry iEntry(e, 0);
357 : return std::lower_bound(it_begin, it_end, iEntry, ieCmp);
358 : }
359 :
360 :
361 : protected:
362 : /// returns a free id in each call.
363 : /** Those ids are not necessarily aligned.*/
364 : size_t get_free_id()
365 : {
366 : if(m_idCounter == 0)
367 : {
368 : m_idCounter = 1;
369 : // we have to reset all entries
370 : for(iterator iter = begin(); iter != end(); ++iter)
371 : (*iter).localID = m_idCounter++;
372 : }
373 :
374 : return m_idCounter++;
375 : }
376 :
377 : protected:
378 : ElemContainer m_elements;
379 : size_t m_size;
380 : int m_targetProc;
381 : size_t m_idCounter;
382 : };
383 :
384 :
385 : ////////////////////////////////////////////////////////////////////////
386 : // Layout Categories
387 : /// Layout tags allow to differentiate between layouts with different features
388 : namespace layout_tags
389 : {
390 : /// marks a layout as a single-level layout
391 : /**
392 : * Typedefs that have to be supported by a layout with this tag:
393 : * - category_tag
394 : * - iterator
395 : * - Interface
396 : * - Type
397 : * - Element
398 : *
399 : * Methods that have to be supported by a layout with this tag:
400 : * - iterator begin()
401 : * - iterator end()
402 : * - Interface& interface(iterator iter)
403 : * - int proc_id(iterator iter)
404 : * - iterator erase(iterator iter)
405 : * - int get_local_src_id()
406 : */
407 : class single_level_layout_tag {};
408 :
409 : /// marks a layout as a multi-level layout
410 : /**
411 : * Typedefs that have to be supported by a layout with this tag:
412 : * - category_tag
413 : * - iterator
414 : * - Interface
415 : * - Element
416 : *
417 : * Methods that have to be supported by a layout with this tag:
418 : * - size_t num_levels()
419 : * - iterator begin(size_t level)
420 : * - iterator end(size_t level)
421 : * - Interface& interface(iterator iter)
422 : * - int proc_id(iterator iter)
423 : * - iterator erase(iterator iter, size_t level)
424 : * - int get_local_src_id()
425 : */
426 : class multi_level_layout_tag {};
427 :
428 : }// end of namespace layout_tags
429 :
430 :
431 : ////////////////////////////////////////////////////////////////////////
432 : // SingleLevelLayout
433 : /// the standard single-level-layout implementation
434 : /**
435 : * A Layout is a collection of interfaces.
436 : * Each interface is associated with a process-id.
437 : *
438 : * This layout type supports the requirements of the
439 : * pcl::layout_tags::single_level_layout_tag category.
440 : *
441 : * The layout passes its local srcID on to created interfaces.
442 : *
443 : * Additionally it features methods that allow to add new interfaces
444 : *
445 : * In order to allow one method to operate both on a SingleLevelLayout
446 : * and a MultiLevelLayout, the (size_t level = 0) convenience parameter
447 : * has been added to some methods. Those parameters are ignored throughout
448 : * the whole implementation.
449 : */
450 : template <class TInterface>
451 : class SingleLevelLayout
452 : {
453 : public:
454 : SingleLevelLayout() {}
455 :
456 : ////////////////////////////////////////////////
457 : // typedefs required by implementation
458 : /// an interface-map is a list of interfaces, each associated with a process id.
459 : typedef std::map<int, TInterface> InterfaceMap;
460 :
461 : ////////////////////////////////////////////////
462 : // typedefs required by layout-tag
463 : /// Layout category
464 : typedef layout_tags::single_level_layout_tag category_tag;
465 :
466 : /// Interface type
467 : typedef TInterface Interface;
468 :
469 : /// Type
470 : typedef typename Interface::Type Type;
471 :
472 : /// Element type
473 : typedef typename Interface::Element Element;
474 :
475 : /// An iterator that allows to iterate over the interfaces stored in the layout.
476 : typedef typename InterfaceMap::iterator iterator;
477 : typedef typename InterfaceMap::const_iterator const_iterator;
478 :
479 : public:
480 : ////////////////////////////////////////////////
481 : // methods required by the layout-tag
482 :
483 : /// returns the iterator to the first interface of the layout.
484 : /** You should access the values of this iterator using the methods
485 : Layout::interface and Layout::proc_id.*/
486 : inline iterator begin(size_t level = 0) {return m_interfaceMap.begin();}
487 : inline const_iterator begin(size_t level = 0) const {return m_interfaceMap.begin();}
488 :
489 : /// returns the iterator to the last interface of the layout.
490 : /** You should access the values of this iterator using the methods
491 : Layout::interface and Layout::proc_id.*/
492 : inline iterator end(size_t level = 0) {return m_interfaceMap.end();}
493 : inline const_iterator end(size_t level = 0) const {return m_interfaceMap.end();}
494 :
495 : /// returns true if the layout has no interfaces.
496 : /** Note that this method only tells whether there are interfaces or not.
497 : * To check whether there are any elements use has_interface_elements.
498 : */
499 : inline bool empty(size_t level = 0) const {return begin() == end();}
500 :
501 : /// returns 1
502 : inline size_t num_levels() const {return 1;}
503 :
504 : /// returns the interface to the given iterator.
505 : inline Interface& interface(iterator iter) {return iter->second;}
506 : inline const Interface& interface(const_iterator iter) const {return iter->second;}
507 :
508 : /// returns the target process of the interface given in iterator
509 : inline int proc_id(iterator iter) const {return iter->first;}
510 : inline int proc_id(const_iterator iter) const {return iter->first;}
511 :
512 : /// erases the interface at the given iterator.
513 : /** returns an iterator to the next interface.*/
514 : inline iterator erase(iterator iter, size_t level = 0)
515 : {
516 : iterator tIter = iter++;
517 : m_interfaceMap.erase(tIter);
518 : return iter;
519 : }
520 :
521 : /// clears the layout
522 : void clear() {m_interfaceMap.clear();}
523 :
524 : /// returns the interface to the given process.
525 : /** if the queried interface exist, it will be returned.
526 : * If not it will be created.
527 : * The new interfaces localSrcID will be set to the localSrcID of this layout.*/
528 : inline Interface& interface(int procID, size_t level = 0)
529 : {
530 : iterator iter = m_interfaceMap.find(procID);
531 : if(iter != m_interfaceMap.end())
532 : return iter->second;
533 : return m_interfaceMap.insert(make_pair(procID, Interface(procID))).first->second;
534 : }
535 :
536 : inline const Interface& interface(int procID, size_t level = 0) const
537 : {
538 : const_iterator iter = m_interfaceMap.find(procID);
539 : UG_ASSERT(iter != m_interfaceMap.end(), "trying to access an non-existing interface in a constant layout");
540 : return iter->second;
541 : }
542 :
543 : /// returns true if an interface to the given procID already exists.
544 : inline bool interface_exists(int procID, size_t level = 0) const
545 : {return m_interfaceMap.find(procID) != m_interfaceMap.end();}
546 :
547 : /// returns the sum of the interface sizes
548 : inline size_t num_interface_elements() const
549 : {
550 : size_t sum = 0;
551 : for(const_iterator iter = begin(); iter != end(); ++iter)
552 : sum += interface(iter).size();
553 : return sum;
554 : }
555 :
556 : /// returns true if the layout contains interface elements
557 : inline bool has_interface_elements() const
558 : {
559 : for(iterator iter = begin(); iter != end(); ++iter){
560 : if(!interface(iter).empty())
561 : return true;
562 : }
563 : return false;
564 : }
565 :
566 : /// returns the number of interfaces in the layout
567 : inline size_t num_interfaces(size_t level = 0) const
568 : {
569 : return m_interfaceMap.size();
570 : }
571 :
572 : /// sort the entries in all interfaces of this layout
573 : template <class TCompare>
574 : void sort_interface_entries(TCompare cmp)
575 : {
576 : for(iterator iter = begin(); iter != end(); ++iter)
577 : interface(iter).sort(cmp);
578 : }
579 :
580 : private:
581 : /*
582 : /// copy-constructor is not yet implemented
583 : SingleLevelLayout(const SingleLevelLayout& sll);
584 :
585 : /// assignement-operator is not yet implemented
586 : SingleLevelLayout& operator = (const SingleLevelLayout& sll);
587 : */
588 : protected:
589 : /// holds the interfaces in a map.
590 : InterfaceMap m_interfaceMap;
591 : };
592 :
593 : ////////////////////////////////////////////////////////////////////////
594 : // MultiLevelLayout
595 : /// the standard multi-level-layout implementation
596 : /**
597 : * A MultiLevelLayout is a collection of interfaces, which are
598 : * grouped in different levels.
599 : *
600 : * Each interface is associated with a process-id.
601 : * If the localSrcID of this layout == -1 then, when a new level is
602 : * created, it's local srcID is automatically
603 : * initialized with the level index. localSrcIDs of interfaces created on
604 : * those levels are then initialised with the level index, too.
605 : *
606 : * If the localSrcID >= 0 it is simply passed on to the level-layouts.
607 : *
608 : * This layout type supports the requirements of the
609 : * pcl::layout_tags::multi_level_layout_tag category.
610 : *
611 : * Additionally it features methods that allow to add new interfaces.
612 : */
613 : template <class TInterface>
614 : class MultiLevelLayout
615 : {
616 : public:
617 : ////////////////////////////////////////////////
618 : // typedefs required by implementation
619 : /// on each level a single-level-layout is used
620 : typedef SingleLevelLayout<TInterface> LevelLayout;
621 :
622 : ////////////////////////////////////////////////
623 : // typedefs required by layout-tag
624 : /// Layout category
625 : typedef layout_tags::multi_level_layout_tag category_tag;
626 :
627 : /// Interface type
628 : typedef TInterface Interface;
629 :
630 : /// Type
631 : typedef typename Interface::Type Type;
632 :
633 : /// Element type
634 : typedef typename Interface::Element Element;
635 :
636 : /// An iterator that allows to iterate over the interfaces stored in the layout.
637 : typedef typename LevelLayout::iterator iterator;
638 : typedef typename LevelLayout::const_iterator const_iterator;
639 :
640 : public:
641 : MultiLevelLayout() {}
642 : MultiLevelLayout(const MultiLevelLayout& mll) {assign_layout(mll);}
643 :
644 : ~MultiLevelLayout() {clear();}
645 :
646 : MultiLevelLayout& operator = (const MultiLevelLayout& mll)
647 : {
648 : assign_layout(mll);
649 : return *this;
650 : }
651 :
652 : ////////////////////////////////////////////////
653 : // methods required by the layout-tag
654 :
655 : /// returns the iterator to the first interface of the layout in the given level.
656 : /** You should access the values of this iterator using the methods
657 : * Layout::interface and Layout::proc_id.
658 : * Make sure that the level matches the level in the associated end() call.*/
659 0 : inline iterator begin(size_t level) {require_level(level); return m_vLayouts[level]->begin();}
660 0 : inline const_iterator begin(size_t level) const {require_level(level); return m_vLayouts[level]->begin();}
661 :
662 : /// returns the iterator to the last interface of the layout in the given level.
663 : /** You should access the values of this iterator using the methods
664 : * Layout::interface and Layout::proc_id.
665 : * Make sure that the level matches the level in the associated begin() call.*/
666 0 : inline iterator end(size_t level) {require_level(level); return m_vLayouts[level]->end();}
667 0 : inline const_iterator end(size_t level) const {require_level(level); return m_vLayouts[level]->end();}
668 :
669 : /// returns true if the layout has no interfaces on the given level.
670 : /** Note that this method only tells whether there are interfaces or not.
671 : * To check whether there are any elements use has_interface_elements.
672 : */
673 : inline bool empty(size_t level) {return begin(level) == end(level);}
674 0 : inline bool empty(size_t level) const {return begin(level) == end(level);}
675 :
676 : /// returns true if the layout has no interfaces.
677 : /** Note that this method only tells whether there are interfaces or not.
678 : * To check whether there are any elements use has_interface_elements.
679 : */
680 : inline bool empty() const {for(size_t l = 0; l < num_levels(); ++l){if(!empty(l)) return false;} return true;}
681 :
682 : /// returns the interface to the given iterator.
683 : inline Interface& interface(iterator iter) {return iter->second;}
684 : inline const Interface& interface(const_iterator iter) const {return iter->second;}
685 :
686 : /// returns the interface to the given iterator.
687 : inline int proc_id(const_iterator iter) const {return iter->first;}
688 :
689 : /// erases the interface at the given iterator on the given level.
690 : /** returns an iterator to the next interface.*/
691 0 : inline iterator erase(iterator iter, size_t level) {return m_vLayouts[level]->erase(iter);}
692 :
693 : /// returns the number of levels.
694 : inline size_t num_levels() const {return m_vLayouts.size();}
695 :
696 : ////////////////////////////////////////////////
697 : // methods that enhance the layout-tag
698 : /// deletes all levels.
699 : void clear()
700 : {
701 : for(size_t i = 0; i < m_vLayouts.size(); ++i)
702 : delete m_vLayouts[i];
703 : m_vLayouts.clear();
704 : }
705 :
706 : /// returns the interface to the given process.
707 : /** if the interface doesn't exist yet, it will be created.*/
708 : inline Interface& interface(int procID, size_t level) {require_level(level); return m_vLayouts[level]->interface(procID);}
709 : inline const Interface& interface(int procID, size_t level) const {require_level(level); return m_vLayouts[level]->interface(procID);}
710 :
711 : /// returns true if an interface to the given procID on the given level already exists.
712 : inline bool interface_exists(int procID, size_t level) {require_level(level); return m_vLayouts[level]->interface_exists(procID);}
713 : inline bool interface_exists(int procID, size_t level) const {require_level(level); return m_vLayouts[level]->interface_exists(procID);}
714 :
715 : /// returns true if an interface to the given procID already exists.
716 : inline bool interface_exists(int procID) {for(size_t i = 0; i < num_levels(); ++i){if(m_vLayouts[i]->interface_exists(procID)) return true;} return false;}
717 : inline bool interface_exists(int procID) const {for(size_t i = 0; i < num_levels(); ++i){if(m_vLayouts[i]->interface_exists(procID)) return true;} return false;}
718 :
719 : /// returns the layout at the given level.
720 : /** If level >= num_levels() then the layouts in between
721 : will be automatically created.*/
722 : inline LevelLayout& layout_on_level(int level) {require_level(level); return *m_vLayouts[level];}
723 0 : inline const LevelLayout& layout_on_level(int level) const {require_level(level); return *m_vLayouts[level];}
724 :
725 : /// returns the sum of the interface sizes
726 : inline size_t num_interface_elements() const
727 : {
728 : size_t sum = 0;
729 : for(size_t lvl = 0; lvl < num_levels(); ++lvl){
730 : for(iterator iter = begin(lvl); iter != end(lvl); ++iter)
731 : sum += interface(iter).size();
732 : }
733 : return sum;
734 : }
735 :
736 : /// returns true if the layout contains any interface entries
737 : inline bool has_interface_elements() const
738 : {
739 : for(size_t lvl = 0; lvl < num_levels(); ++lvl){
740 : for(iterator iter = begin(lvl); iter != end(lvl); ++iter){
741 : if(!interface(iter).empty())
742 : return true;
743 : }
744 : }
745 : return false;
746 : }
747 :
748 : /// returns the number of interfaces in the layout
749 : inline size_t num_interfaces(size_t level) const
750 : {
751 : return m_vLayouts[level].size();
752 : }
753 :
754 : /// sort the entries in all interfaces of this layout
755 : template <class TCompare>
756 : void sort_interface_entries(TCompare cmp)
757 : {
758 : for(size_t lvl = 0; lvl < num_levels(); ++lvl)
759 : layout_on_level(lvl).sort_interface_entries(cmp);
760 : }
761 :
762 : protected:
763 : /// adds num new levels.
764 0 : inline void new_levels(size_t num) {for(size_t i = 0; i < num; ++i) m_vLayouts.push_back(new LevelLayout());}
765 :
766 : /// if the required level doesn't exist yet, it will created.
767 0 : inline void require_level(size_t level) {if(level >= num_levels()) new_levels(level - num_levels() + 1);}
768 0 : inline void require_level(size_t level) const {if(level >= num_levels()){UG_THROW("Level too high: " << level << ", while num_levels == " << num_levels());}}
769 :
770 : /// clears this layout and then copies all levels from the given layout
771 : void assign_layout(const MultiLevelLayout& mll)
772 : {
773 : clear();
774 : for(size_t i = 0; i < mll.m_vLayouts.size(); ++i)
775 : m_vLayouts.push_back(new LevelLayout(*mll.m_vLayouts[i]));
776 : }
777 :
778 : protected:
779 : std::vector<LevelLayout*> m_vLayouts;
780 : };
781 :
782 : ////////////////////////////////////////////////////////////////////////
783 : // ICommunicationPolicy
784 : /// specializations are responsible to pack and unpack interface data during communication.
785 : /** Make sure that you use the same communication-policy for send and receive operations.
786 : * Otherwise problems regarding buffer-sizes may occur.
787 : */
788 : template <class TLayout>
789 : class ICommunicationPolicy
790 : {
791 : public:
792 : typedef TLayout Layout;
793 : typedef typename Layout::Interface Interface;
794 :
795 : virtual ~ICommunicationPolicy() {}
796 :
797 : ////////////////////////////////
798 : // COLLECT AND EXTRACT
799 : /// returns the size of the buffer in bytes, that will be required for interface-communication.
800 : /** Determines the size of the buffer on which the extract and receive methods
801 : * for the given interface will operate.
802 : * If the buffer-size can't be calculated on both sides (sender and receiver)
803 : * this method should return -1. This will lead to an additional communication
804 : * step in which buffer-sizes will be exchanged.
805 : * If the buffer-size can be calculated on both sides, it makes sense to do so,
806 : * since this leads to less communication and overall improved performance.
807 : * The buffer-size has to exactly match the size of required memory. Make sure that you
808 : * completely fill the buffer during collect(...) and that you read all data during
809 : * extract(...).
810 : * The default implementation returns -1.
811 : */
812 : virtual int
813 : get_required_buffer_size(const Interface& interface) {return -1;}
814 :
815 : ////////////////////////////////
816 : // COLLECT
817 : /// signals the beginning of a layout collection.
818 : /** the default implementation returns true and does nothing else.
819 : * This method is only called on processes which collect data.*/
820 : virtual bool
821 : begin_layout_collection(const Layout* pLayout) {return true;}
822 :
823 : /// signals the end of a layout collection
824 : /** the default implementation returns true and does nothing else.
825 : * This method is only called on processes which collect data.*/
826 : virtual bool
827 : end_layout_collection(const Layout* pLayout) {return true;}
828 :
829 : /// should write data which is associated with the interface elements to the buffer.
830 : virtual bool
831 : collect(ug::BinaryBuffer& buff, const Interface& interface) = 0;
832 :
833 : ////////////////////////////////
834 : // EXTRACT
835 : /// signals the beginning of a layout extraction.
836 : /** the default implementation returns true and does nothing else.
837 : * This method is only called on processes which extract data.*/
838 : virtual bool
839 : begin_layout_extraction(const Layout* pLayout) {return true;}
840 :
841 : /// signals the end of a layout extraction
842 : /** the default implementation returns true and does nothing else.
843 : * This method is only called on processes which extract data.*/
844 : virtual bool
845 : end_layout_extraction(const Layout* pLayout) {return true;}
846 :
847 : /// signals that a new layout-level will now be processed.
848 : /** This is primarily interesting for layout-extraction of multi-level-layouts.
849 : * Before extract is called for the interfaces of one level of a layout,
850 : * begin_level_extraction(level) is called.
851 : * If single-level-layouts are processed, this method is called
852 : * once with level = 0.
853 : * This method is called after begin_layout_extraction and before
854 : * the associated extract calls.*/
855 : virtual void begin_level_extraction(int level) {}
856 :
857 : /// extract data from the buffer and assigns it to the interface-elements.
858 : /** If this method is called between calls to begin_layout_extraction and
859 : end_layout_extraction, the interface that is passed to this method
860 : belongs to the layout.*/
861 : virtual bool
862 : extract(ug::BinaryBuffer& buff, const Interface& interface) = 0;
863 : };
864 :
865 : // end group pcl
866 : /// \}
867 :
868 : }// end of namespace pcl
869 :
870 : #endif
|