00001 #ifndef TAGCOLL_COLLECTION_H 00002 #define TAGCOLL_COLLECTION_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/Consumer.h> 00027 00028 namespace Tagcoll 00029 { 00030 template<typename T1, typename T2> class PatchList; 00031 00039 template<typename ITEM, typename TAG> 00040 class Collection : public Consumer<ITEM, TAG> 00041 { 00042 protected: 00043 /* 00044 * Implementation note: to avoid problems with classes implementing only 00045 * some of the virtual methods, they are given different names. The common 00046 * 'comsume' methods are just inlined calls to the right virtual functions, 00047 * and are a way of keeping the unoverridden methods from being hidden. 00048 */ 00049 00050 void consumeItemUntagged(const ITEM&) {} 00051 void consumeItemsUntagged(const OpSet<ITEM>&) {} 00052 00059 virtual OpSet<ITEM> getItemsHavingTag(const TAG& tag) const = 0; 00060 00067 virtual OpSet<ITEM> getItemsHavingTags(const OpSet<TAG>& tags) const 00068 { 00069 if (tags.empty()) 00070 return OpSet<ITEM>(); 00071 00072 typename OpSet<TAG>::const_iterator i = tags.begin(); 00073 OpSet<ITEM> res = getItemsHavingTag(*i); 00074 00075 for ( ; i != tags.end(); i++) 00076 res ^= getItemsHavingTag(*i); 00077 00078 return res; 00079 00080 } 00081 00091 virtual OpSet<TAG> getTagsOfItem(const ITEM& item) const = 0; 00092 00102 virtual OpSet<TAG> getTagsOfItems(const OpSet<ITEM>& items) const 00103 { 00104 OpSet<TAG> res; 00105 for (typename OpSet<ITEM>::const_iterator i = items.begin(); 00106 i != items.end(); i++) 00107 res += getTagsOfItem(*i); 00108 return res; 00109 } 00110 00111 public: 00112 virtual ~Collection() {} 00113 00122 virtual bool hasTag(const TAG& tag) const 00123 { 00124 return !getItems(tag).empty(); 00125 } 00126 00130 OpSet<TAG> getTags(const ITEM& item) const { return getTagsOfItem(item); } 00131 00135 OpSet<TAG> getTags(const OpSet<ITEM>& items) const { return getTagsOfItems(items); } 00136 00140 OpSet<ITEM> getItems(const TAG& tag) const { return getItemsHavingTag(tag); } 00141 00145 OpSet<ITEM> getItems(const OpSet<TAG>& tags) const { return getItemsHavingTags(tags); } 00146 00159 virtual void applyChange(const PatchList<ITEM, TAG>& change) = 0; 00160 00164 virtual OpSet<ITEM> getTaggedItems() const = 0; 00165 00169 virtual OpSet<TAG> getAllTags() const = 0; 00170 00174 virtual int getCardinality(const TAG& tag) const 00175 { 00176 return getItemsHavingTag(tag).size(); 00177 } 00178 00192 virtual OpSet<TAG> getCompanionTags(const OpSet<TAG>& tags) const 00193 { 00194 return getTagsOfItems(getItemsHavingTags(tags)) - tags; 00195 } 00196 00228 virtual OpSet<ITEM> getRelatedItems(const OpSet<TAG>& tags, int maxdistance = 1) const 00229 { 00230 OpSet<ITEM> packages; 00231 OpSet<ITEM> res; 00232 00233 // First get a list of packages that have a non-empty intersection with `tags' 00234 for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++) 00235 packages += getItemsHavingTag(*i); 00236 00237 // Then keep only those within the given distance 00238 for (typename OpSet<ITEM>::const_iterator i = packages.begin(); i != packages.end(); i++) 00239 { 00240 int dist = tags.distance(getTagsOfItem(*i)); 00241 if (dist >= 0 && dist <= maxdistance) 00242 res += *i; 00243 } 00244 00245 return res; 00246 } 00247 00251 virtual void output(Consumer<ITEM, TAG>& consumer) const = 0; 00252 00257 virtual void outputHavingTags(const OpSet<TAG>& tags, Consumer<ITEM, TAG>& consumer) const 00258 { 00259 OpSet<ITEM> items = getItemsHavingTags(tags); 00260 for (typename OpSet<ITEM>::const_iterator i = items.begin(); 00261 i != items.end(); i++) 00262 consumer.consume(*i, getTagsOfItem(*i)); 00263 } 00264 }; 00265 00266 }; 00267 00268 // vim:set ts=4 sw=4: 00269 #endif