1 : #ifndef TAGCOLL_COLL_BASE_H
2 : #define TAGCOLL_COLL_BASE_H
3 :
4 : /** \file
5 : * Base mixins for tagged collections
6 : */
7 :
8 : /*
9 : * Copyright (C) 2003,2004,2005,2006 Enrico Zini <enrico@debian.org>
10 : *
11 : * This library is free software; you can redistribute it and/or
12 : * modify it under the terms of the GNU Lesser General Public
13 : * License as published by the Free Software Foundation; either
14 : * version 2.1 of the License, or (at your option) any later version.
15 : *
16 : * This library is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 : * Lesser General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU Lesser General Public
22 : * License along with this library; if not, write to the Free Software
23 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 : */
25 :
26 : #include <wibble/mixin.h>
27 : #include <vector>
28 :
29 : namespace std {
30 : template<typename A, typename B> class pair;
31 : }
32 :
33 : namespace tagcoll {
34 : namespace coll {
35 :
36 : template<typename T>
37 : class coll_traits;
38 :
39 : /**
40 : * Interface for all collections of tagged items.
41 : *
42 : * \note The point of a collection is to track the tags attached to items, and
43 : * not to store the items themselves. This means that collections are not
44 : * required to keep track of items with no tags.
45 : */
46 : template<typename Self>
47 : class ReadonlyCollection
48 37 : {
49 84611 : const Self& self() const { return *static_cast<const Self*>(this); }
50 :
51 : class CardinalityOrder
52 : {
53 : const Self& coll;
54 : public:
55 : CardinalityOrder(const Self& coll) : coll(coll) {}
56 : bool operator()(const typename coll_traits<Self>::tag_type& t1, const typename coll_traits<Self>::tag_type& t2)
57 : {
58 : // Returns true if t1 precedes t2, and false otherwise
59 : return coll.getCardinality(t1) < coll.getCardinality(t2);
60 : }
61 : };
62 :
63 : class DiscriminanceOrder
64 : {
65 : const Self& coll;
66 : public:
67 : DiscriminanceOrder(const Self& coll) : coll(coll) {}
68 : bool operator()(const typename coll_traits<Self>::tag_type& t1, const typename coll_traits<Self>::tag_type& t2)
69 : {
70 : // Returns true if t1 precedes t2, and false otherwise
71 : return coll.getDiscriminance(t1) < coll.getDiscriminance(t2);
72 : }
73 : };
74 :
75 : template<typename COLL>
76 : class RelevanceOrder
77 : {
78 : const COLL& first;
79 : const Self& second;
80 : public:
81 : RelevanceOrder(const COLL& first, const Self& second)
82 : : first(first), second(second) {}
83 : bool operator()(const typename coll_traits<Self>::tag_type& t1, const typename coll_traits<Self>::tag_type& t2);
84 : };
85 :
86 : /**
87 : * Get the items which are tagged with at least the tag `tag'
88 : *
89 : * \return
90 : * The items found, or an empty set if no items have that tag
91 : */
92 : //virtual std::set<ITEM> getItemsHavingTag(const TAG& tag) const = 0;
93 :
94 : /**
95 : * Get the tags attached to an item.
96 : *
97 : * \param item
98 : * The item to query
99 : * \return
100 : * The set of tags, or an empty set if the item has no tags or it does
101 : * not exist.
102 : */
103 : //virtual std::set<TAG> getTagsOfItem(const ITEM& item) const = 0;
104 :
105 : public:
106 : /**
107 : * Check if the collection contains a tag
108 : *
109 : * \param tag
110 : * The tag to look for
111 : * \return
112 : * true if the collection contains tag, false otherwise
113 : */
114 : bool hasTag(const typename coll_traits<Self>::tag_type& tag) const;
115 :
116 : /**
117 : * Get the tags of item `item'. Return an empty set if `item' does not exist
118 : */
119 : //std::set<Self::tag_type> getTags(const typename Self::item_type& item) const = 0;
120 :
121 : /**
122 : * Get all the tags attached to the items in a set.
123 : *
124 : * \param items
125 : * The items to query
126 : * \return
127 : * The set of tags, or an empty set if the items have no tags or do not
128 : * exist.
129 : */
130 : template<typename ITEMS>
131 : typename coll_traits<Self>::tagset_type getTagsOfItems(const ITEMS& items) const;
132 :
133 : /**
134 : * Get the items with tag `tag'. Return an empty set if `tag' does not exist
135 : */
136 : //std::set<typename Self::item_type> getItems(const TAG& tag) const { return getItemsHavingTag(tag); }
137 :
138 : /**
139 : * Get the items which are tagged with at least the tags `tags'
140 : *
141 : * \return
142 : * The items found, or an empty set if no items have that tag
143 : */
144 : template<typename TAGS>
145 2 : typename coll_traits<Self>::itemset_type getItemsHavingTags(const TAGS& tags) const;
146 :
147 : /**
148 : * Get the set of all the items that have tags according to this collection
149 : */
150 : //virtual std::set<Self::item_type> getTaggedItems() const = 0;
151 :
152 : /**
153 : * Get the set of all the tags in this collection
154 : */
155 : //virtual std::set<Self::tag_type> getAllTags() const = 0;
156 :
157 : /**
158 : * Get all the tags in the collectin, as a vector
159 : */
160 : std::vector<typename coll_traits<Self>::tag_type> getAllTagsAsVector() const;
161 :
162 : /**
163 : * Get the cardinality of tag `tag' (that is, the number of items who have it)
164 : */
165 : unsigned int getCardinality(const typename coll_traits<Self>::tag_type& tag) const;
166 :
167 : /**
168 : * Return the discriminance value for this tag, that is, the minimum number
169 : * of packages that would be eliminated by selecting only those tagged with
170 : * this tag or only those not tagged with this tag.
171 : */
172 : unsigned int getDiscriminance(const typename coll_traits<Self>::tag_type& tag) const
173 : {
174 : return self().getCardinality(tag) < self().tagCount() - self().getCardinality(tag) ?
175 : self().getCardinality(tag) :
176 : self().tagCount() - self().getCardinality(tag);
177 : }
178 :
179 : /**
180 : * Get the set of all tags in this collection that appear in tagsets
181 : * containing `tags'
182 : *
183 : * Example:
184 : * \code
185 : * void refineSelection(const std::set<Tag>& selection)
186 : * {
187 : * std::set<Tag> extraTags = collection.getCompanionTags(selection);
188 : * tagMenu.setAvailableOptions(extraTags);
189 : * }
190 : * \endcode
191 : */
192 : template<typename TAGS>
193 : typename coll_traits<Self>::tagset_type getCompanionTags(const TAGS& tags) const;
194 :
195 : /**
196 : * Get the related items at the given maximum distance
197 : *
198 : * Examples:
199 : * \code
200 : * // Get the items related to a given one, at the given distance
201 : * std::set<Item> getRelated(const Item& item, int distance)
202 : * {
203 : * std::set<Item> res = collection.getRelatedItems(collection.getTags(item), distance);
204 : * return res - item;
205 : * }
206 : *
207 : * // Get the items related to the given ones, at the given distance
208 : * std::set<Item> getRelated(const std::set<Item>& items, int distance)
209 : * {
210 : * std::set<Item> res = collection.getRelatedItems(collection.getTags(items), distance);
211 : * return res - items;
212 : * }
213 : *
214 : * // Get the related items, increasing the distance until it finds at
215 : * // least 'minimum' items
216 : * std::set<Item> getRelated(const Item& item, int minimum)
217 : * {
218 : * std::set<Tag> tags = collection.getTags(item);
219 : * std::set<Item> res;
220 : * for (int i = 0; i < tags.size() && res.size() < minimum; i++)
221 : * res += collection.getRelatedItems(tags, i);
222 : * return res - item;
223 : * }
224 : * \endcode
225 : */
226 : template<typename TAGS>
227 : typename coll_traits<Self>::itemset_type getRelatedItems(const TAGS& tags, int maxdistance = 1) const;
228 :
229 : /**
230 : * Output all the contents of the collection to an output iterator
231 : */
232 : template<typename OUT>
233 5 : void output(OUT out) const;
234 :
235 : /**
236 : * Send to a consumer all the items which are tagged with at least the
237 : * given tags
238 : */
239 : template<typename TAGS, typename OUT>
240 : void outputHavingTags(const TAGS& tags, OUT out) const;
241 :
242 : /**
243 : * Get a vector containing all tags in this collection, sorted by
244 : * increasing cardinality
245 : */
246 : std::vector<typename coll_traits<Self>::tag_type> tagsInCardinalityOrder() const;
247 :
248 : /**
249 : * Get a vector containing all tags in this collection, sorted by
250 : * increasing discriminance value (@see getDiscriminance)
251 : */
252 : std::vector<typename coll_traits<Self>::tag_type> tagsInDiscriminanceOrder() const;
253 :
254 : /**
255 : * Get a vector containing all tags in this collection, sorted by
256 : * increasing relevance to the filtering applied between coll and this
257 : * collection
258 : */
259 : template<typename COLL>
260 : std::vector<typename coll_traits<Self>::tag_type> tagsInRelevanceOrder(const COLL& coll) const;
261 : };
262 :
263 :
264 : /**
265 : * Interface for all collections of tagged items.
266 : *
267 : * \note The point of a collection is to track the tags attached to items, and
268 : * not to store the items themselves. This means that collections are not
269 : * required to keep track of items with no tags.
270 : */
271 : template<typename Self>
272 : class Collection : public ReadonlyCollection<Self>
273 27 : {
274 : //protected:
275 : /*
276 : * Implementation note: to avoid problems with classes implementing only
277 : * some of the virtual methods, they are given different names. The common
278 : * 'comsume' methods are just inlined calls to the right virtual functions,
279 : * and are a way of keeping the unoverridden methods from being hidden.
280 : */
281 :
282 : //void consumeItemUntagged(const ITEM&) {}
283 : //void consumeItemsUntagged(const std::set<ITEM>&) {}
284 :
285 : public:
286 : //virtual ~Collection() {}
287 :
288 : /**
289 : * Apply a patch to the collection
290 : *
291 : * Example:
292 : * \code
293 : * void perform(const PatchList<ITEM, TAG>& change)
294 : * {
295 : * collection.applyChange(change);
296 : * undo.push_back(change.getReverse());
297 : * }
298 : * \endcode
299 : */
300 : // void applyChange(
301 : // const PatchList<
302 : // typename coll_traits<Self>::item_type,
303 : // typename coll_traits<Self>::tag_type>& change);
304 : };
305 :
306 :
307 : template<typename COLL>
308 : class Inserter : public wibble::mixin::OutputIterator< Inserter<COLL> >
309 : {
310 : COLL& coll;
311 :
312 : public:
313 10 : Inserter(COLL& coll) : coll(coll) {}
314 :
315 : template<typename Items, typename Tags>
316 63426 : Inserter<COLL>& operator=(const std::pair<Items, Tags>& data)
317 : {
318 63426 : coll.insert(data.first, data.second);
319 63426 : return *this;
320 : }
321 : };
322 :
323 : template<typename COLL>
324 10 : Inserter<COLL> inserter(COLL& target)
325 : {
326 10 : return Inserter<COLL>(target);
327 : }
328 :
329 : }
330 : }
331 :
332 : // vim:set ts=4 sw=4:
333 : #endif
|