00001 #ifndef TAGCOLL_READONLY_COLLECTION_H 00002 #define TAGCOLL_READONLY_COLLECTION_H 00003 00008 /* 00009 * Copyright (C) 2003,2004,2005,2006 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 { 00037 template<typename ITEM, typename TAG> 00038 class ReadonlyCollection 00039 { 00040 protected: 00047 virtual OpSet<ITEM> getItemsHavingTag(const TAG& tag) const = 0; 00048 00055 virtual OpSet<ITEM> getItemsHavingTags(const OpSet<TAG>& tags) const 00056 { 00057 if (tags.empty()) 00058 return OpSet<ITEM>(); 00059 00060 typename OpSet<TAG>::const_iterator i = tags.begin(); 00061 OpSet<ITEM> res = getItemsHavingTag(*i); 00062 00063 for ( ; i != tags.end(); i++) 00064 res ^= getItemsHavingTag(*i); 00065 00066 return res; 00067 00068 } 00069 00079 virtual OpSet<TAG> getTagsOfItem(const ITEM& item) const = 0; 00080 00090 virtual OpSet<TAG> getTagsOfItems(const OpSet<ITEM>& items) const 00091 { 00092 OpSet<TAG> res; 00093 for (typename OpSet<ITEM>::const_iterator i = items.begin(); 00094 i != items.end(); i++) 00095 res += getTagsOfItem(*i); 00096 return res; 00097 } 00098 00099 public: 00100 virtual ~ReadonlyCollection() {} 00101 00110 virtual bool hasTag(const TAG& tag) const 00111 { 00112 return !getItems(tag).empty(); 00113 } 00114 00118 OpSet<TAG> getTags(const ITEM& item) const { return getTagsOfItem(item); } 00119 00123 OpSet<TAG> getTags(const OpSet<ITEM>& items) const { return getTagsOfItems(items); } 00124 00128 OpSet<ITEM> getItems(const TAG& tag) const { return getItemsHavingTag(tag); } 00129 00133 OpSet<ITEM> getItems(const OpSet<TAG>& tags) const { return getItemsHavingTags(tags); } 00134 00138 virtual OpSet<ITEM> getTaggedItems() const = 0; 00139 00143 virtual OpSet<TAG> getAllTags() const = 0; 00144 00148 virtual int getCardinality(const TAG& tag) const 00149 { 00150 return getItemsHavingTag(tag).size(); 00151 } 00152 00166 virtual OpSet<TAG> getCompanionTags(const OpSet<TAG>& tags) const 00167 { 00168 return getTagsOfItems(getItemsHavingTags(tags)) - tags; 00169 } 00170 00202 virtual OpSet<ITEM> getRelatedItems(const OpSet<TAG>& tags, int maxdistance = 1) const 00203 { 00204 OpSet<ITEM> packages; 00205 OpSet<ITEM> res; 00206 00207 // First get a list of packages that have a non-empty intersection with `tags' 00208 for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++) 00209 packages += getItemsHavingTag(*i); 00210 00211 // Then keep only those within the given distance 00212 for (typename OpSet<ITEM>::const_iterator i = packages.begin(); i != packages.end(); i++) 00213 { 00214 int dist = tags.distance(getTagsOfItem(*i)); 00215 if (dist >= 0 && dist <= maxdistance) 00216 res += *i; 00217 } 00218 00219 return res; 00220 } 00221 00225 virtual void output(Consumer<ITEM, TAG>& consumer) const = 0; 00226 00231 virtual void outputHavingTags(const OpSet<TAG>& tags, Consumer<ITEM, TAG>& consumer) const 00232 { 00233 OpSet<ITEM> items = getItemsHavingTags(tags); 00234 for (typename OpSet<ITEM>::const_iterator i = items.begin(); 00235 i != items.end(); i++) 00236 consumer.consume(*i, getTagsOfItem(*i)); 00237 } 00238 }; 00239 00240 }; 00241 00242 // vim:set ts=4 sw=4: 00243 #endif