ItemGrouper.h

Go to the documentation of this file.
00001 #ifndef TAGCOLL_ITEM_GROUPER_H
00002 #define TAGCOLL_ITEM_GROUPER_H
00003 
00008 /*
00009  * Copyright (C) 2003,2004,2005  Enrico Zini <enrico@debian.org>
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00024  */
00025 
00026 #include <tagcoll/Collection.h>
00027 #include <tagcoll/OpSet.h>
00028 #include <tagcoll/Patches.h>
00029 
00030 #include <map>
00031 #include <list>
00032 
00033 namespace Tagcoll
00034 {
00035 
00068 template<class ITEM, class TAG>
00069 class ItemGrouper : public Collection<ITEM, TAG>
00070 {
00071 protected:
00072     typedef typename std::map<OpSet<TAG>, OpSet<ITEM> > groups_t;
00073 
00074     // tagset -> item group
00075     groups_t groups;
00076 
00077     virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
00078     {
00079         groups[tags] += item;
00080     }
00081     virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
00082     {
00083         groups[tags] += items;
00084     }
00085 
00086     virtual OpSet<ITEM> getItemsHavingTag(const TAG& tag) const
00087     {
00088         OpSet<ITEM> res;
00089         for (typename groups_t::const_iterator i = groups.begin();
00090                 i != groups.end(); i++)
00091             if (i->first.contains(tag))
00092                 res += i->second;
00093         return res;
00094     }
00095     virtual OpSet<ITEM> getItemsHavingTags(const OpSet<TAG>& tags) const
00096     {
00097         OpSet<ITEM> res;
00098         for (typename groups_t::const_iterator i = groups.begin();
00099                 i != groups.end(); i++)
00100             if (i->first.contains(tags))
00101                 res += i->second;
00102         return res;
00103     }
00104 
00105     virtual OpSet<TAG> getTagsOfItem(const ITEM& item) const
00106     {
00107         for (typename groups_t::const_iterator i = groups.begin();
00108                 i != groups.end(); i++)
00109             if (i->second.contains(item))
00110                 return i->first;
00111         return OpSet<TAG>();
00112     }
00113     virtual OpSet<TAG> getTagsOfItems(const OpSet<ITEM>& items) const
00114     {
00115         OpSet<TAG> res;
00116         for (typename groups_t::const_iterator i = groups.begin();
00117                 i != groups.end(); i++)
00118         {
00119             OpSet<ITEM> found = i->second ^ items;
00120             if (!found.empty())
00121                 res += i->first;
00122         }
00123         return res;
00124     }
00125 
00126     
00127 public:
00128     virtual ~ItemGrouper() throw () {}
00129 
00130     virtual bool hasItem(const ITEM& item) const
00131     {
00132         for (typename groups_t::const_iterator i = groups.begin();
00133                 i != groups.end(); i++)
00134             if (i->second.contains(item))
00135                 return true;
00136         return false;
00137     }
00138     virtual bool hasTag(const TAG& tag) const
00139     {
00140         for (typename groups_t::const_iterator i = groups.begin();
00141                 i != groups.end(); i++)
00142             if (i->first.contains(tag))
00143                 return true;
00144         return false;
00145     }
00146 
00147     virtual void applyChange(const PatchList<ITEM, TAG>& change)
00148     {
00149         OpSet<ITEM> involvedItems;
00150 
00151         // Find out the items that are involved by the patch
00152         for (typename PatchList<ITEM, TAG>::const_iterator i = change.begin(); i != change.end(); i++)
00153             involvedItems += i->first;
00154 
00155         // Take the involved items temporarily out of the collection, and save
00156         // them together with their patched tagset
00157         std::map< ITEM, OpSet<TAG> > involved;
00158         OpSet<ITEM> extraItems = involvedItems;
00159         std::list< typename groups_t::iterator > toremove;
00160         for (typename groups_t::iterator i = groups.begin();
00161                 i != groups.end(); i++)
00162         {
00163             OpSet<ITEM> found = i->second ^ involvedItems;
00164             extraItems -= found;
00165             if (!found.empty())
00166             {
00167                 i->second -= found;
00168                 for (typename OpSet<ITEM>::const_iterator j = found.begin();
00169                         j != found.end(); j++)
00170                     involved.insert(make_pair(*j, change.patch(*j, i->first)));
00171                 if (i->second.empty())
00172                     toremove.push_back(i);
00173             }
00174         }
00175         for (typename std::list< typename groups_t::iterator >::const_iterator i = toremove.begin();
00176                 i != toremove.end(); i++)
00177             groups.erase(*i);
00178 
00179         // Also add those tags that have been introduced with the patch
00180         for (typename OpSet<ITEM>::const_iterator i = extraItems.begin();
00181                 i != extraItems.end(); i++)
00182         {
00183             typename PatchList<ITEM, TAG>::const_iterator found = change.find(*i);
00184             if (found != change.end())
00185                 involved.insert(make_pair(*i, found->second.getAdded()));
00186         }
00187         
00188         // Reinsert the involved items and their patched tagset
00189         for (typename std::map< ITEM, OpSet<TAG> >::const_iterator i = involved.begin();
00190                 i != involved.end(); i++)
00191             groups[i->second] += i->first;
00192     }
00193 
00194 
00195     virtual OpSet<ITEM> getTaggedItems() const
00196     {
00197         OpSet<ITEM> res;
00198         for (typename groups_t::const_iterator i = groups.begin();
00199                 i != groups.end(); i++)
00200             res += i->second;
00201         return res;
00202     }
00203 
00204     virtual OpSet<TAG> getAllTags() const
00205     {
00206         OpSet<TAG> res;
00207         for (typename groups_t::const_iterator i = groups.begin();
00208                 i != groups.end(); i++)
00209             res += i->first;
00210         return res;
00211     }
00212 
00213     virtual OpSet<TAG> getCompanionTags(const OpSet<TAG>& tags) const
00214     {
00215         OpSet<TAG> res;
00216         for (typename groups_t::const_iterator i = groups.begin();
00217                 i != groups.end(); i++)
00218             if (i->first.contains(tags))
00219                 res += i->first;
00220         return res - tags;
00221     }
00222 
00223     virtual OpSet<ITEM> getRelatedItems(const OpSet<TAG>& tags, int maxdistance = 1) const
00224     {
00225         OpSet<ITEM> packages;
00226 
00227         for (typename groups_t::const_iterator i = groups.begin();
00228                 i != groups.end(); i++)
00229         {
00230             int dist = tags.distance(i->first);
00231             if (dist >= 0 && dist <= maxdistance)
00232                 packages += i->second;
00233         }
00234 
00235         return packages;
00236     }
00237 
00238     virtual void output(Consumer<ITEM, TAG>& consumer) const
00239     {
00240         for (typename groups_t::const_iterator i = groups.begin();
00241                 i != groups.end(); i++)
00242             if (i->first.empty())
00243                 consumer.consume(i->second);
00244             else
00245                 consumer.consume(i->second, i->first);
00246     }
00247 
00252     void outputReversed(Consumer<TAG, ITEM>& consumer) const
00253     {
00254         for (typename groups_t::const_iterator i = groups.begin();
00255                 i != groups.end(); i++)
00256             consumer.consume(i->first, i->second);
00257     }
00258 
00259     virtual void outputHavingTags(const OpSet<TAG>& tags, Consumer<ITEM, TAG>& consumer) const
00260     {
00261         for (typename groups_t::const_iterator i = groups.begin();
00262                 i != groups.end(); i++)
00263             if (i->first.contains(tags))
00264                 consumer.consume(i->second, i->first);
00265     }
00266 
00270     void clear() { groups.clear(); }
00271 };
00272 
00273 };
00274 
00275 // vim:set ts=4 sw=4:
00276 #endif

Generated on Sat Jan 17 03:28:50 2009 for libtagcoll by  doxygen 1.5.1