Actual source code: XSifter.hh
1: #ifndef included_ALE_Sifter_hh
2: #define included_ALE_Sifter_hh
5: #include <boost/multi_index_container.hpp>
6: #include <boost/multi_index/key_extractors.hpp>
7: #include <boost/multi_index/ordered_index.hpp>
8: #include <boost/multi_index/composite_key.hpp>
10: #include <boost/lambda/lambda.hpp>
11: using namespace ::boost::lambda;
13: #include <iostream>
16: #ifndef included_ALE_hh
17: #include <ALE.hh>
18: #endif
21: namespace ALE {
23: class XObject {
24: protected:
25: int _debug;
26: public:
27: XObject(const int debug = 0) : _debug(debug) {};
28: XObject(const XObject& xobject) : _debug(xobject._debug) {};
29: //
30: int debug(const int& debug = -1) {if(debug >= 0) {this->_debug = debug;} return this->_debug;};
31: };// class XObject
33: class XParallelObject : public XObject {
34: protected:
35: MPI_Comm _comm;
36: int _commRank, _commSize;
37: protected:
38: void __setupComm(const MPI_Comm& comm) {
39: this->_comm = comm;
41: MPI_Comm_size(this->_comm, &this->_commSize); CHKERROR(ierr, "Error in MPI_Comm_size");
42: MPI_Comm_rank(this->_comm, &this->_commRank); CHKERROR(ierr, "Error in MPI_Comm_rank");
43: }
44: public:
45: XParallelObject(const MPI_Comm& comm, const int debug) : XObject(debug) {this->__setupComm(comm);};
46: XParallelObject(const MPI_Comm& comm = PETSC_COMM_WORLD) : XObject() {this->__setupComm(comm);};
47: XParallelObject(const XParallelObject& xpobject) : XObject(xpobject), _comm(xpobject._comm) {};
48: //
49: MPI_Comm comm() {return this->_comm;};
50: int commSize() {return this->_commSize;};
51: int commRank() {return this->_commRank;};
52: };// class XParallelObject
53:
54: namespace XSifterDef {
55: static int debug = 0;
56: static int codebug = 0;
57: #define ALE_XDEBUG_DEPTH 5
58: #define ALE_XDEBUG(n) ((ALE_XDEBUG_DEPTH - ALE::XSifterDef::debug < n) || (ALE::XSifterDef::codebug >= n))
59: #define ALE_XDEBUG_AUTO ((ALE_XDEBUG_DEPTH - ALE::XSifterDef::debug < __ALE_XDEBUG__) || (ALE::XSifterDef::codebug >= __ALE_XDEBUG__))
62: //
63: // Key orders
64: //
65: template<typename OuterKey_, typename InnerKey_, typename OuterKeyOrder_, typename InnerKeyOrder_>
66: struct OuterInnerKeyOrder {
67: typedef OuterKey_ outer_key_type;
68: typedef InnerKey_ inner_key_type;
69: typedef ALE::pair<outer_key_type, inner_key_type> key_pair_type;
70: //
71: typedef OuterKeyOrder_ outer_key_order_type;
72: typedef InnerKeyOrder_ inner_key_order_type;
73: //
74: bool operator()(const outer_key_type ok1, const inner_key_type ik1, const outer_key_type& ok2, const inner_key_type& ik2) {
75: static outer_key_order_type okCompare;
76: static inner_key_order_type ikCompare;
77: return (okCompare(ok1,ok2) || (!okCompare(ok2,ok1) && ikCompare(ik1,ik2)));
78: };
79: };
81: //
82: // Rec orders
83: //
84: // RecKeyOrder compares records by comparing keys of type Key_ extracted from arrows using a KeyExtractor_.
85: // In addition, a record can be compared to a single Key_ or another CompatibleKey_.
86: template<typename Rec_, typename KeyExtractor_, typename KeyOrder_ = std::less<typename KeyExtractor_::result_type> >
87: struct RecKeyOrder {
88: typedef Rec_ rec_type;
89: typedef KeyExtractor_ key_extractor_type;
90: typedef typename key_extractor_type::result_type key_type;
91: typedef KeyOrder_ key_order_type;
92: protected:
93: key_order_type _key_order;
94: key_extractor_type _kex;
95: public:
96: bool operator()(const rec_type& rec1, const rec_type& rec2) const {
97: return this->_key_order(this->_kex(rec1), this->_kex(rec2));
98: };
99: template <typename CompatibleKey_>
100: bool operator()(const rec_type& rec, const ALE::singleton<CompatibleKey_> keySingleton) const {
101: // In order to disamiguate calls such as this from (rec&,rec&) calls, compatible keys are passed in wrapped as singletons,
102: // and must be unwrapped before the ordering operator is applied.
103: return this->_key_order(this->_kex(rec), keySingleton.first);
104: };
105: template <typename CompatibleKey_>
106: bool operator()(const ALE::singleton<CompatibleKey_> keySingleton, const rec_type& rec) const {
107: // In order to disamiguate calls such as this from (rec&,rec&) calls, compatible keys are passed in wrapped as singletons,
108: // and must be unwrapped before the ordering operator is applied
109: return this->_key_order(keySingleton.first, this->_kex(rec));
110: };
111: };// RecKeyOrder
113: //
114: // Composite Rec ordering operators (e.g., used to generate cone and support indices for Arrows).
115: // An RecKeyXXXOrder first orders on a single key using KeyOrder (e.g., Target or Source for cone and support respectively),
116: // and then on the whole Rec, using an additional predicate XXXOrder.
117: // These are then specialized (with Rec = Arrow) to SupportCompare & ConeCompare, using the order operators supplied by the user:
118: // SupportOrder = (SourceOrder, SupportXXXOrder),
119: // ConeOrder = (TargetOrder, ConeXXXOrder), etc
120: template <typename Rec_, typename KeyExtractor_, typename KeyOrder_, typename XXXOrder_>
121: struct RecKeyXXXOrder {
122: typedef Rec_ rec_type;
123: typedef KeyExtractor_ key_extractor_type;
124: typedef KeyOrder_ key_order_type;
125: typedef typename key_extractor_type::result_type key_type;
126: typedef XXXOrder_ xxx_order_type;
127: //
128: private:
129: key_order_type _compare_keys;
130: xxx_order_type _compare_xxx;
131: key_extractor_type _kex;
132: public:
133: bool operator()(const rec_type& rec1, const rec_type& rec2) const {
134: //
135: // return this->_compare_keys(this->_kex(rec1),this->_kex(rec2)) ||
136: // (!this->_compare_keys(this->_kex(rec2),this->_kex(rec1)) && this->_compare_xxx(rec1,rec2));
137: if(this->_compare_keys(this->_kex(rec1), this->_kex(rec2)))
138: return true;
139: if(this->_compare_keys(this->_kex(rec2), this->_kex(rec1)))
140: return false;
141: if(this->_compare_xxx(rec1,rec2))
142: return true;
143: return false;
144: };
145: template <typename CompatibleKey_>
146: bool operator()(const ALE::singleton<CompatibleKey_>& keySingleton, const rec_type& rec1) const {
147: // In order to disamiguate calls such as this from (rec&,rec&) calls, compatible keys are passed in wrapped as singletons,
148: // and must be unwrapped before the ordering operator is applied
149: return this->_compare_keys(keySingleton.first, this->_kex(rec1));
150: };
151: template <typename CompatibleKey_>
152: bool operator()(const rec_type& rec1, const ALE::singleton<CompatibleKey_>& keySingleton) const {
153: // In order to disamiguate calls such as this from (rec&,rec&) calls, compatible keys are passed in wrapped as singletons,
154: // and must be unwrapped before the ordering operator is applied
155: return this->_compare_keys(this->_kex(rec1), keySingleton.first);
156: };
157: template <typename CompatibleKey_, typename CompatibleXXXKey_>
158: bool operator()(const ALE::pair<CompatibleKey_, CompatibleXXXKey_>& keyPair, const rec_type& rec) const {
159: // In order to disamiguate calls such as this from (rec&,rec&) calls, compatible keys are passed in wrapped as singletons,
160: // and must be unwrapped before the ordering operator is applied
161: //
162: // We want (key,xxxkey) to be no greater than any (key, xxxkey, ...)
163: return this->_compare_keys(keyPair.first, _kex(rec)) ||
164: (!this->_compare_keys(_kex(rec), keyPair.first) && this->_compare_xxx(ALE::singleton<CompatibleXXXKey_>(keyPair.second), rec));
165: // Note that CompatibleXXXKey_ -- the second key in the pair -- must be wrapped up as a singleton before being passed for comparison against rec
166: // to compare_xxx. This is necessary for compare_xxx to disamiguate comparison of recs to elements of differents types. In particular,
167: // this is necessary if compare_xxx is of the RecKeyXXXOrder type. Specialization doesn't work, or I don't know how to make it work in this context.
168: };
169: template <typename CompatibleKey_, typename CompatibleXXXKey_>
170: bool operator()(const rec_type& rec, const ALE::pair<CompatibleKey_, CompatibleXXXKey_>& keyPair) const {
171: // We want (key,xxxkey) to be no greater than any (key, xxxkey, ...)
172: return _compare_keys(_kex(rec), keyPair.first) ||
173: (!this->_compare_keys(keyPair.first, _kex(rec)) && this->_compare_xxx(rec,ALE::singleton<CompatibleXXXKey_>(keyPair.second)));
174: // Note that CompatibleXXXKey_ -- the second key in the pair -- must be wrapped up as a singleton before being passed for comparison against rec
175: // to compare_xxx. This is necessary for compare_xxx to disamiguate comparison of recs to elements of differents types. In particular,
176: // this is necessary if compare_xxx is of the RecKeyXXXOrder type. Specialization doesn't work, or I don't know how to make it work in this context.
177: };
178: };// class RecKeyXXXOrder
181: //
182: // PredicateTraits encapsulates Predicate types encoding object subsets with a given Predicate value or within a value range.
183: template<typename Predicate_>
184: struct PredicateTraits {};
185: // Traits of different predicate types are defined via specialization of PredicateTraits.
186: // We require that the predicate type act like an int (signed or unsigned).
187: //
188: template<>
189: struct PredicateTraits<int> {
190: typedef int predicate_type;
191: typedef int printable_type;
192: static const predicate_type default_value;
193: static const predicate_type zero;
194: static printable_type printable(const predicate_type& p) {return (printable_type)p;};
195: };
196: const PredicateTraits<int>::predicate_type PredicateTraits<int>::default_value = 0;
197: const PredicateTraits<int>::predicate_type PredicateTraits<int>::zero = 0;
198: //
199: template<>
200: struct PredicateTraits<unsigned int> {
201: typedef unsigned int predicate_type;
202: typedef unsigned int printable_type;
203: static const predicate_type default_value;
204: static const predicate_type zero;
205: static printable_type printable(const predicate_type& p) {return (printable_type)p;};
206: };
207: const PredicateTraits<unsigned int>::predicate_type PredicateTraits<unsigned int>::default_value = 0;
208: const PredicateTraits<unsigned int>::predicate_type PredicateTraits<unsigned int>::zero = 0;
209: //
210: template<>
211: struct PredicateTraits<short> {
212: typedef short predicate_type;
213: typedef short printable_type;
214: static const predicate_type default_value;
215: static const predicate_type zero;
216: static printable_type printable(const predicate_type& p) {return (printable_type)p;};
217: };
218: const PredicateTraits<short>::predicate_type PredicateTraits<short>::default_value = 0;
219: const PredicateTraits<short>::predicate_type PredicateTraits<short>::zero = 0;
221: //
222: template<>
223: struct PredicateTraits<char> {
224: typedef char predicate_type;
225: typedef short printable_type;
226: static const predicate_type default_value;
227: static const predicate_type zero;
228: static printable_type printable(const predicate_type& p) {return (printable_type)p;};
229: };
230: const PredicateTraits<char>::predicate_type PredicateTraits<char>::default_value = '\0';
231: const PredicateTraits<char>::predicate_type PredicateTraits<char>::zero = '\0';
234: //
235: // RangeFilter defines a subset of a Sequence_ based on the high and low value of a key.
236: // The type and ordering of the key are defined by KeyExtractor_ and KeyCompare_ respectively.
237: //
238: #undef __CLASS__
240: template <typename Index_, typename KeyExtractor_, typename KeyCompare_, bool Strided = false>
241: class RangeFilter : XObject {
242: public:
243: typedef Index_ index_type;
244: typedef KeyExtractor_ key_extractor_type;
245: typedef KeyCompare_ key_compare_type;
246: typedef typename key_extractor_type::result_type key_type;
247: typedef PredicateTraits<key_type> key_traits;
248: typedef typename index_type::iterator iterator;
249: //
250: typedef iterator cookie_type;
251: protected:
252: index_type* _index; // a pointer rather than a reference is used for use in default constructor
253: bool _have_low, _have_high;
254: key_type _low, _high;
255: public:
256: // Basic interface
257: RangeFilter(index_type* order) :
258: XObject(), _index(order), _have_low(false), _have_high(false) {};
259: RangeFilter(index_type* order, const key_type& low, const key_type& high) :
260: XObject(), _index(order), _have_low(true), _have_high(true), _low(low), _high(high) {};
261: RangeFilter(const RangeFilter& f) :
262: XObject(f), _index(f._index), _have_low(f._have_low), _have_high(f._have_high), _low(f._low), _high(f._high) {};
263: ~RangeFilter(){};
264: //
265: void setLow(const key_type& low) {this->_low = low; this->_have_low = true;};
266: void setHigh(const key_type& high) {this->_high = high; this->_have_high = true;};
267: void setLowAndHigh(const key_type& low, const key_type& high) {this->setLow(low); this->setHigh(high);};
268: //
269: key_type low() const {return this->_low;};
270: key_type high() const {return this->_high;};
271: bool haveLow() const {return this->_have_low;};
272: bool haveHigh() const {return this->_have_high;};
273: //
274: static iterator& end(cookie_type& cookie) {return cookie;};
275: static key_type key(const iterator& iter) { static key_extractor_type kex; return kex(*iter);};
276: //
277: #undef __FUNCT__
279: #undef __ALE_XDEBUG__
281: // Returns the first allowed segment.
282: void firstSegment(iterator& segmentBegin, cookie_type& segmentCookie) const {
283: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
284: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
285: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
286: std::cout << "filter: " << *this << std::endl;
287: }
288: iterator& segmentEnd = this->end(segmentCookie);
289: if(this->_have_low) {
290: segmentBegin = this->_index->lower_bound(ALE::singleton<key_type>(this->_low));
291: }
292: else {
293: segmentBegin = this->_index->begin();
294: }
295: if(Strided) {
296: if(this->_have_high) {
297: segmentEnd = this->_index->upper_bound(ALE::singleton<key_type>(this->_high));
298: }
299: else {
300: segmentEnd = this->_index->end();
301: }
302: }
303: else {
304: segmentEnd = this->_index->upper_bound(ALE::singleton<key_type>(this->key(segmentBegin)));
305: }
306: //
307: if(ALE_XDEBUG(__ALE_XDEBUG__)){
308: //
309: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*segmentBegin: " << *segmentBegin;
310: std::cout << ", *segmentEnd: " << *segmentEnd << std::endl;
311: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
312: }
313: };//firstSegment()
314: //
315: #undef __FUNCT__
317: #undef __ALE_XDEBUG__
319: // Returns the first allowed subsegment within the segment containing current_iter.
320: template<typename OuterFilter_>
321: void firstSegment(const OuterFilter_& outer_filter, iterator& current_iter, typename OuterFilter_::cookie_type& outerCookie, iterator& segmentBegin, cookie_type& segmentCookie) const {
322: typedef typename OuterFilter_::key_type outer_key_type;
323: static key_compare_type keyCompare;
324: iterator& outerEnd = outer_filter.end(outerCookie);
325: iterator& segmentEnd = this->end(segmentCookie);
326: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
327: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
328: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
329: std::cout << "filter: " << *this << ", outer_filter: " << outer_filter << std::endl;
330: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
331: std::cout << "*current_iter: " << *current_iter << ", *outerEnd: " << *outerEnd << std::endl;
332: }
333: if(this->_have_low) {
334: segmentBegin = this->_index->lower_bound(ALE::pair<outer_key_type, key_type>(outer_filter.key(current_iter), this->_low));
335: }
336: else {
337: segmentBegin = current_iter;
338: }
339: if(Strided) { // if filter is strided
340: // if the segment is empty, both begin and end must be at outer end
341: // otherwise, only the inner end is at outer end
342: segmentEnd = outer_filter.end(outerCookie);
343: // detect an overshoot of high by segment begin: indicating an empty inner segment
344: if(segmentBegin != outerEnd && this->_have_high && keyCompare(this->_high,this->key(segmentBegin))) {// inner begin overshoots inner high
345: // Move segmentBegin to segmentEnd to indicate an empty inner segment
346: segmentBegin = segmentEnd;
347: }
348: }// filter is strided
349: else { // if filter is not strided
350: // if inner begin is not at the outer end and not above high (if there is any)
351: if(segmentBegin != outerEnd && (!this->_have_high || !keyCompare(this->_high, this->key(segmentBegin)))) {
352: // the inner segment end is 'one up' from the inner begin
353: segmentEnd = this->_index->upper_bound(ALE::pair<outer_key_type, key_type>(outer_filter.key(current_iter), this->key(segmentBegin)));
354: }
355: else {
356: // otherwise the inner segment end is equal to inner begin
357: segmentEnd = segmentBegin;
358: }
359: }
360: //
361: if(ALE_XDEBUG(__ALE_XDEBUG__)){
362: //
363: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*segmentBegin: " << *segmentBegin;
364: std::cout << ", *segmentEnd: " << *segmentEnd << std::endl;
365: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
366: }
367: };//firstSegment<OuterFilter_>()
368: //
369: #undef __FUNCT__
371: #undef __ALE_XDEBUG__
373: // Returns the allowed segment immediately following current_iter.
374: void nextSegment(iterator& current_iter, iterator& segmentBegin, cookie_type& segmentCookie) const {
375: static key_compare_type keyCompare;
376: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
377: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
378: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
379: std::cout << "filter: " << *this << std::endl;
380: }
381: iterator& segmentEnd = this->end(segmentCookie);
382: // Go to the segmentEnd --- iterator with the following key;
383: segmentBegin = segmentEnd;
384: // Check for an overshoot
385: if(this->_have_high && keyCompare(this->_high, this->key(segmentBegin))) {// overshoot
386: // Go to the end of index
387: segmentBegin = this->_index->end();
388: segmentEnd = this->_index->end();
389: }
390: else { // no overshoot
391: segmentEnd= this->_index->upper_bound(ALE::singleton<key_type>(this->key(segmentBegin)));
392: }
393: if(ALE_XDEBUG(__ALE_XDEBUG__)){
394: //
395: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*segmentBegin: " << *segmentBegin;
396: std::cout << ", *segmentEnd: " << *segmentEnd << std::endl;
397: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
398: }
399: };//nextSegment
400: //
401: #undef __FUNCT__
403: #undef __ALE_XDEBUG__
405: // Returns the allowed subsegment immediately following current_iter within the same segment.
406: template <typename OuterFilter_>
407: void nextSegment(const OuterFilter_& outer_filter, iterator& current_iter, typename OuterFilter_::cookie_type& outerCookie, iterator& segmentBegin, cookie_type& segmentCookie) const {
408: typedef typename OuterFilter_::key_type outer_key_type;
409: typedef typename OuterFilter_::key_compare_type outer_key_compare_type;
410: static OuterInnerKeyOrder<outer_key_type, key_type, outer_key_compare_type, key_compare_type> oiKeyCompare;
411: iterator& outerEnd = outer_filter.end(outerCookie);
412: iterator& segmentEnd = this->end(segmentCookie);
413: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
414: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
415: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
416: std::cout << "filter: " << *this << ", outer filter: " << outer_filter << std::endl;
417: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
418: std::cout << "*current_iter: " << *current_iter << ", *outerEnd:" << *outerEnd << std::endl;
419: }
420: // Check if current_iter is at the outer end
421: if(current_iter == outerEnd) {
422: segmentBegin = outerEnd;
423: segmentEnd = outerEnd;
424: }
425: else {// if current_iter is not at outer end
426: // Go to segmentEnd -- iterator with the following key or the segment end, if strided
427: segmentBegin = segmentEnd;
428: // Check for overshoots
429: if(segmentBegin == outerEnd) { // outerEnd reached
430: segmentEnd = outerEnd;
431: }
432: else if((this->_have_high && oiKeyCompare(outer_filter.key(current_iter), this->_high, outer_filter.key(segmentBegin), this->key(segmentBegin))))
433: {// inner high overshoot
434: segmentBegin = outerEnd; segmentEnd = outerEnd;
435: }
436: else {// no overshoot
437: segmentEnd = this->_index->upper_bound(ALE::pair<outer_key_type, key_type>(outer_filter.key(segmentBegin), this->key(segmentBegin)));
438: }
439: }// if current_iter is not at outer end
440: if(ALE_XDEBUG(__ALE_XDEBUG__)){
441: //
442: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*segmentBegin " << *segmentBegin;
443: std::cout << ", *segmentEnd: " << *segmentEnd << std::endl;
444: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
445: }
446: };//nextSegment<OuterFilter_>
447: //
448: friend std::ostream& operator<<(std::ostream& os, const RangeFilter& f) {
449: os << "[low, high] = [";
450: if(f.haveLow()){
451: os << ((typename key_traits::printable_type)(f.low())) << ",";
452: }
453: else {
454: os << "none, ";
455: }
456: if(f.haveHigh()) {
457: os << ((typename key_traits::printable_type)(f.high()));
458: }
459: else {
460: os << "none";
461: }
462: os << "] ";
463: if(Strided) {
464: os << "strided";
465: }
466: else {
467: os << "non-strided";
468: }
469: return os;
470: };
471: friend std::ostream& operator<<(std::ostream& os, const Obj<RangeFilter>& f) {
472: return (os << f.object());
473: };
474: };// RangeFilter
477: //
478: // FilteredIndexSequence definition
479: //
480: // Defines a sequence representing a subset of a multi_index container defined by its Index_ which is ordered lexicographically.
481: // The ordering is controlled by a pair of filters (OuterFilter_ and InnerFilter_ types).
482: // The elements of the sequence are a subset of an Index_ ordered lexicographically by (OuterKey_,InnerKey_) pairs and such that
483: // each key lies in the range of OuterFilter_/InnerFilter_ respectively.
484: // A sequence defines output iterators (input iterators in std terminology) for traversing a subset of an Index_ object.
485: // Upon dereferencing values are extracted from each result record using a ValueExtractor_ object.
486: // More precisely, the index can be viewed as oredered by (OuterKey_,InnerKey_,RemainderKey_) triples, where the RemainderKey_
487: // type is not explicitly known to FilteredIndexSequence. The Filters only restrict the allowable values of the first two keys,
488: // while all RemainderKey_ values are allowed. By default a FilteredIndexSequence will traverse ALL entries with a given leading
489: // (OuterKey_,InnerKey_) pair. However, setting the template parameter 'Strided = true' will cause only the first elements of
490: // each segment with the same (OuterKey_,InnerKey_) pair to be traversed. In other words, each (OuterKey_,InnerKey_) pair will
491: // be seen once only.
492: // Ideally, 'Strided' should parameterize different implementations, but right now there is an 'if' test. An opporunity for improvement.
493: //
494: #undef __CLASS__
496: template <typename Index_, typename OuterFilter_, typename InnerFilter_,
497: typename ValueExtractor_ = ::boost::multi_index::identity<typename Index_::value_type>, bool Strided = false >
498: struct FilteredIndexSequence : XObject {
499: typedef Index_ index_type;
500: typedef typename index_type::value_type rec_type;
501: typedef InnerFilter_ inner_filter_type;
502: typedef OuterFilter_ outer_filter_type;
503: //
504: typedef typename outer_filter_type::key_extractor_type outer_key_extractor_type;
505: typedef typename outer_key_extractor_type::result_type outer_key_type;
506: typedef typename inner_filter_type::key_extractor_type inner_key_extractor_type;
507: typedef typename inner_key_extractor_type::result_type inner_key_type;
508: //
509: typedef typename inner_filter_type::cookie_type inner_cookie_type;
510: typedef typename outer_filter_type::cookie_type outer_cookie_type;
511: //
512: typedef ValueExtractor_ value_extractor_type;
513: typedef typename value_extractor_type::result_type value_type;
514: typedef typename index_type::size_type size_type;
515: //
516: typedef typename index_type::iterator itor_type;
517: typedef typename index_type::reverse_iterator ritor_type;
518: //
519: class iterator {
520: public:
521: // Parent sequence type
522: typedef FilteredIndexSequence sequence_type;
523: // Standard iterator typedefs
524: typedef std::input_iterator_tag iterator_category;
525: typedef int difference_type;
526: typedef value_type* pointer;
527: typedef value_type& reference;
528: /* value_type defined in the containing FilteredIndexSequence */
529: protected:
530: // Parent sequence
531: sequence_type *_sequence;
532: // Underlying iterator & segment filter cookies
533: itor_type _itor;
534: outer_cookie_type _outerCookie;
535: inner_cookie_type _innerCookie;
536: //
537: // Key and Value extractors
538: outer_key_extractor_type _okex;
539: inner_key_extractor_type _ikex;
540: value_extractor_type _ex;
541: public:
542: iterator() : _sequence(NULL) {};
543: iterator(sequence_type *sequence, const itor_type& itor, const outer_cookie_type& outerCookie, const inner_cookie_type& innerCookie) :
544: _sequence(sequence), _itor(itor), _outerCookie(outerCookie), _innerCookie(innerCookie) {};
545: iterator(const iterator& iter):_sequence(iter._sequence), _itor(iter._itor), _outerCookie(iter._outerCookie), _innerCookie(iter._innerCookie) {};
546: virtual ~iterator() {};
547: virtual bool operator==(const iterator& iter) const {return this->_itor == iter._itor;};
548: virtual bool operator!=(const iterator& iter) const {return this->_itor != iter._itor;};
549: //
550: virtual rec_type& rec() {return *(this->_itor);};
551: // FIX: operator*() should return a const reference, but it won't compile that way, because _ex() returns const value_type
552: virtual const value_type operator*() const {return _ex(*(this->_itor));};
553: //
554: virtual iterator operator++() {
555: this->_sequence->next(this->_itor, this->_outerCookie, this->_innerCookie);
556: return *this;
557: };
558: virtual iterator operator++(int n) {iterator tmp(*this); ++(*this); return tmp;};
559: };// class iterator
560: protected:
561: //
562: index_type *_index;
563: //
564: outer_filter_type _outer_filter;
565: inner_filter_type _inner_filter;
566: //
567: outer_key_extractor_type _okex;
568: inner_key_extractor_type _ikex;
569: public:
570: //
571: // Basic interface
572: //
573: FilteredIndexSequence() : XObject(), _index(NULL), _outer_filter(NULL), _inner_filter(NULL) {};
574: FilteredIndexSequence(index_type *index, const outer_filter_type& outer_filter, const inner_filter_type& inner_filter) :
575: XObject(), _index(index), _outer_filter(outer_filter), _inner_filter(inner_filter){};
576: FilteredIndexSequence(const FilteredIndexSequence& seq) :
577: XObject(seq), _index(seq._index), _outer_filter(seq._outer_filter), _inner_filter(seq._inner_filter) {};
578: virtual ~FilteredIndexSequence() {};
579: //
580: void copy(const FilteredIndexSequence& seq, FilteredIndexSequence cseq) {
581: cseq._index = seq._index;
582: cseq._inner_filter = seq._inner_filter;
583: cseq._outer_filter = seq._outer_filter;
584: };
585: FilteredIndexSequence& operator=(const FilteredIndexSequence& seq) {
586: copy(seq,*this); return *this;
587: };
588: void reset(index_type *index, const outer_filter_type& outer_filter, const inner_filter_type& inner_filter) {
589: this->_index = index;
590: this->_inner_filter = inner_filter;
591: this->_outer_filter = outer_filter;
592: };
593: //
594: // Extended interface
595: //
596: virtual bool
597: empty() {return (this->begin() == this->end());};
598: //
599: virtual size_type
600: size() {
601: size_type sz = 0;
602: for(iterator it = this->begin(); it != this->end(); it++) {
603: ++sz;
604: }
605: return sz;
606: };
607: //
608: inner_filter_type& innerFilter(){return this->_inner_filter;};
609: outer_filter_type& outerFilter(){return this->_outer_filter;};
610: void setInnerFilter(const inner_filter_type& inner_filter) {this->_inner_filter = inner_filter;};
611: void setOuterFilter(const outer_filter_type& outer_filter) {this->_outer_filter = outer_filter;};
612: //
613: #undef __FUNCT__
615: #undef __ALE_XDEBUG__
617: iterator begin() {
618: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
619: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
620: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
621: std::cout << "outer filter: " << this->outerFilter() << ", ";
622: std::cout << "inner filter: " << this->innerFilter() << std::endl;
623: }
624: static itor_type itor;
625: inner_cookie_type innerCookie;
626: outer_cookie_type outerCookie;
627: itor_type& innerEnd = this->innerFilter().end(innerCookie);
628: itor_type& outerEnd = this->outerFilter().end(outerCookie);
629: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
630: std::cout << __CLASS__ << "::" << __FUNCT__ << ": looking for the beginning segment pair" << std::endl;
631: }
632: this->outerFilter().firstSegment(itor, outerCookie);
633: this->innerFilter().firstSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie);
634: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
635: std::cout << __CLASS__ << "::" << __FUNCT__ << ": found an outer segment and an inner segment " << std::endl;
636: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
637: std::cout << "*itor : " << *itor << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd << std::endl;
638: }
639: while(!(itor != innerEnd || itor == this->_index->end())) {
640: while(!(itor != outerEnd || itor == this->_index->end())) { // find the next non-empty outer segment
641: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
642: std::cout << __CLASS__ << "::" << __FUNCT__ << ": looking for a non-empty outer segment; starting with:" << std::endl;
643: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
644: std::cout << "*itor : " << *itor << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd << std::endl;
645: }
646: this->outerFilter().nextSegment(itor, itor, outerCookie);
647: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
648: std::cout << __CLASS__ << "::" << __FUNCT__ << ": found an outer segment:" << std::endl;
649: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
650: std::cout << "*itor : " << *itor << ", *outerEnd: " << *outerEnd << std::endl;
651: }
652: if(itor != outerEnd || itor == this->_index->end()) {
653: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
654: std::cout << __CLASS__ << "::" << __FUNCT__ << ": have a non-empty outer segment; looking for the first inner segment; starting with:";
655: std::cout << std::endl;
656: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
657: std::cout << "*itor : " << *itor << ", *innerEnd: " << *innerEnd << ", *outerEnd: " << *outerEnd << std::endl;
658: }
659: this->innerFilter().firstSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie);
660: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
661: std::cout << __CLASS__ << "::" << __FUNCT__ << ": found an inner segment:" << std::endl;
662: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
663: std::cout << "*itor : " << *itor << ", *innerEnd: " << *innerEnd << *innerEnd << ", *outerEnd: " << *outerEnd << std::endl;
664: }
665: }// non-empty outer segment: looking for the first inner
666: }
667: if(itor == innerEnd){
668: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
669: std::cout << __CLASS__ << "::" << __FUNCT__ << ": looking for the next non-empty inner segment" << std::endl;
670: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
671: std::cout << "*itor : " << *itor << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd << std::endl;
672: }
673: this->innerFilter().nextSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie);
674: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
675: std::cout << __CLASS__ << "::" << __FUNCT__ << ": found an inner segment" << std::endl;
676: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
677: std::cout << "*itor : " << *itor << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd << std::endl;
678: }
679: }
680: }
681: if(ALE_XDEBUG(__ALE_XDEBUG__)){
682: //
683: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*itor: " << *itor;
684: std::cout << ", (okey, ikey): (" << this->outerFilter().key(itor) << ", " << this->innerFilter().key(itor) << ") ";
685: std::cout << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd;
686: std::cout << std::endl;
687: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
688: }
689: return iterator(this, itor, outerCookie, innerCookie);
690: }; // begin()
691: //
692: #undef __FUNCT__
694: #undef __ALE_XSIFTER_DEBUG__
696: void next(itor_type& itor, outer_cookie_type& outerCookie, inner_cookie_type& innerCookie) {
697: itor_type& innerEnd = this->innerFilter().end(innerCookie);
698: itor_type& outerEnd = this->outerFilter().end(outerCookie);
699: if(ALE_XDEBUG(__ALE_XSIFTER_DEBUG__)) {
700: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>> " << std::endl;
701: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
702: std::cout << "outer filter: " << this->outerFilter() << ", ";
703: std::cout << "inner filter: " << this->innerFilter() << std::endl;
704: if(Strided) {
705: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "strided sequence" << std::endl;
706: }
707: else {
708: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "non-strided sequence" << std::endl;
709: }
710: //
711: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "starting with *itor " << *itor;
712: std::cout << ", (okey, ikey): (" << this->outerFilter().key(itor) << ", " << this->innerFilter().key(itor) << ") ";
713: std::cout << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd;
714: std::cout << std::endl;
715: }
716: // We assume that it is safe to advance the iterator first and then check whether one of the segment ends has been reached.
717: // If iteration is to be strided we skip the remainder of the current subsegment and go over to the following subsegment within the same segment:
718: // effectively, we iterate over subsegments.
719: if(Strided) {
720: if(ALE_XDEBUG(__ALE_XSIFTER_DEBUG__)) {
721: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "strided sequence" << std::endl;
722: }
723: this->innerFilter().nextSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie);
724: }// Strided
725: // Otherwise, we iterate *within* a segment until its end is reached; then the following segment is started.
726: else {
727: if(ALE_XDEBUG(__ALE_XSIFTER_DEBUG__)) {
728: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "non-strided sequence" << std::endl;
729: }
730: ++itor;
731: }// not Strided
732: while(!(itor != innerEnd || itor == this->_index->end())) {
733: while(!(itor != outerEnd || itor == this->_index->end())) { // find the next non-empty outer segment
734: this->outerFilter().nextSegment(itor, itor, outerCookie);
735: if(itor != outerEnd || itor == this->_index->end()){
736: this->innerFilter().firstSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie); // find first inner segment within new outer segment
737: }
738: }// outerDone
739: if(!(itor != innerEnd || itor == this->_index->end())) { // if inner segment empty
740: // go to the next inner segment
741: this->innerFilter().nextSegment(this->outerFilter(), itor, outerCookie, itor, innerCookie);
742: }
743: }// innerDone
744: if(ALE_XDEBUG(__ALE_XSIFTER_DEBUG__)) {
745: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "new *itor " << *itor;
746: std::cout << ", (okey, ikey): (" << this->outerFilter().key(itor) << ", " << this->innerFilter().key(itor) << ") ";
747: std::cout << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd;
748: std::cout << std::endl;
749: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<< " << std::endl;
750: }
751: };// next()
752: //
753: #undef __FUNCT__
755: #undef __ALE_XDEBUG__
757: iterator end() {
758: if(ALE_XDEBUG(__ALE_XDEBUG__)) {
759: std::cout << __CLASS__ << "::" << __FUNCT__ << ":>>>" << std::endl;
760: std::cout << __CLASS__ << "::" << __FUNCT__ << ": ";
761: std::cout << "outer filter: " << this->outerFilter() << ", ";
762: std::cout << "inner filter: " << this->innerFilter() << std::endl;
763: if(Strided) {
764: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "strided sequence" << std::endl;
765: }
766: else {
767: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "non-strided sequence" << std::endl;
768: }
769: }
770: inner_cookie_type innerCookie;
771: outer_cookie_type outerCookie;
772: static itor_type itor;
773: itor_type& outerEnd = this->outerFilter().end(outerCookie);
774: itor_type& innerEnd = this->innerFilter().end(innerCookie);
775: itor = this->_index->end();
776: outerEnd = itor;
777: innerEnd = itor;
778: if(ALE_XDEBUG(__ALE_XDEBUG__)){
779: //
780: std::cout << __CLASS__ << "::" << __FUNCT__ << ": " << "*itor: " << *itor;
781: std::cout << ", (okey, ikey): (" << this->outerFilter().key(itor) << ", " << this->innerFilter().key(itor) << ") ";
782: std::cout << ", *outerEnd: " << *outerEnd << ", *innerEnd: " << *innerEnd;
783: std::cout << std::endl;
784: std::cout << __CLASS__ << "::" << __FUNCT__ << ":<<<" << std::endl;
785: }
786: return iterator(this, itor, outerCookie, innerCookie);
787: };// end()
788: //
789: template<typename ostream_type>
790: void view(ostream_type& os, const char* label = NULL){
791: if(label != NULL) {
792: os << "Viewing " << label << " sequence:" << std::endl;
793: }
794: os << "[";
795: for(iterator i = this->begin(); i != this->end(); i++) {
796: os << " "<< *i;
797: }
798: os << " ]" << std::endl;
799: };
800: };// class FilteredIndexSequence
801:
803: // Definitions of typical XSifter usage of records, orderings, etc.
805: //
806: // Default orders.
807: //
808: template<typename Arrow_,
809: typename SourceOrder_ = std::less<typename Arrow_::source_type>,
810: typename ColorOrder_ = std::less<typename Arrow_::color_type> >
811: struct SourceColorOrder :
812: public RecKeyXXXOrder<Arrow_,
813: ::boost::multi_index::const_mem_fun<Arrow_,typename Arrow_::source_type, &Arrow_::source>,
814: SourceOrder_,
815: RecKeyOrder<Arrow_,
816: ::boost::multi_index::const_mem_fun<Arrow_, typename Arrow_::color_type, &Arrow_::color>,
817: ColorOrder_>
818: >
819: {};
820:
821: //
822: template<typename Arrow_,
823: typename ColorOrder_ = std::less<typename Arrow_::color_type>,
824: typename SourceOrder_ = std::less<typename Arrow_::source_type>
825: >
826: struct ColorSourceOrder :
827: public RecKeyXXXOrder<Arrow_,
828: ::boost::multi_index::const_mem_fun<Arrow_,typename Arrow_::color_type, &Arrow_::source>,
829: ColorOrder_,
830: RecKeyOrder<Arrow_,
831: ::boost::multi_index::const_mem_fun<Arrow_, typename Arrow_::source_type, &Arrow_::source>,
832: SourceOrder_>
833: >
834: {};
835: //
836: template<typename Arrow_,
837: typename TargetOrder_ = std::less<typename Arrow_::source_type>,
838: typename ColorOrder_ = std::less<typename Arrow_::color_type> >
839: struct TargetColorOrder :
840: public RecKeyXXXOrder<Arrow_,
841: ::boost::multi_index::const_mem_fun<Arrow_,typename Arrow_::source_type, &Arrow_::source>,
842: TargetOrder_,
843: RecKeyOrder<Arrow_,
844: ::boost::multi_index::const_mem_fun<Arrow_, typename Arrow_::color_type, &Arrow_::color>,
845: ColorOrder_>
846: >
847: {};
848: //
849: template<typename Arrow_,
850: typename ColorOrder_ = std::less<typename Arrow_::color_type>,
851: typename TargetOrder_ = std::less<typename Arrow_::source_type> >
852: struct ColorTargetOrder :
853: public RecKeyXXXOrder<Arrow_,
854: ::boost::multi_index::const_mem_fun<Arrow_,typename Arrow_::color_type, &Arrow_::source>,
855: ColorOrder_,
856: RecKeyOrder<Arrow_,
857: ::boost::multi_index::const_mem_fun<Arrow_, typename Arrow_::source_type, &Arrow_::source>,
858: TargetOrder_>
859: >
860: {};
861:
862: //
863: // Arrow definition: a concrete arrow; other Arrow definitions are possible, since orders above are templated on it; must have expected const_mem_funs
864: //
865: template<typename Source_, typename Target_, typename Color_>
866: struct Arrow {
867: typedef Arrow arrow_type;
868: typedef Source_ source_type;
869: typedef Target_ target_type;
870: typedef Color_ color_type;
871: source_type _source;
872: target_type _target;
873: color_type _color;
874: //
875: source_type source() const {return this->_source;};
876: target_type target() const {return this->_target;};
877: color_type color() const {return this->_color;};
878: // Basic
879: Arrow(const source_type& s, const target_type& t, const color_type& c) : _source(s), _target(t), _color(c) {};
880: // Rebinding
881: template <typename OtherSource_, typename OtherTarget_, typename OtherColor_>
882: struct rebind {
883: typedef Arrow<OtherSource_, OtherTarget_, OtherColor_> type;
884: };
885: // Flipping
886: struct flip {
887: typedef Arrow<target_type, source_type, color_type> type;
888: type arrow(const arrow_type& a) { return type(a.target, a.source, a.color);};
889: };
890: // Printing
891: friend std::ostream& operator<<(std::ostream& os, const Arrow& a) {
892: os << a._source << " --(" << a._color << ")--> " << a._target;
893: return os;
894: }
895: // Modifying
896: struct sourceChanger {
897: sourceChanger(const source_type& newSource) : _newSource(newSource) {};
898: void operator()(arrow_type& a) {a._source = this->_newSource;}
899: private:
900: source_type _newSource;
901: };
902: //
903: struct targetChanger {
904: targetChanger(const target_type& newTarget) : _newTarget(newTarget) {};
905: void operator()(arrow_type& a) { a._target = this->_newTarget;}
906: private:
907: const target_type _newTarget;
908: };
909: //
910: struct colorChanger {
911: colorChanger(const color_type& newColor) : _newColor(newColor) {};
912: void operator()(arrow_type& a) { a._color = this->_newColor;}
913: private:
914: const color_type _newColor;
915: };
916: };// struct Arrow
918: // Arrow + Predicate = ArrowRec (used in the multi-index container underlying the XSifter)
919: template <typename Arrow_, typename Predicate_>
920: struct ArrowRec : public Arrow_ {
921: public:
922: //
923: // Re-export typedefs
924: //
925: typedef Arrow_ arrow_type;
926: typedef typename arrow_type::source_type source_type;
927: typedef typename arrow_type::target_type target_type;
928: //
929: typedef Predicate_ predicate_type;
930: typedef PredicateTraits<predicate_type> predicate_traits;
931: protected:
932: // Predicate stored alongside the arrow data
933: predicate_type _predicate;
934: // Slice pointer
935: // HACK: ArrowRec should really reside at a lower level
936: void * _slice_ptr;
937: predicate_type _slice_marker;
938: public:
939: // Basic interface
940: ArrowRec(const arrow_type& a) : arrow_type(a), _predicate(predicate_traits::zero), _slice_ptr(NULL), _slice_marker(predicate_traits::zero) {};
941: ArrowRec(const arrow_type& a, const predicate_type& p) : arrow_type(a), _predicate(p), _slice_ptr(NULL), _slice_marker(predicate_traits::zero){};
942: // Extended interface
943: predicate_type predicate() const{return this->_predicate;};
944: source_type source() const {return this->arrow_type::source();};
945: target_type target() const {return this->arrow_type::target();};
946: //
947: // HACK: this should be implemented at the lower level of a multi_index container
948: const predicate_type slice_marker() const {return this->_slice_marker;};
949: const void* slice_ptr() const {return this->_slice_ptr;};
950: // Printing
951: friend std::ostream& operator<<(std::ostream& os, const ArrowRec& r) {
952: os << "<" << predicate_traits::printable(r._predicate) << ">" << "[" << (arrow_type)r << "]";
953: return os;
954: }
955: // Modifier objects
956: struct PredicateChanger {
957: PredicateChanger(const predicate_type& newPredicate) : _newPredicate(newPredicate) {};
958: void operator()(ArrowRec& r) { r._predicate = this->_newPredicate;}
959: private:
960: const predicate_type _newPredicate;
961: };
962: //
963: struct SliceChanger {
964: SliceChanger(const predicate_type& new_slice_marker, const void *& new_slice_ptr) : _new_slice_marker(new_slice_marker), _new_slice_ptr(new_slice_ptr) {};
965: void setSlice(const predicate_type& new_slice_marker, const void *& new_slice_ptr){
966: this->_new_slice_marker = new_slice_marker;
967: this->_new_slice_pointer = new_slice_ptr;
968: }
969: void operator()(ArrowRec& r) {r._slice_marker = this->_new_slice_marker; r._slice_ptr = this->_new_slice_ptr;};
970: private:
971: void *_new_slice_ptr;
972: predicate_type _new_slice_marker;
973: };// struct SliceChanger
974: };// struct ArrowRec
976: //
977: // Arrow Sequence type
978: //
979: template <typename XSifter_, typename Index_,
980: typename OuterFilter_, typename InnerFilter_, typename ValueExtractor_, bool Strided = false>
981: class ArrowSequence :
982: public XSifterDef::FilteredIndexSequence<Index_, OuterFilter_, InnerFilter_, ValueExtractor_, Strided> {
983: // ArrowSequence extends FilteredIndexSequence with extra iterator methods.
984: public:
985: typedef XSifter_ xsifter_type;
986: typedef XSifterDef::FilteredIndexSequence<Index_, OuterFilter_, InnerFilter_, ValueExtractor_, Strided> super;
987: typedef typename super::index_type index_type;
988: typedef typename super::outer_filter_type outer_filter_type;
989: typedef typename super::inner_filter_type inner_filter_type;
990: typedef typename super::outer_key_type outer_key_type;
991: typedef typename super::inner_key_type inner_key_type;
992: //
993: typedef typename xsifter_type::rec_type rec_type;
994: typedef typename xsifter_type::arrow_type arrow_type;
995: typedef typename arrow_type::source_type source_type;
996: typedef typename arrow_type::target_type target_type;
997: //
998: // Need to extend the inherited iterators to be able to extract arrow components in addition to what comes out of ValueExtractor_
999: class iterator : public super::iterator {
1000: public:
1001: iterator() : super::iterator() {};
1002: iterator(const typename super::iterator& super_iter) : super::iterator(super_iter) {};
1003: virtual const source_type& source() const {return this->_itor->source();};
1004: virtual const target_type& target() const {return this->_itor->target();};
1005: virtual const arrow_type& arrow() const {return *(this->_itor);};
1006: virtual const rec_type& rec() const {return *(this->_itor);};
1007: };
1008: protected:
1009: xsifter_type *_xsifter;
1010: public:
1011: //
1012: // Basic ArrowSequence interface
1013: //
1014: ArrowSequence() : super(), _xsifter(NULL) {};
1015: ArrowSequence(const ArrowSequence& seq) : super(seq), _xsifter(seq._xsifter) {};
1016: ArrowSequence(xsifter_type *xsifter, index_type *index, const outer_filter_type& outer_filter, const inner_filter_type& inner_filter) :
1017: super(index, outer_filter, inner_filter), _xsifter(xsifter) {};
1018: virtual ~ArrowSequence() {};
1019: void copy(const ArrowSequence& seq, ArrowSequence& cseq) {
1020: super::copy(seq,cseq);
1021: cseq._xsifter = seq._xsifter;
1022: };
1023: void reset(xsifter_type *xsifter, index_type *index, const outer_filter_type& outer_filter, const inner_filter_type& inner_filter) {
1024: this->super::reset(index, outer_filter, inner_filter);
1025: this->_xsifter = xsifter;
1026: };
1027: ArrowSequence& operator=(const ArrowSequence& seq) {
1028: copy(seq,*this); return *this;
1029: };
1030: //
1031: // Extended ArrowSequence interface
1032: //
1033: virtual iterator begin() {
1034: return this->super::begin();
1035: };
1036: //
1037: virtual iterator end() {
1038: return this->super::end();
1039: };
1040: //
1041: template<typename ostream_type>
1042: void view(ostream_type& os, const bool& useColor = false, const char* label = NULL){
1043: if(label != NULL) {
1044: os << "Viewing " << label << " sequence:" << std::endl;
1045: }
1046: os << "[";
1047: for(iterator i = this->begin(); i != this->end(); i++) {
1048: os << " (" << *i;
1049: if(useColor) {
1050: os << "," << i.color();
1051: }
1052: os << ")";
1053: }
1054: os << " ]" << std::endl;
1055: };
1056: void addArrow(const arrow_type& a) {
1057: this->_xsifter->addArrow(a);
1058: };
1059: //
1060: };// class ArrowSequence
1062: }; // namespace XSifterDef
1063:
1064: //
1065: // XSifter definition
1066: //
1067: template<typename Arrow_,
1068: typename ArrowConeOrder_ = XSifterDef::SourceColorOrder<Arrow_>,
1069: typename Predicate_ = unsigned int>
1070: struct XSifter : XObject { // struct XSifter
1071: //
1072: typedef XSifter xsifter_type;
1073: //
1074: // Encapsulated types: re-export types and/or bind parameterized types
1075: //
1076: //
1077: typedef Arrow_ arrow_type;
1078: typedef typename arrow_type::source_type source_type;
1079: typedef typename arrow_type::target_type target_type;
1080: //
1081: typedef Predicate_ predicate_type;
1082: typedef ALE::XSifterDef::PredicateTraits<predicate_type> predicate_traits;
1083: //
1084: typedef ALE::XSifterDef::ArrowRec<arrow_type, predicate_type> rec_type;
1085: //
1086: // Key extractors are defined here
1087: //
1088: typedef ::boost::multi_index::const_mem_fun<rec_type, source_type, &rec_type::source> source_extractor_type;
1089: typedef ::boost::multi_index::const_mem_fun<rec_type, target_type, &rec_type::target> target_extractor_type;
1090: typedef ::boost::multi_index::const_mem_fun<rec_type, predicate_type, &rec_type::predicate> predicate_extractor_type;
1091: //
1092: // Orders are defined here
1093: //
1094: typedef std::less<typename rec_type::target_type> target_order_type;
1095: typedef ArrowConeOrder_ arrow_cone_order_type;
1096: //
1097: // Rec 'Cone' order type: first order by target then using a custom arrow_cone order
1098: struct cone_order_type : public
1099: XSifterDef::RecKeyXXXOrder<rec_type,
1100: typename ::boost::multi_index::const_mem_fun<rec_type,target_type, &rec_type::target>,
1101: target_order_type,
1102: XSifterDef::RecKeyOrder<rec_type,
1103: ::boost::multi_index::identity<rec_type>, arrow_cone_order_type> >
1104: {};
1105:
1106: //
1107: // Index tags
1108: //
1109: struct ConeTag{};
1110:
1111: // Rec set type
1112: typedef ::boost::multi_index::multi_index_container<
1113: rec_type,
1114: ::boost::multi_index::indexed_by<
1115: ::boost::multi_index::ordered_non_unique<
1116: ::boost::multi_index::tag<ConeTag>, ::boost::multi_index::identity<rec_type>, cone_order_type
1117: >
1118: >,
1119: ALE_ALLOCATOR<rec_type> >
1120: rec_set_type;
1121: //
1122: // Index types
1123: //
1124: typedef typename ::boost::multi_index::index<rec_set_type, ConeTag>::type cone_index_type;
1126: //
1127: // Specialized RangeFilters
1128: //
1129: typedef ALE::XSifterDef::RangeFilter<cone_index_type, target_extractor_type, target_order_type> cone_target_filter_type;
1130: typedef ALE::XSifterDef::RangeFilter<cone_index_type, target_extractor_type, target_order_type, true> cone_target_strided_filter_type;
1132: //
1133: // Specialized sequence types
1134: //
1135: // FIXIT: need to allow a single filter in ArrowSequence; optimize for no filter?
1136: typedef ALE::XSifterDef::ArrowSequence<xsifter_type, cone_index_type, cone_target_strided_filter_type, cone_target_filter_type, target_extractor_type, true> BaseSequence;
1137: typedef ALE::XSifterDef::ArrowSequence<xsifter_type, cone_index_type, cone_target_filter_type, cone_target_filter_type, source_extractor_type> ConeSequence;
1138: //
1139: // Basic interface
1140: //
1141: XSifter(const MPI_Comm comm, int debug = 0) : // FIXIT: Should really inherit from XParallelObject
1142: XObject(debug), _rec_set(),
1143: _cone_index(::boost::multi_index::get<ConeTag>(this->_rec_set))
1144: {};
1145: //
1146: // Extended interface
1147: //
1148: void addArrow(const arrow_type& a, const predicate_type& p) {
1149: this->_rec_set.insert(rec_type(a,p));
1150: };
1151: void addArrow(const arrow_type& a) {
1152: this->_rec_set.insert(rec_type(a));
1153: };
1154: //
1155: void cone(const target_type& t, ConeSequence& seq) {
1156: seq.reset(this, &this->_cone_index,cone_target_filter_type(&this->_cone_index,t,t),cone_target_filter_type(&this->_cone_index,t,t));
1157: };
1158: ConeSequence& cone(const target_type& t) {
1159: static ConeSequence cseq;
1160: this->cone(t,cseq);
1161: return cseq;
1162: };
1163: //
1164: void base(BaseSequence& seq) {
1165: seq.reset(this, &this->_cone_index,cone_target_strided_filter_type(&this->_cone_index),cone_target_strided_filter_type(&this->_cone_index));
1166: };
1167: BaseSequence& base() {
1168: static BaseSequence bseq;
1169: this->base(bseq);
1170: return bseq;
1171: };
1172: //
1173: template<typename ostream_type>
1174: void view(ostream_type& os, const char* label = NULL){
1175: if(label != NULL) {
1176: os << "Viewing " << label << " XSifter (debug: " << this->debug() << "): " << std::endl;
1177: }
1178: else {
1179: os << "Viewing a XSifter (debug: " << this->debug() << "): " << std::endl;
1180: }
1181: os << "Cone index: (";
1182: for(typename cone_index_type::iterator itor = this->_cone_index.begin(); itor != this->_cone_index.end(); ++itor) {
1183: os << *itor << " ";
1184: }
1185: os << ")" << std::endl;
1186: };
1187: //
1188: // Direct access (a kind of hack)
1189: //
1190: // Whole container begin/end
1191: typedef typename cone_index_type::iterator iterator;
1192: iterator begin() const {return this->_cone_index.begin();};
1193: iterator end() const {return this->_cone_index.end();};
1194: //
1195: // Slice class
1196: //
1197: struct Slice {
1198: //
1199: public:
1200: typedef XSifter xsifter_type;
1201: //
1202: // Encapsulated types: re-export types and/or bind parameterized types
1203: //
1204: typedef typename xsifter_type::rec_type rec_type;
1205: //
1206: class iterator {
1207: protected:
1208: typename xsifter_type::iterator _itor;
1209: protected:
1210: iterator() {};
1211: iterator(const xsifter_type::iterator itor) : _itor(itor) {};
1212: public:
1213: virtual iterator operator=(const iterator& iter) const {this->_itor = iter._itor; return *this;};
1214: virtual bool operator==(const iterator& iter) const {return this->_itor == iter._itor;};
1215: virtual bool operator!=(const iterator& iter) const {return this->_itor != iter._itor;};
1216: virtual iterator operator++() {
1217: this->_itor = (xsifter_type::iterator)(this->_itor->rec().slice_ptr());
1218: return *this;
1219: };
1220: virtual iterator operator++(int n) {iterator tmp(*this); ++(*this); return tmp;};
1221: //
1222: virtual const source_type& source() const {return this->_itor->_source;};
1223: virtual const target_type& target() const {return this->_itor->_target;};
1224: virtual const arrow_type& arrow() const {return *(this->_itor);};
1225: //
1226: };
1227: protected:
1228: xsifter_type _xsifter;
1229: predicate_type _slice_marker;
1230: void* _slice_head;
1231: void* _slice_tail;
1232: bool _clean_on_destruction;
1233: public:
1234: //
1235: // Basic interface
1236: //
1237: Slice(xsifter_type *xsifter, const predicate_type& marker = predicate_traits::zero(), const bool& clean = false) :
1238: _slice_marker(marker), _slice_head(NULL), _slice_tail(NULL), _clean_on_destruction(clean) {};
1239: ~Slice() {
1240: if(this->_clean_on_destruction) {
1241: iterator tmp;
1242: iterator sitor = this->begin();
1243: iterator send = this->end();
1244: for(;sitor != send();) {
1245: tmp = ++sitor;
1246: // CONTINUE: modify (*itor)'s _slice_marker and _next_in_slice pointer.
1247: sitor = tmp;
1248: }
1249: }// if(this->_clean_on_destruction)
1250: };// ~Slice()
1251: iterator begin(){ return iterator((typename xsifter_type::iterator)this->_slice_head);};
1252: iterator end(){ return iterator((typename xsifter_type::iterator)((xsifter_type::iterator)(this->_slice_tail)->rec().slice_ptr()));};
1253: void add(const xsifter_type::iterator& itor) {
1254: // add *itor at the tail of the slice linked list
1255: static typename xsifter_type::rec_type::SliceChanger tailSlicer(this->_slice_marker, NULL), nextSlicer;
1256: nextSlicer.setSlice(this->_slice_marker, (void*)itor);
1257: // set the current slice tail to point to itor
1258: // CAUTION: hoping for no cycles; can check itor's slice_marker, but will hurt performance
1259: // However, the caller should really be checking that itor is not in the slice yet; otherwise the 'set' semantics are violated.
1260: this->_xsifter.update((typename xsifter_type::iterator)(this->_slice_tail), nextSlicer);
1261: // mark itor with the slice_marker and set it -- the new tail -- to point to NULL
1262: this->_xsifter.update(itor, tailSlicer);
1263: };
1264: //
1265: };// Slice
1266:
1267: protected:
1268: // set of arrow records
1269: rec_set_type _rec_set;
1270: cone_index_type& _cone_index;
1271: public:
1272: //
1273: }; // class XSifter
1275:
1276: } // namespace ALE
1278: #endif