Analytics Template Library
 All Classes Namespaces Functions Variables Pages
lazyflatset.hpp
1 
25 #ifndef RS_LAZY_FLAT_SET
26 #define RS_LAZY_FLAT_SET
27 
28 #include <vector>
29 #include <algorithm>
30 #include <type_traits>
31 #include <functional>
32 #include <memory>
33 
34 namespace rs {
35 
36  template <class Value, class Less>
38 
39  template <class Value, class Less = std::less<Value>, class Equal = std::equal_to<Value>, class Sort = LazyFlatSetQuickSort<Value, Less>, class Alloc = std::allocator<Value>, bool IsPointer = false>
40  class LazyFlatSet {
41  public:
42  template <class T> struct is_shared_ptr : std::false_type {};
43  template <class T> struct is_shared_ptr<std::shared_ptr<T> > : std::true_type {};
44 
45  template <class T> struct is_pointer : std::conditional<IsPointer || std::is_pointer<T>::value || is_shared_ptr<T>::value, std::true_type, std::false_type>::type {};
46 
47  using base_collection = typename std::vector<Value, Alloc>;
48  using size_type = typename base_collection::size_type;
49  using iterator = typename base_collection::iterator;
50  using const_iterator = typename base_collection::const_iterator;
51  using value_type = Value;
52  using value_type_ptr = typename std::conditional<is_pointer<value_type>::value, value_type, value_type*>::type;
53  using reference = typename std::conditional<std::is_fundamental<value_type>::value || std::is_pointer<value_type>::value, value_type, value_type&>::type;
54  using const_reference = typename std::conditional<std::is_fundamental<value_type>::value || std::is_pointer<value_type>::value, value_type, const value_type&>::type;
55  using less_type = Less;
56  using equal_type = Equal;
57  using sort_type = Sort;
58  using alloc_type = Alloc;
59  using compare_type = typename std::function<int(const_reference)>;
60  using erase_type = typename std::function<void(reference)>;
61 
62  LazyFlatSet(unsigned maxUnsortedEntries = 16, unsigned maxNurseryEntries = 1024) :
63  maxUnsortedEntries_(maxUnsortedEntries), maxNurseryEntries_(maxNurseryEntries) {
64  unsorted_.reserve(maxUnsortedEntries);
65  }
66 
67  void insert(const value_type& k) {
68  auto iter = lower_bound_equals(coll_, k);
69  if (iter != coll_.end()) {
70  *iter = k;
71  } else {
72  iter = lower_bound_equals(nursery_, k);
73  if (iter != nursery_.end()) {
74  *iter = k;
75  } else {
76  iter = search_unsorted(unsorted_, k);
77  if (iter != unsorted_.end()) {
78  *iter = k;
79  } else {
80  if (unsorted_.size() == maxUnsortedEntries_) {
81  flushUnsorted();
82  }
83 
84  unsorted_.push_back(k);
85  }
86  }
87  }
88  }
89 
90  template <typename... Args>
91  void emplace(Args&&... args) {
92  if (unsorted_.size() == maxUnsortedEntries_) {
93  flushUnsorted();
94  }
95 
96  unsorted_.emplace_back(std::forward<Args>(args)...);
97 
98  auto iter = lower_bound_equals(coll_, unsorted_.back());
99  if (iter != coll_.end()) {
100  *iter = std::move(unsorted_.back());
101  unsorted_.pop_back();
102  } else {
103  iter = lower_bound_equals(nursery_, unsorted_.back());
104  if (iter != nursery_.end()) {
105  *iter = std::move(unsorted_.back());
106  unsorted_.pop_back();
107  } else if (unsorted_.size() > 1) {
108  auto newItemIter = unsorted_.end() - 1;
109 
110  iter = search_unsorted(unsorted_, unsorted_.back());
111  if (iter != newItemIter) {
112  *iter = std::move(unsorted_.back());
113  unsorted_.pop_back();
114  }
115  }
116  }
117  }
118 
119  bool empty() const {
120  return coll_.empty() && nursery_.empty() && unsorted_.empty();
121  }
122 
123  void clear() {
124  coll_.clear();
125  nursery_.clear();
126  unsorted_.clear();
127  }
128 
129  void clear_fn(erase_type erase) {
130  for (auto i : coll_) {
131  erase(i);
132  }
133 
134  coll_.clear();
135 
136  for (auto i : nursery_) {
137  erase(i);
138  }
139 
140  nursery_.clear();
141 
142  for (auto i : unsorted_) {
143  erase(i);
144  }
145 
146  unsorted_.clear();
147  }
148 
149  void reserve(size_type n) {
150  coll_.reserve(n);
151  }
152 
153  size_type size() const {
154  return coll_.size() + nursery_.size() + unsorted_.size();
155  }
156 
157  void shrink_to_fit() {
158  flush();
159  nursery_.shrink_to_fit();
160  coll_.shrink_to_fit();
161  }
162 
163  size_type count(const value_type& k) const {
164  size_type found = 0;
165 
166  auto iter = lower_bound_equals(coll_, k);
167  if (iter != coll_.end()) {
168  found = 1;
169  } else {
170  iter = lower_bound_equals(nursery_, k);
171  if (iter != nursery_.end()) {
172  found = 1;
173  } else {
174  iter = search_unsorted(unsorted_, k);
175  if (iter != unsorted_.end()) {
176  found = 1;
177  }
178  }
179  }
180 
181  return found;
182  }
183 
184  size_type count_fn(compare_type compare) const {
185  size_type found = 0;
186 
187  auto index = search(coll_, compare);
188  if (index != search_end) {
189  found = 1;
190  } else {
191  index = search(nursery_, compare);
192  if (index != search_end) {
193  found = 1;
194  } else {
195  index = search_unsorted(unsorted_, compare);
196  if (index != search_end) {
197  found = 1;
198  }
199  }
200  }
201 
202  return found;
203  }
204 
205  bool find(const value_type& k, value_type& v) const {
206  auto found = false;
207 
208  auto iter = lower_bound_equals(coll_, k);
209  if (iter != coll_.end()) {
210  v = *iter;
211  found = true;
212  } else {
213  iter = lower_bound_equals(nursery_, k);
214  if (iter != nursery_.end()) {
215  v = *iter;
216  found = true;
217  } else {
218  iter = search_unsorted(unsorted_, k);
219  if (iter != unsorted_.end()) {
220  v = *iter;
221  found = true;
222  }
223  }
224  }
225 
226  return found;
227  }
228 
229  value_type_ptr find_fn(compare_type compare) const {
230  value_type_ptr value = nullptr;
231 
232  auto index = search(coll_, compare);
233  if (index != search_end) {
234  value = getValue(coll_, index, is_pointer<value_type>());
235  } else {
236  index = search(nursery_, compare);
237  if (index != search_end) {
238  value = getValue(nursery_, index, is_pointer<value_type>());
239  } else {
240  index = search_unsorted(unsorted_, compare);
241  if (index != search_end) {
242  value = getValue(unsorted_, index, is_pointer<value_type>());
243  }
244  }
245  }
246 
247  return value;
248  }
249 
250  const_reference operator[](size_type n) const {
251  flush();
252  return coll_[n];
253  }
254 
255  const_iterator cbegin() const {
256  flush();
257  return coll_.cbegin();
258  }
259 
260  const_iterator cend() const {
261  flush();
262  return coll_.cend();
263  }
264 
265  const value_type* data() const {
266  flush();
267  return coll_.data();
268  }
269 
270  size_type erase(const value_type& k) {
271  size_type count = 0;
272 
273  auto iter = lower_bound_equals(coll_, k);
274  if (iter != coll_.end()) {
275  coll_.erase(iter);
276  count = 1;
277  } else {
278  iter = lower_bound_equals(nursery_, k);
279  if (iter != nursery_.end()) {
280  nursery_.erase(iter);
281  count = 1;
282  } else {
283  iter = search_unsorted(unsorted_, k);
284  if (iter != unsorted_.end()) {
285  unsorted_.erase(iter);
286  count = 1;
287  }
288  }
289  }
290 
291  return count;
292  }
293 
294  size_type erase_fn(compare_type compare, erase_type erase = nullptr) {
295  size_type count = 0;
296 
297  auto index = search(coll_, compare);
298  if (index != search_end) {
299  if (erase != nullptr) {
300  erase(coll_[index]);
301  }
302  coll_.erase(coll_.begin() + index);
303  count = 1;
304  } else {
305  index = search(nursery_, compare);
306  if (index != search_end) {
307  if (erase != nullptr) {
308  erase(nursery_[index]);
309  }
310  nursery_.erase(nursery_.begin() + index);
311  count = 1;
312  } else {
313  index = search_unsorted(unsorted_, compare);
314  if (index != search_end) {
315  if (erase != nullptr) {
316  erase(unsorted_[index]);
317  }
318  unsorted_.erase(unsorted_.begin() + index);
319  count = 1;
320  }
321  }
322  }
323 
324  return count;
325  }
326 
327  void copy(std::vector<Value>& coll, bool sort = true) const {
328  if (sort) {
329  flush();
330  }
331 
332  const auto newSize = coll.size() + coll_.size() + nursery_.size() + unsorted_.size();
333  coll.reserve(newSize);
334 
335  coll.insert(coll.end(), coll_.cbegin(), coll_.cend());
336  coll.insert(coll.end(), nursery_.cbegin(), nursery_.cend());
337  coll.insert(coll.end(), unsorted_.cbegin(), unsorted_.cend());
338  }
339 
340  private:
341  const size_type search_end = -1;
342 
343  void sort(base_collection& coll) const {
344  Sort{}(coll.begin(), coll.end());
345  }
346 
347  iterator lower_bound(base_collection& coll, const value_type& k) const {
348  return std::lower_bound(coll.begin(), coll.end(), k, Less{});
349  }
350 
351  iterator lower_bound_equals(base_collection& coll, const value_type& k) const {
352  auto iter = lower_bound(coll, k);
353  return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
354  }
355 
356  iterator upper_bound(base_collection& coll, const value_type& k) const {
357  return std::upper_bound(coll.begin(), coll.end(), k, Less{});
358  }
359 
360  iterator upper_bound_equals(base_collection& coll, const value_type& k) const {
361  auto iter = upper_bound(coll, k);
362  return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
363  }
364 
365  size_type search(base_collection& coll, compare_type compare) const {
366  const auto size = coll.size();
367 
368  if (size > 0) {
369  size_type min = 0;
370  size_type max = size - 1;
371  const auto data = coll.data();
372 
373  while (max != search_end && max >= min) {
374  auto mid = ((max - min) / 2) + min;
375 
376  const auto& item = data[mid];
377  auto diff = compare(item);
378  if (diff == 0) {
379  return mid;
380  } else if (diff < 0) {
381  max = mid - 1;
382  } else {
383  min = mid + 1;
384  }
385  }
386  }
387 
388  return search_end;
389  }
390 
391  size_type search_unsorted(base_collection& coll, compare_type compare) const {
392  const auto data = coll.data();
393 
394  for (size_type i = 0, size = coll.size(); i < size; ++i) {
395  if (compare(data[i]) == 0) {
396  return i;
397  }
398  }
399 
400  return search_end;
401  }
402 
403  iterator search_unsorted(base_collection& coll, const value_type& k) const {
404  return std::search_n(coll.begin(), coll.end(), 1, k, Equal{});
405  }
406 
407  void flush() const {
408  flushUnsorted();
409  flushNursery();
410  }
411 
412  void flushUnsorted() const {
413  const auto unsortedSize = unsorted_.size();
414  if (unsortedSize > 0) {
415  if ((nursery_.size() + unsortedSize) > maxNurseryEntries_) {
416  flushNursery();
417  }
418 
419  sort(unsorted_);
420  merge(unsorted_, nursery_);
421  unsorted_.clear();
422  }
423  }
424 
425  void flushNursery() const {
426  if (nursery_.size() > 0) {
427  merge(nursery_, coll_);
428  nursery_.clear();
429  }
430  }
431 
432  void merge(base_collection& source, base_collection& target) const {
433  if (source.size() > 0) {
434  Less less;
435  if (target.size() == 0 || less(target.back(), source.front())) {
436  target.insert(target.end(), source.cbegin(), source.cend());
437  } else if (less(source.back(), target.front())) {
438  target.insert(target.begin(), source.cbegin(), source.cend());
439  } else {
440  target.insert(target.begin(), source.cbegin(), source.cend());
441  std::inplace_merge(target.begin(), target.begin() + source.size(), target.end(), less);
442  }
443  }
444  }
445 
446  value_type getValue(base_collection& coll, int index, std::true_type) const {
447  return coll[index];
448  }
449 
450  value_type_ptr getValue(base_collection& coll, int index, std::false_type) const {
451  return &coll[index];
452  }
453 
454  const unsigned maxUnsortedEntries_;
455  const unsigned maxNurseryEntries_;
456 
457  mutable base_collection coll_;
458  mutable base_collection nursery_;
459  mutable base_collection unsorted_;
460  };
461 
462  template <class Value, class Less>
463  struct LazyFlatSetQuickSort {
464  void operator()(typename LazyFlatSet<Value>::iterator first, typename LazyFlatSet<Value>::iterator last) {
465  std::sort(first, last, Less{});
466  }
467  };
468 
469 }
470 
471 #endif
const atl::Variable< T > min(const atl::Variable< T > &a, const atl::Variable< T > &b)
Definition: ATL.hpp:57
Definition: lazyflatset.hpp:40
Definition: ad_cmath.hpp:17
Definition: lazyflatset.hpp:45
Definition: lazyflatset.hpp:34
Definition: lazyflatset.hpp:42
Definition: lazyflatset.hpp:37
const atl::Variable< T > max(const atl::Variable< T > &a, const atl::Variable< T > &b)
Definition: ATL.hpp:43