Depends.h

Go to the documentation of this file.
00001 /* Depends: A generic dependency tracker in C++
00002  * Copyright (c) 2004-2007, Ronald Landheer-Cieslak
00003  * All rights reserved
00004  * 
00005  * This is free software. You may distribute it and/or modify it and
00006  * distribute modified forms provided that the following terms are met:
00007  *
00008  * * Redistributions of the source code must retain the above copyright
00009  *   notice, this list of conditions and the following disclaimer;
00010  * * Redistributions in binary form must reproduce the above copyright
00011  *   notice, this list of conditions and the following disclaimer in
00012  *   the documentation and/or other materials provided with the distribution;
00013  * * None of the names of the authors of this software may be used to endorse
00014  *   or promote this software, derived software or any distribution of this 
00015  *   software or any distribution of which this software is part, without 
00016  *   prior written permission from the authors involved;
00017  * * Unless you have received a written statement from Ronald Landheer-Cieslak
00018  *   that says otherwise, the terms of the GNU General Public License, as 
00019  *   published by the Free Software Foundation, version 2 or (at your option)
00020  *   any later version, also apply.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  * POSSIBILITY OF SUCH DAMAGE.
00033  */
00035 #ifndef _depends_depends_h
00036 #define _depends_depends_h
00037 
00038 #include <algorithm>
00039 #include <cassert>
00040 #include <set>
00041 #include "DAG.h"
00042 
00043 namespace Depends
00044 {
00100         template < typename ValueType >
00101         class Depends
00102         {
00103                 // here only so we can use it below
00104                 typedef std::set< ValueType > Storage;
00105         public :
00107                 typedef typename Storage::iterator iterator;
00109                 typedef typename Storage::const_iterator const_iterator;
00111                 typedef typename Storage::reverse_iterator reverse_iterator;
00113                 typedef typename Storage::const_reverse_iterator const_reverse_iterator;
00114 
00116                 typedef typename std::iterator_traits< iterator >::value_type value_type;
00118                 typedef typename std::iterator_traits< iterator >::reference reference;
00120                 typedef typename std::iterator_traits< const_iterator >::reference const_reference;
00122                 typedef typename std::iterator_traits< iterator >::pointer pointer;
00124                 typedef typename std::iterator_traits< iterator >::difference_type difference_type;
00126                 typedef typename Storage::size_type size_type;
00127 
00129                 Depends()
00130                         : selected_(0)
00131                 { /* no-op */ }
00133                 template < typename InputIterator >
00134                 Depends(InputIterator begin, InputIterator end)
00135                         : selected_(0)
00136                 { insert(begin, end); }
00137 
00139                 bool empty() const throw()
00140                 { return storage_.empty(); }
00141                 size_type size() const throw()
00142                 { return storage_.size(); }
00143 
00145                 iterator begin()
00146                 { return iterator(storage_.begin()); }
00148                 const_iterator begin() const
00149                 { return const_iterator(storage_.begin()); }
00151                 iterator end()
00152                 { return iterator(storage_.end()); }
00154                 const_iterator end() const
00155                 { return const_iterator(storage_.end()); }
00157                 reverse_iterator rbegin()
00158                 { return reverse_iterator(storage_.rbegin()); }
00160                 const_reverse_iterator rbegin() const
00161                 { return const_reverse_iterator(storage_.rbegin()); }
00163                 reverse_iterator rend()
00164                 { return reverse_iterator(storage_.rend()); }
00166                 const_reverse_iterator rend() const
00167                 { return const_reverse_iterator(storage_.rend()); }
00168 
00170                 template < typename V >
00171                 const_iterator find(const V & v) const throw()
00172                 { return storage_.find(v); }
00173                 template < typename V >
00174                 iterator find(const V & v) throw()
00175                 { return storage_.find(v); }
00176 
00178                 template < typename InputIterator >
00179                 void insert(InputIterator begin, InputIterator end)
00180                 {
00181                         for (InputIterator where(begin); where != end; ++where)
00182                                 insert(*where);
00183                 }
00185                 std::pair< iterator, bool > insert( const value_type & v )
00186                 {
00187                         std::pair< iterator, bool > retval(storage_.insert(v));
00188                         if (retval.second)
00189                         {
00190                                 prerequisites_.insert(getPointer(retval.first));
00191                                 dependants_.insert(getPointer(retval.first));
00192                         }
00193                         else
00194                         { /* nothing really inserted */ }
00195 
00196                         return retval;
00197                 }
00199                 iterator insert( const iterator & where, const value_type & what )
00200                 { return insert(what).first; }
00201 
00203                 template < typename V >
00204                 size_type erase(const V & v)
00205                 {
00206                         size_type erased(0);
00207                         iterator where;
00208                         while ((where = find(v)) != end())
00209                         {
00210                                 erase(where);
00211                                 ++erased;
00212                         }
00213 
00214                         return erased;
00215                 }
00216                 // erase the value at the indicated position
00217                 void erase(iterator where)
00218                 {
00219                         if (selected_)
00220                         {
00221                                 if (where == *selected_)
00222                                         clearSelection();
00223                                 else
00224                                 { /* not erasing the selection */ }
00225                         }
00226                         else
00227                         { /* no selection - nothing to clear */ }
00228                         pointer p(getPointer(where));
00229                         bool found_in_blockers(false);
00230                         typename DAG< pointer >::iterator whence(std::find(dependants_.begin(), dependants_.end(), p));
00231                         if (whence != dependants_.end())
00232                         {
00233                                 dependants_.erase(whence);
00234                                 found_in_blockers = true;
00235                         }
00236                         else
00237                         { /* value not in the blockers DAG */ }
00238                         whence = std::find(prerequisites_.begin(), prerequisites_.end(), p);
00239                         if (whence != prerequisites_.end())
00240                         {
00241                                 prerequisites_.erase(whence);
00242                                 assert(found_in_blockers);
00243                         }
00244                         else
00245                         {       // if it's no in the prerequisites_ DAG, it shouldn't have been in the dependants_ DAG either
00246                                 assert(!found_in_blockers);
00247                         }
00248                         storage_.erase(where);
00249                 }
00250                 // erase all the values in the given sequence
00251                 void erase(const iterator & begin, const iterator & end)
00252                 {
00253                         for (iterator where(begin); where != end; erase(where++))
00254                                 ;
00255                 }
00256                 // clear the container
00257                 void clear()
00258                 {
00259                         clearSelection();
00260                         dependants_.clear();
00261                         prerequisites_.clear();
00262                         storage_.clear();
00263                 }
00264 
00267                 void select(const_iterator what)
00268                 {
00269                         clearSelection();
00270                         if (what == end())
00271                                 throw std::invalid_argument("Cannot select end");
00272                         else
00273                         { /* OK */ }
00274                         selected_ = new const_iterator(what);
00275                 }
00279                 void select(const value_type & v)
00280                 {
00281                         select(insert(v).first);
00282                 }
00283 
00285                 void addPrerequisite(const_iterator whence)
00286                 {
00287                         assert(selected_);
00288                         prerequisites_.link(getPointer(*selected_), getPointer(whence));
00289                         dependants_.link(getPointer(whence), getPointer(*selected_));
00290                 }
00292                 void addPrerequisite(const value_type & v)
00293                 {
00294                         addPrerequisite(insert(v).first);
00295                 }
00298                 void removePrerequisite(const_iterator whence)
00299                 {
00300                         assert(selected_);
00301                         if (whence == end())
00302                                 return;
00303                         else
00304                         { /* dependency could exist */ }
00305                         bool was_prereq(prerequisites_.unlink(getPointer(*selected_), getPointer(whence)));
00306                         bool was_dep(dependants_.unlink(getPointer(whence), getPointer(*selected_)));
00307                         assert((was_dep && was_prereq) || (!was_dep && !was_prereq));
00308                 }
00311                 void removePrerequisite(const value_type & value)
00312                 {
00313                         removePrerequisite(find(value));
00314                 }
00319                 std::set< value_type > getPrerequisites(bool all = false) const
00320                 {
00321                         std::set< value_type > retval;
00322                         typename DAG< pointer >::const_iterator selected(std::find(prerequisites_.begin(), prerequisites_.end(), getPointer(*selected_)));
00323                         const typename DAG< pointer >::node_type * selected_node(selected.node());
00324                         if (all)
00325                         {
00326                                 typedef Details::NodeVisitor< typename DAG< pointer >::node_type, Details::RetrieveTargets, std::set< pointer > * > Visitor;
00327                                 std::set< pointer > temp;
00328                                 Visitor visitor(Details::RetrieveTargets(), &temp);
00329                                 std::for_each(
00330                                         selected_node->targets_.begin(),
00331                                         selected_node->targets_.end(),
00332                                         visitor);
00333                                 std::copy(
00334                                         boost::indirect_iterator< typename std::set< pointer >::const_iterator >(temp.begin()),
00335                                         boost::indirect_iterator< typename std::set< pointer >::const_iterator >(temp.end()),
00336                                         std::inserter(retval, retval.begin()));
00337                         }
00338                         else
00339                         {
00340                                 typename DAG< pointer >::node_type::targets_type::const_iterator end(selected_node->targets_.end());
00341                                 typename DAG< pointer >::node_type::targets_type::const_iterator where(selected_node->targets_.begin());
00342                                 while (where != end)
00343                                 {
00344                                         retval.insert(*((*where)->value_));
00345                                         ++where;
00346                                 }
00347                         }
00348 
00349                         return retval;
00350                 }
00351 
00353                 void addDependant(const_iterator whence)
00354                 {
00355                         assert(selected_);
00356                         dependants_.link(getPointer(*selected_), getPointer(whence));
00357                         prerequisites_.link(getPointer(whence), getPointer(*selected_));
00358                 }
00360                 void addDependant(const value_type & v)
00361                 {
00362                         addDependant(insert(v).first);
00363                 }
00366                 void removeDependant(const_iterator whence)
00367                 {
00368                         assert(selected_);
00369                         if (whence == end())
00370                                 return;
00371                         else
00372                         { /* dependency could exist */ }
00373                         dependants_.unlink(getPointer(*selected_), getPointer(whence));
00374                         prerequisites_.unlink(getPointer(whence), getPointer(*selected_));
00375                 }
00378                 void removeDependant(const value_type & value)
00379                 {
00380                         removeDependant(find(value));
00381                 }
00386                 std::set< value_type > getDependants(bool all = false) const
00387                 {
00388                         std::set< value_type > retval;
00389                         typename DAG< pointer >::const_iterator selected(std::find(dependants_.begin(), dependants_.end(), getPointer(*selected_)));
00390                         const typename DAG< pointer >::node_type * selected_node(selected.node());
00391                         if (all)
00392                         {
00393                                 typedef Details::NodeVisitor< typename DAG< pointer >::node_type, Details::RetrieveTargets, std::set< pointer > * > Visitor;
00394                                 std::set< pointer > temp;
00395                                 Visitor visitor(Details::RetrieveTargets(), &temp);
00396                                 std::for_each(
00397                                         selected_node->targets_.begin(),
00398                                         selected_node->targets_.end(),
00399                                         visitor);
00400                                 std::copy(
00401                                         boost::indirect_iterator< typename std::set< pointer >::const_iterator >(temp.begin()),
00402                                         boost::indirect_iterator< typename std::set< pointer >::const_iterator >(temp.end()),
00403                                         std::inserter(retval, retval.begin()));
00404                         }
00405                         else
00406                         {
00407                                 typename DAG< pointer >::node_type::targets_type::const_iterator end(selected_node->targets_.end());
00408                                 typename DAG< pointer >::node_type::targets_type::const_iterator where(selected_node->targets_.begin());
00409                                 while (where != end)
00410                                 {
00411                                         retval.insert(*((*where)->value_));
00412                                         ++where;
00413                                 }
00414                         }
00415 
00416                         return retval;
00417                 }
00418 
00419 
00421                 bool depends(const_iterator target, const_iterator source) const
00422                 {
00423                         if (target == end() || source == end())
00424                                 return false;
00425                         else
00426                         { /* such a dependency could exist */ }
00427 
00428                         // target depends on source if target is a dependant of source
00429                         // in which case source should also be a prerequisite of target
00430 #ifndef NDEBUG
00431                         assert(
00432                                 (dependants_.linked(getPointer(source), getPointer(target)) && prerequisites_.linked(getPointer(target), getPointer(source))) ||
00433                                 ((!dependants_.linked(getPointer(source), getPointer(target))) && (!prerequisites_.linked(getPointer(target), getPointer(source)))));
00434 #endif
00435                         return dependants_.linked(getPointer(source), getPointer(target));
00436                 }
00438                 bool depends(const_iterator target, const value_type & source) const
00439                 {
00440                         return depends(target, find(source));
00441                 }
00443                 bool depends(const value_type & target, const_iterator source) const
00444                 {
00445                         return depends(find(target), source);
00446                 }
00448                 bool depends(const value_type & target, const value_type & source) const
00449                 {
00450                         return depends(find(target), find(source));
00451                 }
00452 
00453         private :
00454                 // Neither CopyConstructible nor Assignable
00455                 Depends(const Depends &);
00456                 Depends & operator=(const Depends &);
00457 
00460                 void clearSelection()
00461                 {
00462                         delete selected_;
00463                         selected_ = 0;
00464                 }
00465 
00466                 static pointer getPointer(const_iterator i)
00467                 {
00468                         return const_cast< pointer >(&(*i));
00469                 }
00470 
00471 #if DEPENDS_SUPPORT_SERIALIZATION
00472                 template < typename Archive >
00473                 void serialize( Archive & ar, const unsigned int version )
00474                 {
00475                         ar & boost::serialization::make_nvp("storage_", storage_)
00476                            & boost::serialization::make_nvp("dependants_", dependants_)
00477                            & boost::serialization::make_nvp("prerequisites_", prerequisites_)
00478                            ;
00479                 }
00480 #endif
00481 
00482                 Storage storage_;
00483                 DAG< pointer > dependants_;
00484                 DAG< pointer > prerequisites_;
00489                 const_iterator * selected_;
00490 
00491 #if DEPENDS_SUPPORT_SERIALIZATION
00492                 friend class boost::serialization::access;
00493 #endif
00494         };
00495 }
00496 
00497 #endif

Generated on Sat Aug 11 11:55:55 2007 for Depends by  doxygen 1.5.1