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 
00029 #include <map>
00030 #include <list>
00031 
00032 namespace Tagcoll
00033 {
00034 
00067 template<class ITEM, class TAG>
00068 class ItemGrouper : public Collection<ITEM, TAG>
00069 {
00070 protected:
00071     typedef typename std::map<OpSet<TAG>, OpSet<ITEM> > groups_t;
00072 
00073     // tagset -> item group
00074     groups_t groups;
00075 
00076     virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
00077     {
00078         groups[tags] += item;
00079     }
00080     virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
00081     {
00082         groups[tags] += items;
00083     }
00084 
00085     virtual OpSet<ITEM> getItemsHavingTag(const TAG& tag) const
00086     {
00087         OpSet<ITEM> res;
00088         for (typename groups_t::const_iterator i = groups.begin();
00089                 i != groups.end(); i++)
00090             if (i->first.contains(tag))
00091                 res += i->second;
00092         return res;
00093     }
00094     virtual OpSet<ITEM> getItemsHavingTags(const OpSet<TAG>& tags) const
00095     {
00096         OpSet<ITEM> res;
00097         for (typename groups_t::const_iterator i = groups.begin();
00098                 i != groups.end(); i++)
00099             if (i->first.contains(tags))
00100                 res += i->second;
00101         return res;
00102     }
00103 
00104     virtual OpSet<TAG> getTagsOfItem(const ITEM& item) const
00105     {
00106         for (typename groups_t::const_iterator i = groups.begin();
00107                 i != groups.end(); i++)
00108             if (i->second.contains(item))
00109                 return i->first;
00110         return OpSet<TAG>();
00111     }
00112     virtual OpSet<TAG> getTagsOfItems(const OpSet<ITEM>& items) const
00113     {
00114         OpSet<TAG> res;
00115         for (typename groups_t::const_iterator i = groups.begin();
00116                 i != groups.end(); i++)
00117         {
00118             OpSet<ITEM> found = i->second ^ items;
00119             if (!found.empty())
00120                 res += i->first;
00121         }
00122         return res;
00123     }
00124 
00125     
00126 public:
00127     virtual ~ItemGrouper() throw () {}
00128 
00129     virtual bool hasItem(const ITEM& item) const
00130     {
00131         for (typename groups_t::const_iterator i = groups.begin();
00132                 i != groups.end(); i++)
00133             if (i->second.contains(item))
00134                 return true;
00135         return false;
00136     }
00137     virtual bool hasTag(const TAG& tag) const
00138     {
00139         for (typename groups_t::const_iterator i = groups.begin();
00140                 i != groups.end(); i++)
00141             if (i->first.contains(tag))
00142                 return true;
00143         return false;
00144     }
00145 
00146     virtual void applyChange(const PatchList<ITEM, TAG>& change)
00147     {
00148         OpSet<ITEM> involvedItems;
00149 
00150         // Find out the items that are involved by the patch
00151         for (typename PatchList<ITEM, TAG>::const_iterator i = change.begin(); i != change.end(); i++)
00152             involvedItems += i->first;
00153 
00154         // Take the involved items temporarily out of the collection, and save
00155         // them together with their patched tagset
00156         std::map< ITEM, OpSet<TAG> > involved;
00157         OpSet<ITEM> extraItems = involvedItems;
00158         std::list< typename groups_t::iterator > toremove;
00159         for (typename groups_t::iterator i = groups.begin();
00160                 i != groups.end(); i++)
00161         {
00162             OpSet<ITEM> found = i->second ^ involvedItems;
00163             extraItems -= found;
00164             if (!found.empty())
00165             {
00166                 i->second -= found;
00167                 for (typename OpSet<ITEM>::const_iterator j = found.begin();
00168                         j != found.end(); j++)
00169                     involved.insert(make_pair(*j, change.patch(*j, i->first)));
00170                 if (i->second.empty())
00171                     toremove.push_back(i);
00172             }
00173         }
00174         for (typename std::list< typename groups_t::iterator >::const_iterator i = toremove.begin();
00175                 i != toremove.end(); i++)
00176             groups.erase(*i);
00177 
00178         // Also add those tags that have been introduced with the patch
00179         for (typename OpSet<ITEM>::const_iterator i = extraItems.begin();
00180                 i != extraItems.end(); i++)
00181         {
00182             typename PatchList<ITEM, TAG>::const_iterator found = change.find(*i);
00183             if (found != change.end())
00184                 involved.insert(make_pair(*i, found->second.getAdded()));
00185         }
00186         
00187         // Reinsert the involved items and their patched tagset
00188         for (typename std::map< ITEM, OpSet<TAG> >::const_iterator i = involved.begin();
00189                 i != involved.end(); i++)
00190             groups[i->second] += i->first;
00191     }
00192 
00193 
00194     virtual OpSet<ITEM> getTaggedItems() const
00195     {
00196         OpSet<ITEM> res;
00197         for (typename groups_t::const_iterator i = groups.begin();
00198                 i != groups.end(); i++)
00199             res += i->second;
00200         return res;
00201     }
00202 
00203     virtual OpSet<TAG> getAllTags() const
00204     {
00205         OpSet<TAG> res;
00206         for (typename groups_t::const_iterator i = groups.begin();
00207                 i != groups.end(); i++)
00208             res += i->first;
00209         return res;
00210     }
00211 
00212     virtual OpSet<TAG> getCompanionTags(const OpSet<TAG>& tags) const
00213     {
00214         OpSet<TAG> res;
00215         for (typename groups_t::const_iterator i = groups.begin();
00216                 i != groups.end(); i++)
00217             if (i->first.contains(tags))
00218                 res += i->first;
00219         return res - tags;
00220     }
00221 
00222     virtual OpSet<ITEM> getRelatedItems(const OpSet<TAG>& tags, int maxdistance = 1) const
00223     {
00224         OpSet<ITEM> packages;
00225 
00226         for (typename groups_t::const_iterator i = groups.begin();
00227                 i != groups.end(); i++)
00228         {
00229             int dist = tags.distance(i->first);
00230             if (dist >= 0 && dist <= maxdistance)
00231                 packages += i->second;
00232         }
00233 
00234         return packages;
00235     }
00236 
00237     virtual void output(Consumer<ITEM, TAG>& consumer) const
00238     {
00239         for (typename groups_t::const_iterator i = groups.begin();
00240                 i != groups.end(); i++)
00241             if (i->first.empty())
00242                 consumer.consume(i->second);
00243             else
00244                 consumer.consume(i->second, i->first);
00245     }
00246 
00251     void outputReversed(Consumer<TAG, ITEM>& consumer) const
00252     {
00253         for (typename groups_t::const_iterator i = groups.begin();
00254                 i != groups.end(); i++)
00255             consumer.consume(i->first, i->second);
00256     }
00257 
00258     virtual void outputHavingTags(const OpSet<TAG>& tags, Consumer<ITEM, TAG>& consumer) const
00259     {
00260         for (typename groups_t::const_iterator i = groups.begin();
00261                 i != groups.end(); i++)
00262             if (i->first.contains(tags))
00263                 consumer.consume(i->second, i->first);
00264     }
00265 
00269     void clear() { groups.clear(); }
00270 };
00271 
00272 };
00273 
00274 // vim:set ts=4 sw=4:
00275 #endif

Generated on Fri Mar 24 22:43:05 2006 for libtagcoll by  doxygen 1.4.6