libdballe  9.14
smallset.h
1 #ifndef DBALLE_CORE_SMALLSET_H
2 #define DBALLE_CORE_SMALLSET_H
3 
4 #include <algorithm>
5 #include <vector>
6 
7 namespace dballe {
8 namespace core {
9 
10 template <typename T> inline const T& smallset_default_get_value(const T& val)
11 {
12  return val;
13 }
14 
18 template <typename Item, typename Value = Item,
19  const Value& (*get_value)(const Item&) = smallset_default_get_value>
20 struct SmallSet
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 
180 template <typename Value> struct SmallUniqueValueSet : protected SmallSet<Value>
181 {
187  using SmallSet<Value>::end;
189  using SmallSet<Value>::rend;
191  using SmallSet<Value>::size;
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;
208  }
209 
210  bool has(const Value& val) const { return this->find(val) != this->end(); }
211 };
212 
213 template <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;
229 
230  iterator begin()
231  {
232  if (this->dirty)
233  this->rearrange_dirty();
235  }
236  const_iterator begin() const
237  {
238  if (this->dirty)
239  this->rearrange_dirty();
241  }
242  reverse_iterator rbegin()
243  {
244  if (this->dirty)
245  this->rearrange_dirty();
247  }
248  const_reverse_iterator rbegin() const
249  {
250  if (this->dirty)
251  this->rearrange_dirty();
253  }
254 
255  void add(const Value& val)
256  {
257  auto i = this->find(val);
258  if (i != this->end())
259  return;
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
Definition: cmdline.h:18
Definition: smallset.h:180
Set structure optimized for a small number of items.
Definition: smallset.h:20
Container for a wreport::Var pointer.
Definition: value.h:18
Definition: smallset.h:214