00001 #ifndef TAGCOLL_ITEM_GROUPER_H
00002 #define TAGCOLL_ITEM_GROUPER_H
00003
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00152 for (typename PatchList<ITEM, TAG>::const_iterator i = change.begin(); i != change.end(); i++)
00153 involvedItems += i->first;
00154
00155
00156
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
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
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
00276 #endif