enumerator.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: enumerator.h,v 1.34 2005/12/23 17:01:40 amoll Exp $
00005 //
00006 
00007 #ifndef BALL_CONCEPT_ENUMERATOR_H
00008 #define BALL_CONCEPT_ENUMERATOR_H
00009 
00010 #ifndef BALL_COMMON_H
00011 # include <BALL/common.h>
00012 #endif
00013 
00014 #ifndef BALL_COMMON_EXCEPTION_H
00015 # include <BALL/COMMON/exception.h>
00016 #endif
00017 
00018 #ifndef BALL_COMMON_RTTI_H
00019 # include <BALL/COMMON/rtti.h>
00020 #endif
00021 
00022 #ifndef BALL_CONCEPT_FORWARDITERATOR_H
00023 # include <BALL/CONCEPT/forwardIterator.h>
00024 #endif
00025 
00026 #include <vector>
00027 #include <list>
00028 #include <algorithm>
00029 
00030 namespace BALL
00031 {
00032 
00047   class BALL_EXPORT EnumeratorIndex
00048     : private std::vector<Position>
00049   {
00050     public:
00051 
00058     class BALL_EXPORT IncompatibleIndex
00059       : public Exception::GeneralException
00060     {
00061       public:
00062 
00063       IncompatibleIndex(const char* file, int line)
00064         ;
00065     };
00066 
00068 
00072       
00075     EnumeratorIndex()
00076       ;
00077 
00081     template <typename Variant, typename VariantIterator>
00082     EnumeratorIndex(const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00083       ;
00084 
00087     ~EnumeratorIndex()
00088       ;
00089 
00091 
00097     const EnumeratorIndex& operator = (const EnumeratorIndex& rhs)
00098       ;
00099 
00102     const EnumeratorIndex& operator = (Position index)
00103       throw(Exception::IndexOverflow);
00104 
00107     template <typename Variant, typename VariantIterator>
00108     const EnumeratorIndex& operator = (const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00109       ;
00111 
00115 
00118     const std::vector<Size>& getModulus() const
00119       ;
00120 
00123     Size getModulus(Position pos) const
00124       ;
00125       
00130     EnumeratorIndex& operator ++ ()
00131       throw(Exception::IndexOverflow);
00132 
00137     EnumeratorIndex& operator -- ()
00138       throw(Exception::IndexUnderflow);
00139 
00142     Position operator [] (Position pos) const
00143       ;
00144 
00147     Position& operator [] (Position pos)
00148       ;
00149 
00152     Size getSize() const
00153       ;
00154 
00166     EnumeratorIndex& operator << (Size modulus)
00167       throw(Exception::OutOfRange);
00169     
00173 
00178     bool operator == (const EnumeratorIndex& rhs) const
00179       ;
00180 
00185     bool operator != (const EnumeratorIndex& rhs) const
00186       ;
00187 
00193     bool operator > (const EnumeratorIndex& rhs) const
00194       throw(EnumeratorIndex::IncompatibleIndex);
00195 
00201     bool operator < (const EnumeratorIndex& rhs) const
00202       throw(EnumeratorIndex::IncompatibleIndex);
00203         
00209     bool operator >= (const EnumeratorIndex& rhs) const
00210       throw(EnumeratorIndex::IncompatibleIndex);
00211 
00217     bool operator <= (const EnumeratorIndex& rhs) const
00218       throw(EnumeratorIndex::IncompatibleIndex);
00220 
00221     private:
00223     std::vector<Size> modulus_;
00225     std::vector<Size> base_multipliers_;
00226   };
00227 
00228 
00229   template <typename Variant, typename VariantIterator>
00230   EnumeratorIndex::EnumeratorIndex(const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00231     
00232     : std::vector<Position>(variant_list.size()),
00233       modulus_(variant_list.size()),
00234       base_multipliers_(variant_list.size())
00235   { 
00236     this->operator = (variant_list);
00237   }
00238 
00239 
00240   template <typename Variant, typename VariantIterator>
00241   const EnumeratorIndex& EnumeratorIndex::operator = 
00242     (const std::list<std::pair<VariantIterator, std::vector<Variant> > >& variant_list)
00243     
00244   { 
00245     resize(variant_list.size());
00246     modulus_.resize(variant_list.size());
00247     base_multipliers_.resize(variant_list.size());
00248 
00249     // compute the base multipliers for later usage 
00250     Index i;
00251     Size multiplier = 1;
00252     typename std::list<std::pair<VariantIterator, std::vector<Variant> > >::const_iterator list_it = variant_list.begin();
00253     for (i = (Size)(size() - 1); i >= 0; i--, list_it++)
00254     {
00255       operator[](i) = 0;
00256       modulus_[i] = (Size)list_it->second.size();
00257 
00258       base_multipliers_[i] = multiplier;
00259       multiplier *= modulus_[i];
00260     }
00261     
00262     return *this;
00263   }
00264 
00265 
00294   template <class Container, class SiteIterator, class Variant>
00295   class Enumerator
00296   { 
00297     protected:
00298     class IteratorTraits_;
00299     
00300     public:
00301 
00305       
00314     typedef void (*MutatorFunction) (Variant&, const Variant&);
00315 
00318     typedef std::vector<Variant>              
00319       VariantVector;
00320 
00323     typedef std::pair<SiteIterator, VariantVector>
00324       Site;
00325 
00328     typedef std::list<Site>
00329       SiteList;
00330 
00333     typedef ForwardIterator<Enumerator<Container, SiteIterator, Variant>, Container, EnumeratorIndex*, IteratorTraits_>
00334       Iterator;
00335 
00338     typedef ConstForwardIterator<Enumerator<Container, SiteIterator, Variant>, Container, EnumeratorIndex*, IteratorTraits_>
00339       ConstIterator;
00341 
00345 
00348     Enumerator()
00349       ;
00350 
00356     Enumerator(Container& container)
00357       ;
00358 
00363     Enumerator(Container& container, MutatorFunction mutator)
00364       ;
00365 
00368     ~Enumerator()
00369       
00370     {
00371     }
00373 
00377 
00380     void addVariants(const SiteIterator& it, const VariantVector& variants)
00381       
00382     {
00383       variant_sites_.push_back(Site(it, variants));
00384       position_ = variant_sites_;
00385     }
00386 
00389     void deleteVariants(const SiteIterator& it, const VariantVector& variants)
00390       
00391     {
00392       typename SiteList::iterator var_it;
00393       var_it = std::find(variant_sites_.begin(), variant_sites_.end(), Site(it, variants));
00394       if (var_it != variant_sites_.end())
00395       {
00396         variant_sites_.erase(var_it);
00397       }
00398       position_ = variant_sites_;
00399     }
00400 
00404     Size countVariants()
00405       
00406     {
00407       Size total = 1;
00408       typename SiteList::iterator it;
00409       for (it = variant_sites_.begin(); it != variant_sites_.end(); ++it)
00410       {
00411         total *= it->second.size();
00412       }
00413       return total;
00414     }
00415 
00419     Container& getCurrent()
00420       ;
00421 
00425     void createCombination(const Position index)
00426       throw(Exception::IndexOverflow);
00427 
00432     void createCombination(const EnumeratorIndex& index)
00433       throw(EnumeratorIndex::IncompatibleIndex);
00435 
00439     
00441     Iterator begin()
00442       ;
00443 
00445     Iterator end()
00446       ;
00447 
00449     ConstIterator begin() const
00450       ;
00451 
00453     ConstIterator end() const
00454       ;
00456 
00457     protected:
00458 
00459     friend class IteratorTraits_;
00460 
00463     class IteratorTraits_
00464     {
00465       friend class Enumerator<Container, SiteIterator, Variant>;
00466       
00467       public:
00468         
00469       typedef Enumerator<Container, SiteIterator, Variant>
00470         ContainerType;
00471 
00472       typedef Enumerator<Container, SiteIterator, Variant>* 
00473         ContainerPointer;
00474 
00475       typedef const Enumerator<Container, SiteIterator, Variant>* 
00476         ContainerConstPointer;
00477 
00478       typedef EnumeratorIndex
00479         IteratorPosition;
00480 
00481       typedef Container
00482         ValueType;
00483 
00484       IteratorTraits_()
00485         
00486         : bound_(0),  
00487           position_(),
00488           past_the_end_(false)
00489       {
00490       }
00491         
00492       IteratorTraits_(const ContainerType& enumerator)
00493         
00494         : bound_(const_cast<ContainerPointer>(&enumerator)),
00495           position_(enumerator.variant_sites_),
00496           past_the_end_(false)
00497       {
00498       }
00499       
00500       ContainerConstPointer getContainer() const  
00501         
00502       {
00503         return bound_;
00504       }
00505       
00506       ContainerPointer getContainer()
00507         
00508       {
00509         return bound_;
00510       }
00511 
00512       bool isSingular() const
00513         
00514       {
00515         return (bound_ == 0);
00516       }
00517  
00518       IteratorPosition& getPosition()
00519         
00520       {
00521         return position_;
00522       }
00523 
00524       const IteratorPosition& getPosition() const
00525         
00526       {
00527         return position_;
00528       }
00529 
00530       bool operator == (const IteratorTraits_& traits) const
00531         
00532       {
00533         return ((bound_ == traits.bound_) && (position_ == traits.position_) && (past_the_end_ == traits.past_the_end_));
00534       }
00535 
00536       bool operator != (const IteratorTraits_& traits) const
00537         
00538       {
00539         return ((bound_ != traits.bound_) || (position_ != traits.position_) || (past_the_end_ != traits.past_the_end_));
00540       }
00541 
00542       bool isValid() const
00543         
00544       {
00545         return (bound_ != 0);
00546       }
00547 
00548       void invalidate()
00549         
00550       {
00551         bound_ = 0;
00552         position_ = 0;
00553         past_the_end_ = false;
00554       }
00555 
00556       void toBegin()
00557         
00558       {
00559         position_ = 0;
00560         past_the_end_ = false;
00561       }
00562 
00563       bool isBegin() const
00564         
00565       {
00566         return (position_ == EnumeratorIndex()) && (past_the_end_ == false);
00567       }
00568       
00569       void toEnd()
00570         
00571       {
00572         position_ = 0;
00573         past_the_end_ = true;
00574       }
00575       
00576       bool isEnd() const
00577         
00578       {
00579         return past_the_end_;
00580       }
00581       
00582       ValueType& getData()
00583         
00584       {
00585         validate();
00586         return bound_->getCurrent();
00587       }
00588       
00589       const ValueType& getData() const
00590         
00591       {
00592         // This is logically const only!
00593         const_cast<typename Enumerator<Container, SiteIterator, Variant>::IteratorTraits_*>(this)->validate();
00594         return bound_->getCurrent();
00595       }
00596       
00597       void forward()
00598         
00599       {
00600         try
00601         {
00602           ++position_;
00603         }
00604         catch (Exception::IndexOverflow&)
00605         {
00606           past_the_end_ = true;
00607           position_ = 0;
00608         }
00609       }
00610       
00611       void validate()
00612         
00613       {
00614         if (!bound_->is_valid_position_
00615             || (position_ != bound_->position_))
00616         {
00617           bound_->createCombination(position_);
00618         }
00619       }
00620 
00621       protected:
00622       ContainerPointer  bound_;
00623       EnumeratorIndex   position_;
00624       bool              past_the_end_;
00625     };
00626 
00627     // the default mutation method (calling asignment operator)
00628     static inline void defaultAssign_(Variant& a, const Variant& b)
00629     {
00630       a = b;
00631     }
00632 
00633     void mutate_(SiteIterator& it, const Variant& v)
00634       
00635     {
00636       mutator_(*it, v);
00637     }
00638 
00639     Container&      container_;
00640     MutatorFunction mutator_;
00641     SiteList        variant_sites_;
00642     EnumeratorIndex position_;
00643     bool            is_valid_position_;
00644   };
00645 
00646   template <typename Container, typename SiteIterator, typename Variant>
00647   Enumerator<Container, SiteIterator, Variant>::Enumerator()
00648       
00649     : container_(const_cast<Container&>(RTTI::getDefault<Container>())),
00650       mutator_(0)
00651   {
00652   }
00653     
00654   template <typename Container, typename SiteIterator, typename Variant>
00655   Enumerator<Container, SiteIterator, Variant>::Enumerator(Container& container)
00656       
00657     : container_(container),
00658       mutator_(defaultAssign_)
00659   {
00660   }
00661     
00662   template <typename Container, typename SiteIterator, typename Variant>
00663   BALL_INLINE
00664   Enumerator<Container, SiteIterator, Variant>::Enumerator
00665     (Container& container, typename Enumerator<Container, SiteIterator, Variant>::MutatorFunction mutator)
00666     
00667     : container_(container),
00668       mutator_(mutator)
00669   {
00670   }
00671 
00672 
00673   template <typename Container, typename SiteIterator, typename Variant>
00674   BALL_INLINE
00675   Container& Enumerator<Container, SiteIterator, Variant>::getCurrent()
00676     
00677   {
00678     return container_;
00679   }
00680   
00681   template <typename Container, typename SiteIterator, typename Variant>
00682   void Enumerator<Container, SiteIterator, Variant>::createCombination(const Position index)
00683     throw(Exception::IndexOverflow)
00684   {
00685     try
00686     {
00687       position_ = index;
00688       createCombination(position_);
00689     }
00690     catch (EnumeratorIndex::IncompatibleIndex&)
00691     {
00692       throw Exception::IndexOverflow(__FILE__, __LINE__, index);
00693     }
00694   }
00695 
00696   template <typename Container, typename SiteIterator, typename Variant>
00697   void Enumerator<Container, SiteIterator, Variant>::createCombination(const EnumeratorIndex& index)
00698     throw(EnumeratorIndex::IncompatibleIndex)
00699   {
00700     if (&index != &position_)
00701     {
00702       position_ = index;
00703     }
00704 
00705     typename SiteList::iterator it = variant_sites_.begin();
00706     Position i((Position)(index.getSize() - 1));
00707     for (; it != variant_sites_.end(); ++it, --i)
00708     {
00709       mutate_(it->first, it->second[index[i]]);
00710     }
00711     
00712     is_valid_position_ = true;
00713   }
00714 
00715   template <typename Container, typename SiteIterator, typename Variant>
00716   BALL_INLINE
00717   typename Enumerator<Container, SiteIterator, Variant>::Iterator Enumerator<Container, SiteIterator, Variant>::begin()
00718     
00719   {
00720     return Iterator::begin(*this);
00721   }
00722 
00723   template <typename Container, typename SiteIterator, typename Variant>
00724   BALL_INLINE
00725   typename Enumerator<Container, SiteIterator, Variant>::Iterator Enumerator<Container, SiteIterator, Variant>::end()
00726     
00727   {
00728     return Iterator::end(*this);
00729   }
00730 
00731   template <typename Container, typename VariantConstIterator, typename Variant>
00732   BALL_INLINE
00733   typename Enumerator<Container, VariantConstIterator, Variant>::ConstIterator Enumerator<Container, VariantConstIterator, Variant>::begin() const
00734     
00735   {
00736     return ConstIterator::begin(*this);
00737   }
00738 
00739   template <typename Container, typename VariantConstIterator, typename Variant>
00740   BALL_INLINE
00741   typename Enumerator<Container, VariantConstIterator, Variant>::ConstIterator Enumerator<Container, VariantConstIterator, Variant>::end() const
00742     
00743   {
00744     return ConstIterator::end(*this);
00745   }
00746 
00747   
00748 # ifndef BALL_NO_INLINE_FUNCTIONS
00749 #   include <BALL/CONCEPT/enumerator.iC>
00750 # endif
00751 
00752 }
00753 
00754 #endif // BALL_CONCEPT_ENUMERATOR_H