1 : #ifndef TAGCOLL_PATCHES_H
2 : #define TAGCOLL_PATCHES_H
3 :
4 : /** \file
5 : * Classes handling tag patches
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/operators.h>
27 : #include <wibble/mixin.h>
28 : #include <map>
29 : #include <string>
30 :
31 : namespace tagcoll
32 : {
33 :
34 : /**
35 : * Patch for the tagset of a specific item
36 : */
37 : template <typename ITEM, typename TAG>
38 : struct Patch
39 : {
40 : ITEM item;
41 : std::set<TAG> added;
42 : std::set<TAG> removed;
43 :
44 55 : Patch(const Patch<ITEM, TAG>& p) : item(p.item), added(p.added), removed(p.removed) {}
45 5 : Patch(const ITEM& item) : item(item) {}
46 2 : Patch(const ITEM& item, const std::set<TAG>& added, const std::set<TAG>& removed);
47 : template<typename CONTA, typename CONTB>
48 2 : Patch(const ITEM& item, const CONTA& added, const CONTB& removed);
49 66 : ~Patch() {}
50 :
51 5 : void add(const TAG& tag)
52 : {
53 : using namespace wibble::operators;
54 5 : added |= tag; removed -= tag;
55 5 : }
56 2 : void add(const std::set<TAG>& tags)
57 : {
58 : using namespace wibble::operators;
59 2 : added |= tags; removed -= tags;
60 2 : }
61 2 : void remove(const TAG& tag)
62 : {
63 : using namespace wibble::operators;
64 2 : removed |= tag; added -= tag;
65 2 : }
66 2 : void remove(const std::set<TAG>& tags)
67 : {
68 : using namespace wibble::operators;
69 2 : removed |= tags; added -= tags;
70 2 : }
71 :
72 : Patch<ITEM, TAG> getReverse() const
73 : {
74 : return Patch<ITEM, TAG>(item, removed, added);
75 : }
76 :
77 2 : void mergeWith(const Patch<ITEM, TAG>& patch)
78 : {
79 2 : add(patch.added);
80 2 : remove(patch.removed);
81 2 : }
82 :
83 1 : std::set<TAG> apply(const std::set<TAG>& ts) const
84 : {
85 : using namespace wibble::operators;
86 1 : return (ts | added) - removed;
87 : }
88 :
89 : template<typename TAGS>
90 : std::set<TAG> apply(const TAGS& tags) const
91 : {
92 : using namespace wibble::operators;
93 : std::set<TAG> ts;
94 : for (typename TAGS::const_iterator i = tags.begin();
95 : i != tags.end(); ++i)
96 : ts.insert(*i);
97 : return (ts | added) - removed;
98 : }
99 :
100 4 : void removeRedundant(const std::set<TAG> ts)
101 : {
102 : using namespace wibble::operators;
103 : // Don't add what already exists
104 4 : added -= ts;
105 : // Don't remove what does not exist
106 4 : removed -= (removed - ts);
107 4 : }
108 :
109 : bool operator==(const Patch<ITEM, TAG>& p) const
110 : {
111 : return p.item == item && p.added == added && p.removed == removed;
112 : }
113 : bool operator!=(const Patch<ITEM, TAG>& p) const
114 : {
115 : return p.item != item || p.added != added || p.removed != removed;
116 : }
117 : };
118 :
119 : /**
120 : * List of patches that can be applied to a TaggedCollection
121 : */
122 : template <class ITEM, class TAG>
123 : class PatchList : public std::map<ITEM, Patch<ITEM, TAG> >
124 36 : {
125 : public:
126 32 : PatchList() {}
127 3 : PatchList(const PatchList& pl) : std::map<ITEM, Patch<ITEM, TAG> >(pl) {}
128 :
129 : typedef typename std::map<ITEM, Patch<ITEM, TAG> >::const_iterator const_iterator;
130 : typedef typename std::map<ITEM, Patch<ITEM, TAG> >::iterator iterator;
131 :
132 : /**
133 : * Add to this patchlist the patches needed to transform `im1' in `im2'
134 : */
135 : template<typename COLL1, typename COLL2>
136 : void addPatch(const COLL1& im1, const COLL2& im2);
137 :
138 : /**
139 : * Add `patch' to this PatchList
140 : */
141 15 : void addPatch(const Patch<ITEM, TAG>& patch);
142 :
143 : /**
144 : * Add `patches' to this PatchList
145 : */
146 : void addPatch(const PatchList<ITEM, TAG>& patches);
147 :
148 : /**
149 : * Add 'patch' to this PatchList, as tag: +/- package rather than package
150 : * +/- tag
151 : */
152 2 : void addPatchInverted(const Patch<TAG, ITEM>& patch);
153 :
154 : /**
155 : * Add 'patches' to this PatchList, as tag: +/- package rather than package
156 : * +/- tag
157 : */
158 2 : void addPatchInverted(const PatchList<TAG, ITEM>& patches);
159 :
160 : /**
161 : * If the PatchList contains the give item, invoke
162 : * Patch::removeRedundant(tags) on its patch
163 : */
164 4 : void removeRedundant(const ITEM& item, const std::set<TAG>& tags);
165 :
166 : /**
167 : * Patch a tagged item
168 : *
169 : * @return
170 : * The new (patched) set of tags
171 : */
172 14 : std::set<TAG> patch(const ITEM& item, const std::set<TAG>& tagset) const;
173 :
174 : // Output the patch list to a TagcollConsumer
175 : template<typename OUT>
176 3 : void output(OUT out) const;
177 :
178 : PatchList<ITEM, TAG> getReverse() const;
179 : };
180 :
181 : template<typename ITEM, typename TAG>
182 : class Inserter : public wibble::mixin::OutputIterator< Inserter<ITEM, TAG> >
183 : {
184 : PatchList<ITEM, TAG>& patches;
185 : public:
186 3 : Inserter(PatchList<ITEM, TAG>& patches) : patches(patches) {}
187 :
188 3 : Inserter<ITEM, TAG>& operator=(const Patch<ITEM, TAG>& patch)
189 : {
190 3 : patches.addPatch(patch);
191 3 : return *this;
192 : }
193 : };
194 :
195 : template<typename ITEM, typename TAG>
196 3 : Inserter<ITEM, TAG> inserter(PatchList<ITEM, TAG>& patches)
197 : {
198 3 : return Inserter<ITEM, TAG>(patches);
199 : }
200 :
201 : }
202 :
203 : // vim:set ts=4 sw=4:
204 : #endif
|