00001
00002
00003
00004
00005 #ifndef BALL_CONCEPT_ENUMERATOR_H
00006 #define BALL_CONCEPT_ENUMERATOR_H
00007
00008 #ifndef BALL_COMMON_H
00009 # include <BALL/common.h>
00010 #endif
00011
00012 #ifndef BALL_COMMON_EXCEPTION_H
00013 # include <BALL/COMMON/exception.h>
00014 #endif
00015
00016 #ifndef BALL_COMMON_RTTI_H
00017 # include <BALL/COMMON/rtti.h>
00018 #endif
00019
00020 #ifndef BALL_CONCEPT_FORWARDITERATOR_H
00021 # include <BALL/CONCEPT/forwardIterator.h>
00022 #endif
00023
00024 #include <vector>
00025 #include <list>
00026 #include <algorithm>
00027
00028 namespace BALL
00029 {
00030
00045 class BALL_EXPORT EnumeratorIndex
00046 : private std::vector<Position>
00047 {
00048 public:
00049
00056 class BALL_EXPORT IncompatibleIndex
00057 : public Exception::GeneralException
00058 {
00059 public:
00060
00061 IncompatibleIndex(const char* file, int line);
00062 };
00063
00065
00069
00072 EnumeratorIndex();
00073
00077 template <typename Variant, typename VariantIterator>
00078 EnumeratorIndex(const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list);
00079
00082 ~EnumeratorIndex();
00083
00085
00091 const EnumeratorIndex& operator = (const EnumeratorIndex& rhs);
00092
00096 const EnumeratorIndex& operator = (Position index);
00097
00100 template <typename Variant, typename VariantIterator>
00101 const EnumeratorIndex& operator = (const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list);
00103
00107
00110 const std::vector<Size>& getModulus() const;
00111
00114 Size getModulus(Position pos) const;
00115
00121 EnumeratorIndex& operator ++ ();
00122
00128 EnumeratorIndex& operator -- ();
00129
00132 Position operator [] (Position pos) const;
00133
00136 Position& operator [] (Position pos);
00137
00140 Size getSize() const;
00141
00153 EnumeratorIndex& operator << (Size modulus);
00155
00159
00164 bool operator == (const EnumeratorIndex& rhs) const;
00165
00170 bool operator != (const EnumeratorIndex& rhs) const;
00171
00177 bool operator > (const EnumeratorIndex& rhs) const;
00178
00184 bool operator < (const EnumeratorIndex& rhs) const;
00185
00191 bool operator >= (const EnumeratorIndex& rhs) const;
00192
00198 bool operator <= (const EnumeratorIndex& rhs) const;
00200
00201 private:
00203 std::vector<Size> modulus_;
00205 std::vector<Size> base_multipliers_;
00206 };
00207
00208
00209 template <typename Variant, typename VariantIterator>
00210 EnumeratorIndex::EnumeratorIndex(const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00211 : std::vector<Position>(variant_list.size()),
00212 modulus_(variant_list.size()),
00213 base_multipliers_(variant_list.size())
00214 {
00215 this->operator = (variant_list);
00216 }
00217
00218
00219 template <typename Variant, typename VariantIterator>
00220 const EnumeratorIndex& EnumeratorIndex::operator =
00221 (const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00222 {
00223 resize(variant_list.size());
00224 modulus_.resize(variant_list.size());
00225 base_multipliers_.resize(variant_list.size());
00226
00227
00228 Index i;
00229 Size multiplier = 1;
00230 typename std::list<std::pair<VariantIterator, std::vector<Variant> > >::const_iterator list_it = variant_list.begin();
00231 for (i = (Size)(size() - 1); i >= 0; i--, list_it++)
00232 {
00233 operator[](i) = 0;
00234 modulus_[i] = (Size)list_it->second.size();
00235
00236 base_multipliers_[i] = multiplier;
00237 multiplier *= modulus_[i];
00238 }
00239
00240 return *this;
00241 }
00242
00243
00272 template <class Container, class SiteIterator, class Variant>
00273 class Enumerator
00274 {
00275 protected:
00276 class IteratorTraits_;
00277
00278 public:
00279
00283
00292 typedef void (*MutatorFunction) (Variant&, const Variant&);
00293
00296 typedef std::vector<Variant> VariantVector;
00297
00300 typedef std::pair<SiteIterator, VariantVector> Site;
00301
00304 typedef std::list<Site> SiteList;
00305
00308 typedef ForwardIterator<Enumerator<Container, SiteIterator, Variant>, Container, EnumeratorIndex*, IteratorTraits_>
00309 Iterator;
00310
00313 typedef ConstForwardIterator<Enumerator<Container, SiteIterator, Variant>, Container, EnumeratorIndex*, IteratorTraits_>
00314 ConstIterator;
00316
00320
00323 Enumerator();
00324
00330 Enumerator(Container& container);
00331
00336 Enumerator(Container& container, MutatorFunction mutator);
00337
00340 ~Enumerator()
00341 {
00342 }
00344
00348
00351 void addVariants(const SiteIterator& it, const VariantVector& variants)
00352 {
00353 variant_sites_.push_back(Site(it, variants));
00354 position_ = variant_sites_;
00355 }
00356
00359 void deleteVariants(const SiteIterator& it, const VariantVector& variants)
00360 {
00361 typename SiteList::iterator var_it;
00362 var_it = std::find(variant_sites_.begin(), variant_sites_.end(), Site(it, variants));
00363 if (var_it != variant_sites_.end())
00364 {
00365 variant_sites_.erase(var_it);
00366 }
00367 position_ = variant_sites_;
00368 }
00369
00373 Size countVariants()
00374 {
00375 Size total = 1;
00376 typename SiteList::iterator it;
00377 for (it = variant_sites_.begin(); it != variant_sites_.end(); ++it)
00378 {
00379 total *= it->second.size();
00380 }
00381 return total;
00382 }
00383
00387 Container& getCurrent();
00388
00393 void createCombination(const Position index);
00394
00400 void createCombination(const EnumeratorIndex& index);
00402
00406
00408 Iterator begin();
00409
00411 Iterator end();
00412
00414 ConstIterator begin() const;
00415
00417 ConstIterator end() const;
00419
00420 protected:
00421
00422 friend class IteratorTraits_;
00423
00426 class IteratorTraits_
00427 {
00428 friend class Enumerator<Container, SiteIterator, Variant>;
00429
00430 public:
00431
00432 typedef Enumerator<Container, SiteIterator, Variant>
00433 ContainerType;
00434
00435 typedef Enumerator<Container, SiteIterator, Variant>*
00436 ContainerPointer;
00437
00438 typedef const Enumerator<Container, SiteIterator, Variant>*
00439 ContainerConstPointer;
00440
00441 typedef EnumeratorIndex
00442 IteratorPosition;
00443
00444 typedef Container
00445 ValueType;
00446
00447 IteratorTraits_()
00448 : bound_(0),
00449 position_(),
00450 past_the_end_(false)
00451 {
00452 }
00453
00454 IteratorTraits_(const ContainerType& enumerator)
00455 : bound_(const_cast<ContainerPointer>(&enumerator)),
00456 position_(enumerator.variant_sites_),
00457 past_the_end_(false)
00458 {
00459 }
00460
00461 ContainerConstPointer getContainer() const
00462 {
00463 return bound_;
00464 }
00465
00466 ContainerPointer getContainer()
00467 {
00468 return bound_;
00469 }
00470
00471 bool isSingular() const
00472 {
00473 return (bound_ == 0);
00474 }
00475
00476 IteratorPosition& getPosition()
00477 {
00478 return position_;
00479 }
00480
00481 const IteratorPosition& getPosition() const
00482 {
00483 return position_;
00484 }
00485
00486 bool operator == (const IteratorTraits_& traits) const
00487 {
00488 return ((bound_ == traits.bound_) && (position_ == traits.position_) && (past_the_end_ == traits.past_the_end_));
00489 }
00490
00491 bool operator != (const IteratorTraits_& traits) const
00492 {
00493 return ((bound_ != traits.bound_) || (position_ != traits.position_) || (past_the_end_ != traits.past_the_end_));
00494 }
00495
00496 bool isValid() const
00497 {
00498 return (bound_ != 0);
00499 }
00500
00501 void invalidate()
00502 {
00503 bound_ = 0;
00504 position_ = 0;
00505 past_the_end_ = false;
00506 }
00507
00508 void toBegin()
00509 {
00510 position_ = 0;
00511 past_the_end_ = false;
00512 }
00513
00514 bool isBegin() const
00515 {
00516 return (position_ == EnumeratorIndex()) && (past_the_end_ == false);
00517 }
00518
00519 void toEnd()
00520 {
00521 position_ = 0;
00522 past_the_end_ = true;
00523 }
00524
00525 bool isEnd() const
00526 {
00527 return past_the_end_;
00528 }
00529
00530 ValueType& getData()
00531 {
00532 validate();
00533 return bound_->getCurrent();
00534 }
00535
00536 const ValueType& getData() const
00537 {
00538
00539 const_cast<typename Enumerator<Container, SiteIterator, Variant>::IteratorTraits_*>(this)->validate();
00540 return bound_->getCurrent();
00541 }
00542
00543 void forward()
00544 {
00545 try
00546 {
00547 ++position_;
00548 }
00549 catch (Exception::IndexOverflow&)
00550 {
00551 past_the_end_ = true;
00552 position_ = 0;
00553 }
00554 }
00555
00556 void validate()
00557 {
00558 if (!bound_->is_valid_position_
00559 || (position_ != bound_->position_))
00560 {
00561 bound_->createCombination(position_);
00562 }
00563 }
00564
00565 protected:
00566 ContainerPointer bound_;
00567 EnumeratorIndex position_;
00568 bool past_the_end_;
00569 };
00570
00571
00572 static inline void defaultAssign_(Variant& a, const Variant& b)
00573 {
00574 a = b;
00575 }
00576
00577 void mutate_(SiteIterator& it, const Variant& v)
00578 {
00579 mutator_(*it, v);
00580 }
00581
00582 Container& container_;
00583 MutatorFunction mutator_;
00584 SiteList variant_sites_;
00585 EnumeratorIndex position_;
00586 bool is_valid_position_;
00587 };
00588
00589 template <typename Container, typename SiteIterator, typename Variant>
00590 Enumerator<Container, SiteIterator, Variant>::Enumerator()
00591 : container_(const_cast<Container&>(RTTI::getDefault<Container>())),
00592 mutator_(0)
00593 {
00594 }
00595
00596 template <typename Container, typename SiteIterator, typename Variant>
00597 Enumerator<Container, SiteIterator, Variant>::Enumerator(Container& container)
00598 : container_(container),
00599 mutator_(defaultAssign_)
00600 {
00601 }
00602
00603 template <typename Container, typename SiteIterator, typename Variant>
00604 BALL_INLINE
00605 Enumerator<Container, SiteIterator, Variant>::Enumerator
00606 (Container& container, typename Enumerator<Container, SiteIterator, Variant>::MutatorFunction mutator)
00607 : container_(container),
00608 mutator_(mutator)
00609 {
00610 }
00611
00612
00613 template <typename Container, typename SiteIterator, typename Variant>
00614 BALL_INLINE
00615 Container& Enumerator<Container, SiteIterator, Variant>::getCurrent()
00616 {
00617 return container_;
00618 }
00619
00620 template <typename Container, typename SiteIterator, typename Variant>
00621 void Enumerator<Container, SiteIterator, Variant>::createCombination(const Position index)
00622 {
00623 try
00624 {
00625 position_ = index;
00626 createCombination(position_);
00627 }
00628 catch (EnumeratorIndex::IncompatibleIndex&)
00629 {
00630 throw Exception::IndexOverflow(__FILE__, __LINE__, index);
00631 }
00632 }
00633
00634 template <typename Container, typename SiteIterator, typename Variant>
00635 void Enumerator<Container, SiteIterator, Variant>::createCombination(const EnumeratorIndex& index)
00636 {
00637 if (&index != &position_)
00638 {
00639 position_ = index;
00640 }
00641
00642 typename SiteList::iterator it = variant_sites_.begin();
00643 Position i((Position)(index.getSize() - 1));
00644 for (; it != variant_sites_.end(); ++it, --i)
00645 {
00646 mutate_(it->first, it->second[index[i]]);
00647 }
00648
00649 is_valid_position_ = true;
00650 }
00651
00652 template <typename Container, typename SiteIterator, typename Variant>
00653 BALL_INLINE
00654 typename Enumerator<Container, SiteIterator, Variant>::Iterator Enumerator<Container, SiteIterator, Variant>::begin()
00655 {
00656 return Iterator::begin(*this);
00657 }
00658
00659 template <typename Container, typename SiteIterator, typename Variant>
00660 BALL_INLINE
00661 typename Enumerator<Container, SiteIterator, Variant>::Iterator Enumerator<Container, SiteIterator, Variant>::end()
00662 {
00663 return Iterator::end(*this);
00664 }
00665
00666 template <typename Container, typename VariantConstIterator, typename Variant>
00667 BALL_INLINE
00668 typename Enumerator<Container, VariantConstIterator, Variant>::ConstIterator Enumerator<Container, VariantConstIterator, Variant>::begin() const
00669 {
00670 return ConstIterator::begin(*this);
00671 }
00672
00673 template <typename Container, typename VariantConstIterator, typename Variant>
00674 BALL_INLINE
00675 typename Enumerator<Container, VariantConstIterator, Variant>::ConstIterator Enumerator<Container, VariantConstIterator, Variant>::end() const
00676 {
00677 return ConstIterator::end(*this);
00678 }
00679
00680
00681 # ifndef BALL_NO_INLINE_FUNCTIONS
00682 # include <BALL/CONCEPT/enumerator.iC>
00683 # endif
00684
00685 }
00686
00687 #endif // BALL_CONCEPT_ENUMERATOR_H