1 : /*
2 : * Wrap a Collection, preserving modifications as patches
3 : *
4 : * Copyright (C) 2005,2006 Enrico Zini <enrico@debian.org>
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 2 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 : */
20 :
21 : #ifndef TAGCOLL_COLL_PATCHED_TCC
22 : #define TAGCOLL_COLL_PATCHED_TCC
23 :
24 : #include <tagcoll/coll/patched.h>
25 : #include <tagcoll/utils/set.h>
26 :
27 : #include <wibble/operators.h>
28 :
29 : using namespace std;
30 : using namespace wibble::operators;
31 :
32 : namespace tagcoll {
33 : namespace coll {
34 :
35 : template<typename ROCOLL> template<typename ITEMS, typename TAGS>
36 : void Patched<ROCOLL>::insert(const ITEMS& items, const TAGS& tags)
37 : {
38 : Patches changes;
39 : for (typename ITEMS::const_iterator i = items.begin();
40 : i != items.end(); ++i)
41 : changes.addPatch(Patch(*i, tags, TagSet()));
42 : addChanges(changes);
43 : }
44 :
45 :
46 : template<typename ROCOLL>
47 : void Patched<ROCOLL>::clear()
48 : {
49 : // Remove all patches
50 : m_changes.clear();
51 : m_rchanges.clear();
52 :
53 : // Add all tagsets of the underlying collection as removed tags in the patch
54 : for (typename ROCOLL::const_iterator i = coll.begin();
55 : i != coll.end(); ++i)
56 : {
57 : m_changes.addPatch(Patch(i->first, std::set<Tag>(), i->second));
58 :
59 : for (typename TagSet::const_iterator j = i->second.begin();
60 : j != i->second.end(); ++j)
61 : m_rchanges.addPatch(Patch(*j, wibble::Empty<Tag>(), wibble::singleton(i->first)));
62 : }
63 : }
64 :
65 : template<typename ROCOLL>
66 : void Patched<ROCOLL>::setChanges(const Patches& changes)
67 : {
68 0 : this->m_changes.clear();
69 0 : this->m_rchanges.clear();
70 :
71 0 : addChanges(changes);
72 0 : }
73 :
74 : template<typename ROCOLL>
75 : void Patched<ROCOLL>::addChanges(const Patches& changes)
76 : {
77 : // Simplify the patch against the contents of `coll' before adding it.
78 4 : for (typename Patches::const_iterator i = changes.begin(); i != changes.end(); ++i)
79 : // Consider only valid items
80 2 : if (i->first != Item())
81 : {
82 : // Merge with existing patches
83 2 : this->m_changes.addPatch(i->second);
84 : // Simplify the result
85 2 : this->m_changes.removeRedundant(i->first, coll.getTagsOfItem(i->first));
86 : }
87 :
88 2 : RPatches rchanges;
89 2 : rchanges.addPatchInverted(changes);
90 4 : for (typename RPatches::const_iterator i = rchanges.begin(); i != rchanges.end(); ++i)
91 : // Consider only valid tags
92 2 : if (i->first != Tag())
93 : {
94 : // Merge with existing patches
95 2 : this->m_rchanges.addPatch(i->second);
96 : // Simplify the result
97 4 : this->m_rchanges.removeRedundant(i->first, coll.getItemsHavingTag(i->first));
98 : }
99 2 : }
100 :
101 : template<typename ROCOLL>
102 : bool Patched<ROCOLL>::hasTag(const Tag& tag) const
103 : {
104 : typename RPatches::const_iterator i = m_rchanges.find(tag);
105 : if (i == m_rchanges.end())
106 : return coll.hasTag(tag);
107 : if (! i->second.added.empty())
108 : return true;
109 : return !this->getItemsHavingTag(tag).empty();
110 : }
111 :
112 : template<typename ROCOLL>
113 : typename coll_traits<ROCOLL>::itemset_type Patched<ROCOLL>::getTaggedItems() const
114 : {
115 : ItemSet res(coll.getTaggedItems());
116 : for (typename Patches::const_iterator i = m_changes.begin();
117 : i != m_changes.end(); ++i)
118 : if (!i->second.added.empty())
119 : // Add packages for which tags are added
120 : res |= i->first;
121 : else if (getTagsOfItem(i->first).empty())
122 : // Remove the packages to which the patch removes all tags
123 : res -= i->first;
124 : return res;
125 : }
126 :
127 : template<typename ROCOLL>
128 : typename coll_traits<ROCOLL>::tagset_type Patched<ROCOLL>::getAllTags() const
129 : {
130 1 : TagSet res(coll.getAllTags());
131 1 : for (typename RPatches::const_iterator i = m_rchanges.begin();
132 : i != m_rchanges.end(); ++i)
133 0 : if (!i->second.added.empty())
134 : // Add tags for which packages are added
135 0 : res |= i->first;
136 0 : else if (coll.getCardinality(i->first) - i->second.removed.size() <= 0)
137 : // Remove the tags to which the patch removes all items
138 0 : res -= i->first;
139 0 : return res;
140 : }
141 :
142 : #if 0
143 : template<typename ITEM, typename TAG, typename OUT>
144 : class UnpatchedOnly : public wibble::mixin::OutputIterator< UnpatchedOnly<ITEM, TAG, OUT> >
145 : {
146 : protected:
147 : OUT out;
148 : const PatchList<ITEM, TAG>& changes;
149 :
150 : public:
151 : UnpatchedOnly(const PatchList<ITEM, TAG>& changes, const OUT& out) : out(out), changes(changes) {}
152 :
153 : UnpatchedOnly<ITEM, TAG, OUT>& operator++() { return *this; }
154 :
155 : template<typename Items, typename Tags>
156 : UnpatchedOnly<ITEM, TAG, OUT>& operator=(const std::pair<Items, Tags>& data)
157 : {
158 : for (typename Items::const_iterator i = data.first.begin();
159 : i != data.first.end(); ++i)
160 : if (changes.find(*i) == changes.end())
161 : {
162 : *out = data;
163 : ++out;
164 : }
165 : return *this;
166 : }
167 : };
168 :
169 : template<typename ITEM, typename TAG, typename OUT>
170 : UnpatchedOnly<ITEM, TAG, OUT> unpatchedOnly(const PatchList<ITEM, TAG>& changes, const OUT& out)
171 : {
172 : return UnpatchedOnly<ITEM, TAG, OUT>(changes, out);
173 : }
174 :
175 : template<class ITEM, class TAG>
176 : void Patched<ITEM, TAG>::output(Consumer<ITEM, TAG>& cons) const
177 : {
178 : // First, only pass the unpatched items
179 : coll.outputToIterator(unpatchedOnly(changes, consumer(cons)));
180 :
181 : // Then output the items in the patch
182 : for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
183 : i != changes.end(); i++)
184 : cons.consume(i->first,
185 : changes.patch(i->first, coll.getTags(i->first)));
186 : }
187 : #endif
188 :
189 : template<typename ROCOLL>
190 : unsigned int Patched<ROCOLL>::getCardinality(const Tag& tag) const
191 : {
192 : typename RPatches::const_iterator i = m_rchanges.find(tag);
193 : if (i == m_rchanges.end())
194 : return coll.getCardinality(tag);
195 : else
196 : return coll.getCardinality(tag) + i->second.added.size() - i->second.removed.size();
197 : }
198 :
199 : }
200 : }
201 :
202 : #include <tagcoll/coll/base.tcc>
203 : #include <tagcoll/patch.tcc>
204 :
205 : #endif
206 :
207 : // vim:set ts=4 sw=4:
|