libdballe 9.13
smallset.h
1#ifndef DBALLE_CORE_SMALLSET_H
2#define DBALLE_CORE_SMALLSET_H
3
4#include <algorithm>
5#include <vector>
6
7namespace dballe {
8namespace core {
9
10template <typename T> inline const T& smallset_default_get_value(const T& val)
11{
12 return val;
13}
14
18template <typename Item, typename Value = Item,
19 const Value& (*get_value)(const Item&) = smallset_default_get_value>
21{
22 mutable std::vector<Item> items;
23 mutable size_t dirty = 0;
24
25 typedef typename std::vector<Item>::const_iterator const_iterator;
26 typedef typename std::vector<Item>::iterator iterator;
27 typedef typename std::vector<Item>::const_reverse_iterator
28 const_reverse_iterator;
29 typedef typename std::vector<Item>::reverse_iterator reverse_iterator;
30
31 iterator begin() { return items.begin(); }
32 iterator end() { return items.end(); }
33 const_iterator begin() const { return items.begin(); }
34 const_iterator end() const { return items.end(); }
35 reverse_iterator rbegin() { return items.rbegin(); }
36 reverse_iterator rend() { return items.rend(); }
37 const_reverse_iterator rbegin() const { return items.rbegin(); }
38 const_reverse_iterator rend() const { return items.rend(); }
39 size_t size() const { return items.size(); }
40 bool empty() const { return items.empty(); }
41
42 bool operator==(const SmallSet& o) const
43 {
44 if (dirty)
45 rearrange_dirty();
46 if (o.dirty)
47 o.rearrange_dirty();
48 return items == o.items;
49 }
50
51 bool operator!=(const SmallSet& o) const
52 {
53 if (dirty)
54 rearrange_dirty();
55 if (o.dirty)
56 o.rearrange_dirty();
57 return items == o.items;
58 }
59
60 void clear()
61 {
62 items.clear();
63 dirty = 0;
64 }
65
66 int binary_search(const Value& value) const
67 {
68 int begin, end;
69 begin = -1, end = items.size();
70 while (end - begin > 1)
71 {
72 int cur = (end + begin) / 2;
73 if (value < get_value(items[cur]))
74 end = cur;
75 else
76 begin = cur;
77 }
78 if (begin == -1 || get_value(items[begin]) != value)
79 return -1;
80 else
81 return begin;
82 }
83
84 const_iterator find(const Value& value) const
85 {
86 if (items.empty())
87 return end();
88
89 // Stick to linear search if the vector size is small
90 if (items.size() < 6)
91 {
92 for (auto it = std::begin(items); it != std::end(items); ++it)
93 if (get_value(*it) == value)
94 return it;
95 return end();
96 }
97
98 // Use binary search for larger vectors
99
100 if (dirty > 16)
101 {
102 std::sort(items.begin(), items.end(),
103 [](const Item& a, const Item& b) {
104 return get_value(a) < get_value(b);
105 });
106 dirty = 0;
107 }
108 else if (dirty)
109 {
110 // Use insertion sort, if less than 16 new elements appeared since
111 // the last sort
112 rearrange_dirty();
113 }
114
115 int pos = binary_search(value);
116 if (pos == -1)
117 return items.end();
118 else
119 return items.begin() + pos;
120 }
121
122 iterator find(const Value& value)
123 {
124 if (items.empty())
125 return end();
126
127 // Stick to linear search if the vector size is small
128 if (items.size() < 6)
129 {
130 for (auto it = std::begin(items); it != std::end(items); ++it)
131 if (get_value(*it) == value)
132 return it;
133 return end();
134 }
135
136 // Use binary search for larger vectors
137
138 if (dirty > 16)
139 {
140 std::sort(items.begin(), items.end(),
141 [](const Item& a, const Item& b) {
142 return get_value(a) < get_value(b);
143 });
144 dirty = 0;
145 }
146 else if (dirty)
147 {
148 // Use insertion sort, if less than 16 new elements appeared since
149 // the last sort
150 rearrange_dirty();
151 }
152
153 int pos = binary_search(value);
154 if (pos == -1)
155 return items.end();
156 else
157 return items.begin() + pos;
158 }
159
160 Item& add(const Item& item)
161 {
162 ++dirty;
163 items.emplace_back(item);
164 return items.back();
165 }
166
167 // static const Value& _smallset_get_value(const Item&);
168
169 void rearrange_dirty() const
170 {
171 // Rearrange newly inserted items by insertion sort
172 for (size_t i = items.size() - dirty; i < items.size(); ++i)
173 for (size_t j = i;
174 j > 0 && get_value(items[j]) < get_value(items[j - 1]); --j)
175 std::swap(items[j], items[j - 1]);
176 dirty = 0;
177 }
178};
179
180template <typename Value> struct SmallUniqueValueSet : protected SmallSet<Value>
181{
182 using SmallSet<Value>::iterator;
183 using SmallSet<Value>::const_iterator;
184 using SmallSet<Value>::reverse_iterator;
185 using SmallSet<Value>::const_reverse_iterator;
186 using SmallSet<Value>::begin;
187 using SmallSet<Value>::end;
188 using SmallSet<Value>::rbegin;
189 using SmallSet<Value>::rend;
190 using SmallSet<Value>::empty;
191 using SmallSet<Value>::size;
192 using SmallSet<Value>::clear;
193 bool operator==(const SmallUniqueValueSet& o) const
194 {
195 return SmallSet<Value>::operator==(o);
196 }
197 bool operator!=(const SmallUniqueValueSet& o) const
198 {
199 return SmallSet<Value>::operator!=(o);
200 }
201
202 void add(const Value& val)
203 {
204 auto i = this->find(val);
205 if (i != this->end())
206 return;
207 SmallSet<Value>::add(val);
208 }
209
210 bool has(const Value& val) const { return this->find(val) != this->end(); }
211};
212
213template <typename Value>
215{
216 typedef typename SmallUniqueValueSet<Value>::iterator iterator;
217 typedef typename SmallUniqueValueSet<Value>::const_iterator const_iterator;
218 typedef
219 typename SmallUniqueValueSet<Value>::reverse_iterator reverse_iterator;
220 typedef typename SmallUniqueValueSet<Value>::const_reverse_iterator
221 const_reverse_iterator;
222 using SmallUniqueValueSet<Value>::end;
223 using SmallUniqueValueSet<Value>::rend;
224 using SmallUniqueValueSet<Value>::empty;
225 using SmallUniqueValueSet<Value>::size;
226 using SmallUniqueValueSet<Value>::clear;
227 using SmallUniqueValueSet<Value>::operator==;
228 using SmallUniqueValueSet<Value>::operator!=;
229
230 iterator begin()
231 {
232 if (this->dirty)
233 this->rearrange_dirty();
234 return SmallUniqueValueSet<Value>::begin();
235 }
236 const_iterator begin() const
237 {
238 if (this->dirty)
239 this->rearrange_dirty();
240 return SmallUniqueValueSet<Value>::begin();
241 }
242 reverse_iterator rbegin()
243 {
244 if (this->dirty)
245 this->rearrange_dirty();
246 return SmallUniqueValueSet<Value>::rbegin();
247 }
248 const_reverse_iterator rbegin() const
249 {
250 if (this->dirty)
251 this->rearrange_dirty();
252 return SmallUniqueValueSet<Value>::rbegin();
253 }
254
255 void add(const Value& val)
256 {
257 auto i = this->find(val);
258 if (i != this->end())
259 return;
260 SmallUniqueValueSet<Value>::add(val);
261 }
262
263 bool has(const Value& val) const { return this->find(val) != this->end(); }
264};
265
266} // namespace core
267} // namespace dballe
268
269#endif
Container for a wreport::Var pointer.
Definition value.h:19
Set structure optimized for a small number of items.
Definition smallset.h:21
Definition smallset.h:181