swift
algorithm.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #ifndef SWIFT_MISC_ALGORITHM_H
7 #define SWIFT_MISC_ALGORITHM_H
8 
9 #include <algorithm>
10 #include <iterator>
11 #include <random>
12 #include <tuple>
13 #include <utility>
14 
15 #include <QtGlobal>
16 
17 namespace swift::misc
18 {
24  template <typename I, typename J>
25  auto removeIfIn(I begin1, I end1, J begin2, J end2)
26  {
27  auto newEnd = end1;
28  std::for_each(begin2, end2, [&](const auto &rm) {
29  const auto found = std::find(begin1, end1, rm);
30  Q_ASSERT(found != end1);
31  if (newEnd == end1) { newEnd = found; }
32  else { newEnd = std::move(begin1, found, newEnd); }
33  begin1 = std::next(found);
34  });
35  if (newEnd != end1) { newEnd = std::move(begin1, end1, newEnd); }
36  return newEnd;
37  }
38 
39  namespace private_ns
40  {
43  inline std::mt19937 &defaultRandomGenerator()
44  {
45  thread_local std::mt19937 rng(std::random_device {}());
46  return rng;
47  }
48  } // namespace private_ns
49 
53  template <typename ForwardIt, typename OutputIt, typename Generator>
54  void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
55  {
56  for (auto size = static_cast<int>(std::distance(in, end)); in != end && n > 0; ++in, --size)
57  {
58  if (std::uniform_int_distribution<>(0, size - 1)(rng) < n)
59  {
60  *out++ = *in;
61  --n;
62  }
63  }
64  }
65 
69  template <typename ForwardIt, typename OutputIt>
70  void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n)
71  {
72  copyRandomElements(in, end, out, n, private_ns::defaultRandomGenerator());
73  }
74 
79  template <typename ForwardIt, typename OutputIt, typename Generator>
80  void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
81  {
82  const auto size = static_cast<int>(std::distance(in, end));
83  for (int i = 0; i < std::min(n, size); ++i)
84  {
85  const auto index = std::uniform_int_distribution<>(0, std::max(size / n, 1) - 1)(rng);
86  std::advance(in, index);
87  *out++ = *in;
88  std::advance(in, std::max(size / n, 1) - index);
89  }
90  }
91 
95  template <typename ForwardIt, typename OutputIt>
96  void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, int n)
97  {
98  copySampleElements(in, end, out, n, private_ns::defaultRandomGenerator());
99  }
100 
113  template <typename I, typename F>
114  void topologicalSort(I begin, I end, F comparator)
115  {
116  using value_type = typename std::iterator_traits<I>::value_type;
117  auto part = begin;
118  while (part != end)
119  {
120  auto newPart = std::partition(part, end, [=](const value_type &a) {
121  return std::none_of(part, end, [=, &a](const value_type &b) { return comparator(b, a); });
122  });
123  Q_ASSERT_X(newPart != part, "swift::misc::topologicalSort",
124  "Cyclic less-than relation detected (not a partial ordering)");
125  part = newPart;
126  }
127  }
128 
141  template <typename C, typename T, typename F>
142  void topologicallySortedInsert(C &container, T &&value, F comparator)
143  {
144  using value_type = typename C::value_type;
145  using reverse = std::reverse_iterator<typename C::iterator>;
146  auto rit = std::find_if(reverse(container.end()), reverse(container.begin()),
147  [=, &value](const value_type &lhs) { return comparator(lhs, value); });
148  Q_ASSERT_X(std::none_of(rit, reverse(container.begin()),
149  [=, &value](const value_type &rhs) { return comparator(value, rhs); }),
150  "swift::misc::topologicallySortedInsert",
151  "Cyclic less-than relation detected (not a partial ordering)");
152  container.insert(rit.base(), std::forward<T>(value));
153  }
154 
155  namespace private_ns
156  {
158  template <typename T, typename F, size_t... Is>
159  void tupleForEachPairImpl(T &&tuple, F &&visitor, std::index_sequence<Is...>)
160  {
161  // cppcheck-suppress accessForwarded
162  (static_cast<void>(std::forward<F>(visitor)(std::get<Is * 2>(std::forward<T>(tuple)),
163  std::get<Is * 2 + 1>(std::forward<T>(tuple)))),
164  ...);
165  }
166  } // namespace private_ns
167 
171  template <typename T, typename F>
172  void tupleForEachPair(T &&tuple, F &&visitor)
173  {
174  using seq = std::make_index_sequence<std::tuple_size_v<std::decay_t<T>> / 2>;
175  return private_ns::tupleForEachPairImpl(std::forward<T>(tuple), std::forward<F>(visitor), seq());
176  }
177 } // namespace swift::misc
178 
179 #endif // SWIFT_MISC_ALGORITHM_H
Free functions in swift::misc.
T::const_iterator begin(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:332
void topologicalSort(I begin, I end, F comparator)
Topological sorting algorithm.
Definition: algorithm.h:114
auto removeIfIn(I begin1, I end1, J begin2, J end2)
Removes those elements in range 1 that appear also in range 2 leaving only those that do not appear i...
Definition: algorithm.h:25
void tupleForEachPair(T &&tuple, F &&visitor)
Invoke a visitor function on each pair of elements of a tuple in order.
Definition: algorithm.h:172
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
Definition: lockfree.h:338
void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
Split the range [in,end) into n equal chunks and use the random number generator rng to choose one el...
Definition: algorithm.h:80
void topologicallySortedInsert(C &container, T &&value, F comparator)
Insert an element into a sequential container while preserving the topological ordering of the contai...
Definition: algorithm.h:142
void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
Use the random number generator rng to choose n elements from the range [in,end) and copy them to out...
Definition: algorithm.h:54