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