1 : #ifndef TAGCOLL_COLL_PATCHED_H
2 : #define TAGCOLL_COLL_PATCHED_H
3 :
4 : /** \file
5 : * Wrap a Collection, preserving modifications as patches
6 : */
7 :
8 : /*
9 : * Copyright (C) 2005,2006 Enrico Zini <enrico@debian.org>
10 : *
11 : * This program is free software; you can redistribute it and/or modify
12 : * it under the terms of the GNU General Public License as published by
13 : * the Free Software Foundation; either version 2 of the License, or
14 : * (at your option) any later version.
15 : *
16 : * This program 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
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 : */
25 :
26 : #include <tagcoll/coll/base.h>
27 : #include <tagcoll/patch.h>
28 :
29 : namespace tagcoll {
30 : template<typename T1, typename T2> class PatchList;
31 :
32 : namespace coll {
33 : template<typename ROCOLL>
34 : class Patched;
35 :
36 : template<typename ROCOLL>
37 : struct coll_traits< Patched<ROCOLL> >
38 : {
39 : typedef typename coll_traits<ROCOLL>::item_type item_type;
40 : typedef typename coll_traits<ROCOLL>::tag_type tag_type;
41 : typedef typename coll_traits<ROCOLL>::tagset_type tagset_type;
42 : typedef typename coll_traits<ROCOLL>::itemset_type itemset_type;
43 : };
44 :
45 : /**
46 : * Wraps a collection by intercepting all changes to it and preserving them as
47 : * a PatchList.
48 : */
49 : template<typename ROCOLL>
50 : class Patched : public coll::Collection< Patched<ROCOLL> >
51 10 : {
52 : public:
53 : typedef tagcoll::Patch<
54 : typename coll_traits<ROCOLL>::item_type,
55 : typename coll_traits<ROCOLL>::tag_type> Patch;
56 : typedef tagcoll::PatchList<
57 : typename coll_traits<ROCOLL>::item_type,
58 : typename coll_traits<ROCOLL>::tag_type> Patches;
59 : typedef tagcoll::Patch<
60 : typename coll_traits<ROCOLL>::tag_type,
61 : typename coll_traits<ROCOLL>::item_type> RPatch;
62 : typedef tagcoll::PatchList<
63 : typename coll_traits<ROCOLL>::tag_type,
64 : typename coll_traits<ROCOLL>::item_type> RPatches;
65 :
66 : protected:
67 : typedef typename coll_traits<ROCOLL>::item_type Item;
68 : typedef typename coll_traits<ROCOLL>::tag_type Tag;
69 : typedef typename coll_traits<ROCOLL>::itemset_type ItemSet;
70 : typedef typename coll_traits<ROCOLL>::tagset_type TagSet;
71 :
72 : const ROCOLL& coll;
73 : Patches m_changes;
74 : RPatches m_rchanges;
75 :
76 : #if 0
77 : virtual void consumeItem(const ITEM& item, const std::set<TAG>& tags);
78 :
79 : virtual std::set<ITEM> getItemsHavingTag(const TAG& tag) const;
80 : virtual std::set<TAG> getTagsOfItem(const ITEM& item) const;
81 : #endif
82 :
83 : public:
84 : typedef std::pair<Item, TagSet> value_type;
85 :
86 : class const_iterator
87 : {
88 : const Patched<ROCOLL>& coll;
89 : typename ROCOLL::const_iterator ci;
90 : typename Patches::const_iterator pi;
91 : mutable typename Patched<ROCOLL>::value_type* cached_val;
92 :
93 : protected:
94 : const_iterator(const Patched<ROCOLL>& coll,
95 : const typename ROCOLL::const_iterator& ci,
96 84592 : const typename Patches::const_iterator& pi)
97 84592 : : coll(coll), ci(ci), pi(pi), cached_val(0) {}
98 :
99 : public:
100 148035 : ~const_iterator()
101 : {
102 148035 : if (cached_val)
103 0 : delete cached_val;
104 148035 : }
105 84580 : const typename Patched<ROCOLL>::value_type operator*() const
106 : {
107 84580 : if (cached_val)
108 0 : return *cached_val;
109 :
110 84580 : if (ci == coll.coll.end() && pi == coll.m_changes.end())
111 0 : return *(typename Patched<ROCOLL>::value_type*)0;
112 84580 : else if (pi == coll.m_changes.end())
113 84580 : return *ci;
114 0 : else if (ci == coll.coll.end())
115 0 : return make_pair(pi->first, pi->second.added);
116 0 : else if (ci->first < pi->first)
117 0 : return *ci;
118 0 : else if (ci->first > pi->first)
119 0 : return make_pair(pi->first, pi->second.added);
120 : else
121 0 : return make_pair(ci->first, pi->second.apply(ci->second));
122 : }
123 211450 : const typename Patched<ROCOLL>::value_type* operator->() const
124 : {
125 211450 : if (cached_val)
126 126870 : return cached_val;
127 84580 : return cached_val = new typename Patched<ROCOLL>::value_type(*(*this));
128 : }
129 84580 : const_iterator& operator++()
130 : {
131 84580 : if (ci == coll.coll.end() && pi == coll.m_changes.end())
132 : ;
133 84580 : else if (pi == coll.m_changes.end())
134 84580 : ++ci;
135 0 : else if (ci == coll.coll.end())
136 0 : ++pi;
137 0 : else if (ci->first < pi->first)
138 0 : ++ci;
139 0 : else if (ci->first > pi->first)
140 0 : ++pi;
141 : else
142 : {
143 0 : ++ci;
144 0 : ++pi;
145 : }
146 84580 : if (cached_val)
147 : {
148 84580 : delete cached_val;
149 84580 : cached_val = 0;
150 : }
151 84580 : return *this;
152 : }
153 1 : bool operator==(const const_iterator& iter) const
154 : {
155 1 : return ci == iter.ci && pi == iter.pi;
156 : }
157 84585 : bool operator!=(const const_iterator& iter) const
158 : {
159 84585 : return ci != iter.ci || pi != iter.pi;
160 : }
161 :
162 : friend class Patched<ROCOLL>;
163 : };
164 6 : const_iterator begin() const { return const_iterator(*this, coll.begin(), m_changes.begin()); }
165 84586 : const_iterator end() const { return const_iterator(*this, coll.end(), m_changes.end()); }
166 :
167 10 : Patched(const ROCOLL& coll) : coll(coll) {}
168 :
169 : template<typename ITEMS, typename TAGS>
170 : void insert(const ITEMS& items, const TAGS& tags);
171 :
172 : template<typename ITEMS>
173 : void insert(const ITEMS& items, const wibble::Empty<Tag>& tags)
174 : {
175 : // Nothing to do in this case
176 : }
177 :
178 : /**
179 : * Removes all items from the collection
180 : */
181 : void clear();
182 :
183 : /**
184 : * Get the changes that have been applied to this collection
185 : */
186 4 : const Patches& changes() const { return m_changes; }
187 :
188 : /**
189 : * Throw away all changes previously applied to this collection
190 : */
191 : void resetChanges() { m_changes.clear(); m_rchanges.clear(); }
192 :
193 : /**
194 : * Set the changes list to a specific patch list
195 : */
196 0 : void setChanges(const Patches& changes);
197 :
198 : /**
199 : * Add a specific patch list to the changes list
200 : */
201 2 : void addChanges(const Patches& changes);
202 :
203 : bool hasTag(const Tag& tag) const;
204 :
205 5 : TagSet getTagsOfItem(const Item& item) const
206 : {
207 5 : return m_changes.patch(item, coll.getTagsOfItem(item));
208 : }
209 9 : ItemSet getItemsHavingTag(const typename coll_traits<ROCOLL>::tag_type& tag) const
210 : {
211 9 : return m_rchanges.patch(tag, coll.getItemsHavingTag(tag));
212 : }
213 :
214 : ItemSet getTaggedItems() const;
215 1 : TagSet getAllTags() const;
216 :
217 : unsigned int tagCount() const { return getAllTags().size(); }
218 :
219 : unsigned int getCardinality(const Tag& tag) const;
220 :
221 2 : void applyChange(const Patches& change) { this->addChanges(change); }
222 :
223 : #if 0
224 : template<typename OUT>
225 : void output(OUT out) const
226 : {
227 : for (const_iterator i = begin(); i != end(); ++i)
228 : {
229 : *out = *i;
230 : ++out;
231 : }
232 : }
233 : #endif
234 : };
235 :
236 : }
237 : }
238 :
239 : // vim:set ts=4 sw=4:
240 : #endif
|